Commit 1186b695 1186b695bc7c105b19e36bff4c7c9dc04fe30d8f by Sergey Poznyakoff

sieve: improve memory allocation

* include/mailutils/sieve.h (mu_sieve_alloc)
(mu_sieve_palloc,mu_sieve_prealloc)
(mu_sieve_pfree,mu_sieve_pstrdup):  Remove.
(mu_sieve_mstrdup,mu_sieve_mrealloc)
(mu_sieve_mfree): Remove.

(mu_sieve_reclaim_t): New typedef.
(mu_sieve_calloc,mu_sieve_strdup)
(mu_sieve_realloc)
(mu_sieve_reclaim_default,mu_sieve_reclaim_list)
(mu_sieve_reclaim_value,mu_sieve_reclaim_tag): New functions
(mu_sieve_value_create): Change prototype (take mu_sieve_machine_t
as first argument)
* libmu_sieve/mem.c: New file.
* libmu_sieve/Makefile.am: Add new file.

* libmu_sieve/comparator.c: Use new allocation functions.
* libmu_sieve/prog.c: Likewise.
* libmu_sieve/register.c: Likewise.
* libmu_sieve/sieve.l: Likewise.
* libmu_sieve/sieve.y: Likewise.
* libmu_sieve/util.c: Likewise.

* doc/texinfo/libmu_sieve.texi: Update (needs revision).
1 parent 7b6fe2ab
......@@ -609,27 +609,27 @@ freed upon the call to @code{mu_sieve_machine_destroy (@var{mach})}.
Allocates @var{size} bytes and returns a pointer to the allocated memory.
@end deftypefun
@deftypefun {char *} mu_sieve_mstrdup (mu_sieve_machine_t @var{mach}, const char *@var{str})
@deftypefun {char *} mu_sieve_strdup (mu_sieve_machine_t @var{mach}, const char *@var{str})
This function returns a pointer to a new string which is a duplicate of the
string @var{str}.
@end deftypefun
@deftypefun {void *} mu_sieve_mrealloc (mu_sieve_machine_t @var{mach}, void *@var{ptr}, size_t @var{size})
@deftypefun {void *} mu_sieve_realloc (mu_sieve_machine_t @var{mach}, void *@var{ptr}, size_t @var{size})
Changes the size of the memory block pointed to by @var{ptr} to
@var{size} bytes. The contents will be unchanged to the minimum of the
old and new sizes; newly allocated memory will be uninitialized. If
@var{ptr} is @code{NULL}, the call is equivalent to
@code{mu_sieve_malloc(@var{mach}, @var{size})}; if @var{size} is equal to
zero, the call is equivalent to @code{mu_sieve_mfree(@var{ptr})}. Unless
zero, the call is equivalent to @code{mu_sieve_free(@var{ptr})}. Unless
@var{ptr} is @code{NULL}, it must have been returned by an earlier
call to @code{mu_sieve_malloc()} or @code{mu_sieve_mrealloc()}.
call to @code{mu_sieve_malloc()} or @code{mu_sieve_realloc()}.
@end deftypefun
@deftypefun void mu_sieve_mfree (mu_sieve_machine_t @var{mach}, void *@var{ptr})
@code{mu_sieve_mfree()} frees the memory space pointed to by @var{ptr} and
@deftypefun void mu_sieve_free (mu_sieve_machine_t @var{mach}, void *@var{ptr})
@code{mu_sieve_free()} frees the memory space pointed to by @var{ptr} and
detaches it from the destructor list of @var{mach}. The @var{ptr} must
have been returned by a previous call to @code{mu_sieve_malloc()} or
@code{mu_sieve_mrealloc()}. Otherwise, or if @code{mu_sieve_mfree(@var{ptr})}
@code{mu_sieve_realloc()}. Otherwise, or if @code{mu_sieve_mfree(@var{ptr})}
has already been called before, undefined behaviour occurs.
If @var{ptr} is @code{NULL}, no operation is performed.
......
......@@ -121,18 +121,24 @@ extern mu_list_t mu_sieve_library_path_prefix;
void mu_sieve_debug_init (void);
/* Memory allocation functions */
void *mu_sieve_alloc (size_t size);
void *mu_sieve_palloc (mu_list_t *pool, size_t size);
void *mu_sieve_prealloc (mu_list_t *pool, void *ptr, size_t size);
void mu_sieve_pfree (mu_list_t *pool, void *ptr);
char *mu_sieve_pstrdup (mu_list_t *pool, const char *str);
typedef void (*mu_sieve_reclaim_t) (void *);
void mu_sieve_register_memory (mu_sieve_machine_t mach, void *ptr,
mu_sieve_reclaim_t reclaim);
void *mu_sieve_alloc_memory (mu_sieve_machine_t mach, size_t size,
mu_sieve_reclaim_t recfun);
void mu_sieve_free (mu_sieve_machine_t mach, void *ptr);
void *mu_sieve_malloc (mu_sieve_machine_t mach, size_t size);
char *mu_sieve_mstrdup (mu_sieve_machine_t mach, const char *str);
void *mu_sieve_mrealloc (mu_sieve_machine_t mach, void *ptr, size_t size);
void mu_sieve_mfree (mu_sieve_machine_t mach, void *ptr);
void *mu_sieve_calloc (mu_sieve_machine_t mach, size_t nmemb, size_t size);
char *mu_sieve_strdup (mu_sieve_machine_t mach, char const *str);
void *mu_sieve_realloc (mu_sieve_machine_t mach, void *ptr, size_t size);
void mu_sieve_reclaim_default (void *p);
void mu_sieve_reclaim_list (void *p);
void mu_sieve_reclaim_value (void *p);
void mu_sieve_reclaim_tag (void *p);
mu_sieve_value_t *mu_sieve_value_create (mu_sieve_data_type type, void *data);
mu_sieve_value_t *mu_sieve_value_create (mu_sieve_machine_t mach,
mu_sieve_data_type type, void *data);
void mu_sieve_slist_destroy (mu_list_t *plist);
/* Symbol space functions */
......
......@@ -32,6 +32,7 @@ libmu_sieve_la_SOURCES = \
comparator.c\
encoded.c\
load.c\
mem.c\
prog.c\
register.c\
relational.c\
......
......@@ -338,7 +338,7 @@ mu_sieve_match_part_checker (mu_sieve_machine_t mach,
tmp = mu_sieve_malloc (mach, sizeof (*tmp));
tmp->tag = TAG_COMPFUN;
tmp->arg = mu_sieve_value_create (SVT_POINTER, compfun);
tmp->arg = mu_sieve_value_create (mach, SVT_POINTER, compfun);
mu_list_append (tags, tmp);
if (matchtype == MU_SIEVE_MATCH_REGEX)
......@@ -365,7 +365,7 @@ mu_sieve_match_part_checker (mu_sieve_machine_t mach,
if (rc)
return rc;
newval = mu_sieve_value_create (SVT_STRING_LIST, rd.list);
newval = mu_sieve_value_create (rd.mach, SVT_STRING_LIST, rd.list);
mu_list_replace (args, val, newval);
}
#ifndef FNM_CASEFOLD
......
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 1999-2002, 2005-2008, 2010-2012, 2014-2016 Free
Software Foundation, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library. If not, see
<http://www.gnu.org/licenses/>. */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <sieve-priv.h>
struct memory_cell
{
void *ptr;
void (*reclaim) (void *);
};
static void
memory_cell_destroy (void *item)
{
struct memory_cell *mcp = item;
if (!mcp->reclaim)
abort ();
else
mcp->reclaim (mcp->ptr);
free (mcp);
}
static int
memory_cell_cmp (const void *a, const void *b)
{
struct memory_cell const *ma = a;
struct memory_cell const *mb = b;
return ma->ptr != mb->ptr;
}
void
mu_sieve_register_memory (mu_sieve_machine_t mach, void *ptr,
mu_sieve_reclaim_t reclaim)
{
struct memory_cell *mcp;
if (!reclaim)
reclaim = mu_sieve_reclaim_default;
if (!mach->memory_pool)
{
if (mu_list_create (&mach->memory_pool))
mu_sieve_abort (mach);
mu_list_set_destroy_item (mach->memory_pool, memory_cell_destroy);
mu_list_set_comparator (mach->memory_pool, memory_cell_cmp);
}
mcp = malloc (sizeof (*mcp));
if (!mcp)
mu_sieve_abort (mach);
mcp->ptr = ptr;
mcp->reclaim = reclaim;
if (mu_list_append (mach->memory_pool, mcp))
{
memory_cell_destroy (mcp);
mu_sieve_abort (mach);
}
}
void
mu_sieve_free (mu_sieve_machine_t mach, void *ptr)
{
int rc;
struct memory_cell mcell;
mcell.ptr = ptr;
rc = mu_list_remove (mach->memory_pool, &mcell);
if (rc)
{
mu_sieve_error (mach, _("INTERNAL ERROR: trying to free unregistered memory pointer"));
abort ();
}
}
void *
mu_sieve_alloc_memory (mu_sieve_machine_t mach, size_t size,
mu_sieve_reclaim_t recfun)
{
char *p = malloc (size);
if (!p)
{
mu_sieve_error (mach, "%s", mu_strerror (errno));
mu_sieve_abort (mach);
}
mu_sieve_register_memory (mach, p, recfun);
return p;
}
void *
mu_sieve_malloc (mu_sieve_machine_t mach, size_t size)
{
return mu_sieve_alloc_memory (mach, size, mu_sieve_reclaim_default);
}
void *
mu_sieve_calloc (mu_sieve_machine_t mach, size_t nmemb, size_t size)
{
char *p = calloc (nmemb, size);
if (!p)
{
mu_sieve_error (mach, "%s", mu_strerror (errno));
mu_sieve_abort (mach);
}
mu_sieve_register_memory (mach, p, mu_sieve_reclaim_default);
return p;
}
char *
mu_sieve_strdup (mu_sieve_machine_t mach, char const *str)
{
size_t len;
char *p;
if (!str)
return NULL;
len = strlen (str);
p = mu_sieve_malloc (mach, len + 1);
memcpy (p, str, len);
p[len] = 0;
return p;
}
void *
mu_sieve_realloc (mu_sieve_machine_t mach, void *ptr, size_t size)
{
int rc;
struct memory_cell mcell, *mcp;
if (!ptr)
return mu_sieve_malloc (mach, size);
mcell.ptr = ptr;
rc = mu_list_locate (mach->memory_pool, &mcell, (void **)&mcp);
if (rc == MU_ERR_NOENT)
{
mu_sieve_error (mach, _("INTERNAL ERROR: trying to reallocate unregistered memory pointer"));
abort ();
}
else if (rc)
{
mu_sieve_error (mach, _("error reallocating memory: %s"),
mu_strerror (rc));
mu_sieve_abort (mach);
}
ptr = realloc (mcp->ptr, size);
if (!ptr)
{
mu_sieve_error (mach, _("error reallocating memory: %s"),
mu_strerror (errno));
mu_sieve_abort (mach);
}
mcp->ptr = ptr;
return ptr;
}
void
mu_sieve_reclaim_default (void *p)
{
free (p);
}
void
mu_sieve_reclaim_list (void *p)
{
mu_list_t list = p;
mu_list_destroy (&list);
}
void
mu_sieve_reclaim_value (void *p)
{
if (!p)
return;
/* For now, the same as _default. Will change in the future */
free (p);
}
void
mu_sieve_reclaim_tag (void *p)
{
mu_sieve_runtime_tag_t *tag = p;
mu_sieve_reclaim_value (tag->arg);
}
......@@ -31,7 +31,7 @@ mu_i_sv_code (struct mu_sieve_machine *mach, sieve_op_t op)
{
size_t newsize = mach->progsize + SIEVE_CODE_INCR;
sieve_op_t *newprog =
mu_sieve_mrealloc (mach, mach->prog, newsize * sizeof mach->prog[0]);
mu_sieve_realloc (mach, mach->prog, newsize * sizeof mach->prog[0]);
if (!newprog)
{
mu_diag_at_locus (MU_LOG_ERROR, &mach->locus, _("not enough memory"));
......@@ -261,8 +261,8 @@ sv_code_command (struct mu_sieve_machine *mach,
mu_list_create (&list);
mu_list_append (list, val->v.string);
mu_sieve_mfree (mach, val);
val = mu_sieve_value_create (SVT_STRING_LIST, list);
mu_sieve_free (mach, val);
val = mu_sieve_value_create (mach, SVT_STRING_LIST, list);
}
else
{
......
......@@ -89,14 +89,14 @@ mu_sieve_require_test (mu_sieve_machine_t mach, const char *name)
static int
sieve_register (mu_list_t *pool,
sieve_register (mu_sieve_machine_t mach,
mu_list_t *list,
const char *name, mu_sieve_handler_t handler,
mu_sieve_data_type *req_arg_types,
mu_sieve_data_type *opt_arg_types,
mu_sieve_tag_group_t *tags, int required)
{
mu_sieve_register_t *reg = mu_sieve_palloc (pool, sizeof (*reg));
mu_sieve_register_t *reg = mu_sieve_malloc (mach, sizeof (*reg));
if (!reg)
return ENOMEM;
......@@ -129,7 +129,7 @@ mu_sieve_register_test_ext (mu_sieve_machine_t mach,
mu_sieve_data_type *opt_args,
mu_sieve_tag_group_t *tags, int required)
{
return sieve_register (&mach->memory_pool,
return sieve_register (mach,
&mach->test_list, name, handler,
req_args, opt_args, tags, required);
}
......@@ -153,7 +153,7 @@ mu_sieve_register_action_ext (mu_sieve_machine_t mach,
mu_sieve_data_type *opt_args,
mu_sieve_tag_group_t *tags, int required)
{
return sieve_register (&mach->memory_pool,
return sieve_register (mach,
&mach->action_list, name, handler,
req_args, opt_args, tags, required);
}
......
......@@ -226,7 +226,7 @@ push_source (const char *name)
if (mu_sieve_locus.mu_file)
{
advance_locus ();
ctx = mu_sieve_alloc (sizeof (*ctx));
ctx = mu_sieve_malloc (mu_sieve_machine, sizeof (*ctx));
ctx->locus = mu_sieve_locus;
ctx->i_node = sieve_source_inode;
ctx->input = input_stream;
......@@ -262,7 +262,7 @@ pop_source ()
sieve_source_inode = context_stack->i_node;
RESTORE_BUFFER_STATE (context_stack->state);
ctx = context_stack->prev;
free (context_stack);
mu_sieve_free (mu_sieve_machine, context_stack);
context_stack = ctx;
return 0;
......@@ -393,7 +393,7 @@ get_file_name (char *p, char *endp, int *usepath)
}
n = p - startp;
name = mu_sieve_alloc (n + 1);
name = mu_sieve_malloc (mu_sieve_machine, n + 1);
memcpy (name, startp, n);
name[n] = 0;
return name;
......@@ -420,7 +420,7 @@ _try_include (void *item, void *data)
}
static void
sieve_include ()
sieve_include (void)
{
char *p, *endp = yytext + yyleng, *name;
int usepath;
......@@ -440,14 +440,14 @@ sieve_include ()
&& mu_list_foreach (mu_sieve_include_path, _try_include, &p))
{
push_source (p);
free (name);
mu_sieve_free (mu_sieve_machine, name);
free (p);
return;
}
}
push_source (name);
free (name);
mu_sieve_free (mu_sieve_machine, name);
}
static void
......@@ -462,7 +462,7 @@ sieve_searchpath (void)
if (name)
{
mu_i_sv_load_add_dir (mu_sieve_machine, name);
free (name);
mu_sieve_free (mu_sieve_machine, name);
}
}
......@@ -597,7 +597,7 @@ multiline_begin (void)
break;
len = endp - p;
multiline_delimiter = mu_sieve_alloc (len + 1);
multiline_delimiter = mu_sieve_malloc (mu_sieve_machine, len + 1);
memcpy (multiline_delimiter, p, len);
multiline_delimiter[len] = 0;
}
......@@ -635,7 +635,7 @@ ident (const char *text)
static char *
str_unescape (char *text, size_t len)
{
char *str = mu_sieve_alloc (len);
char *str = mu_sieve_malloc (mu_sieve_machine, len);
memcpy (str, text, len - 2);
str[len - 2] = mu_wordsplit_c_unquote_char (text[len - 1]);
str[len - 1] = 0;
......
......@@ -333,23 +333,24 @@ arglist : arg
arg : stringlist
{
$$ = mu_sieve_value_create (SVT_STRING_LIST, $1);
$$ = mu_sieve_value_create (mu_sieve_machine,
SVT_STRING_LIST, $1);
}
| STRING
{
$$ = mu_sieve_value_create (SVT_STRING, $1);
$$ = mu_sieve_value_create (mu_sieve_machine, SVT_STRING, $1);
}
| MULTILINE
{
$$ = mu_sieve_value_create (SVT_STRING, $1);
$$ = mu_sieve_value_create (mu_sieve_machine, SVT_STRING, $1);
}
| NUMBER
{
$$ = mu_sieve_value_create (SVT_NUMBER, &$1);
$$ = mu_sieve_value_create (mu_sieve_machine, SVT_NUMBER, &$1);
}
| TAG
{
$$ = mu_sieve_value_create (SVT_TAG, $1);
$$ = mu_sieve_value_create (mu_sieve_machine, SVT_TAG, $1);
}
;
......@@ -998,13 +999,7 @@ mu_sieve_machine_init (mu_sieve_machine_t *pmach)
if (!mach)
return ENOMEM;
memset (mach, 0, sizeof (*mach));
rc = mu_list_create (&mach->memory_pool);
if (rc)
{
free (mach);
return rc;
}
mach->memory_pool = NULL;
rc = mu_opool_create (&mach->string_pool, MU_OPOOL_DEFAULT);
if (rc)
{
......@@ -1217,8 +1212,8 @@ mu_sieve_get_daemon_email (mu_sieve_machine_t mach)
void
mu_sieve_set_daemon_email (mu_sieve_machine_t mach, const char *email)
{
mu_sieve_mfree (mach, (void *)mach->daemon_email);
mach->daemon_email = mu_sieve_mstrdup (mach, email);
mu_sieve_free (mach, (void *)mach->daemon_email);
mach->daemon_email = mu_sieve_strdup (mach, email);
}
struct sieve_destr_record
......@@ -1267,7 +1262,7 @@ mu_sieve_machine_destroy (mu_sieve_machine_t *pmach)
mu_list_destroy (&mach->comp_list);
mu_list_destroy (&mach->source_list);
mu_opool_destroy (&mach->string_pool);
mu_sieve_slist_destroy (&mach->memory_pool);
mu_list_destroy (&mach->memory_pool);
free (mach);
*pmach = NULL;
}
......@@ -1284,10 +1279,15 @@ with_machine (mu_sieve_machine_t mach, char const *name,
mu_strerr = mach->errstream;
mu_stream_ref (mu_strerr);
mu_sieve_machine = mach;
rc = setjmp (mach->errbuf);
if (rc == 0)
{
mach->state = mu_sieve_state_init;
mu_i_sv_register_standard_actions (mach);
mu_i_sv_register_standard_tests (mach);
mu_i_sv_register_standard_comparators (mach);
mu_sieve_machine = mach;
mu_sieve_stream_save (mach);
rc = thunk (data);
......@@ -1296,6 +1296,9 @@ with_machine (mu_sieve_machine_t mach, char const *name,
mu_stream_unref (save_errstr);
mu_strerr = save_errstr;
mu_stream_unref (mu_strerr);
}
else
mach->state = mu_sieve_state_error;
return rc;
}
......
......@@ -25,104 +25,6 @@
#include <stdarg.h>
#include <sieve-priv.h>
void *
mu_sieve_alloc (size_t size)
{
void *p = malloc (size);
if (!p)
{
mu_error ("not enough memory");
abort ();
}
return p;
}
void *
mu_sieve_palloc (mu_list_t *pool, size_t size)
{
void *p = malloc (size);
if (p)
{
if (!*pool && mu_list_create (pool))
{
free (p);
return NULL;
}
mu_list_append (*pool, p);
}
return p;
}
char *
mu_sieve_pstrdup (mu_list_t *pool, const char *str)
{
size_t len;
char *p;
if (!str)
return NULL;
len = strlen (str);
p = mu_sieve_palloc (pool, len + 1);
if (p)
{
memcpy (p, str, len);
p[len] = 0;
}
return p;
}
void *
mu_sieve_prealloc (mu_list_t *pool, void *ptr, size_t size)
{
void *newptr;
if (*pool)
mu_list_remove (*pool, ptr);
newptr = realloc (ptr, size);
if (newptr)
{
if (!*pool && mu_list_create (pool))
{
free (newptr);
return NULL;
}
mu_list_append (*pool, newptr);
}
return newptr;
}
void
mu_sieve_pfree (mu_list_t *pool, void *ptr)
{
if (*pool)
mu_list_remove (*pool, ptr);
free (ptr);
}
void *
mu_sieve_malloc (mu_sieve_machine_t mach, size_t size)
{
return mu_sieve_palloc (&mach->memory_pool, size);
}
char *
mu_sieve_mstrdup (mu_sieve_machine_t mach, const char *str)
{
return mu_sieve_pstrdup (&mach->memory_pool, str);
}
void *
mu_sieve_mrealloc (mu_sieve_machine_t mach, void *ptr, size_t size)
{
return mu_sieve_prealloc (&mach->memory_pool, ptr, size);
}
void
mu_sieve_mfree (mu_sieve_machine_t mach, void *ptr)
{
mu_sieve_pfree (&mach->memory_pool, ptr);
}
static int
_destroy_item (void *item, void *data)
......@@ -130,7 +32,7 @@ _destroy_item (void *item, void *data)
free (item);
return 0;
}
/* FIXME: Not needed? */
void
mu_sieve_slist_destroy (mu_list_t *plist)
{
......@@ -141,9 +43,11 @@ mu_sieve_slist_destroy (mu_list_t *plist)
}
mu_sieve_value_t *
mu_sieve_value_create (mu_sieve_data_type type, void *data)
mu_sieve_value_create (mu_sieve_machine_t mach, mu_sieve_data_type type,
void *data)
{
mu_sieve_value_t *val = mu_sieve_alloc (sizeof (*val));
mu_sieve_value_t *val = mu_sieve_alloc_memory (mach, sizeof (*val),
mu_sieve_reclaim_value);
val->type = type;
switch (type)
......