#ifndef _TALLOC_H_
#define _TALLOC_H_
-/*
+/*
Unix SMB/CIFS implementation.
Samba temporary memory allocation functions
Copyright (C) Andrew Tridgell 2004-2005
Copyright (C) Stefan Metzmacher 2006
-
+
** NOTE! The following LGPL license applies to the talloc
** library. This does NOT imply that all of Samba is released
** under the LGPL
-
+
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
#include <stdio.h>
#include <stdarg.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/**
* @defgroup talloc The talloc API
*
*/
#define TALLOC_VERSION_MAJOR 2
-#define TALLOC_VERSION_MINOR 0
+#define TALLOC_VERSION_MINOR 1
int talloc_version_major(void);
int talloc_version_minor(void);
+/* This is mostly useful only for testing */
+int talloc_test_get_magic(void);
/**
* @brief Define a talloc parent type
/**
* @brief Free a chunk of talloc memory.
*
- * This function frees a piece of talloc memory, and all its children. It
- * operates recursively on its children. You can call talloc_free() on any
- * pointer returned by talloc().
- *
- * If this pointer has an additional parent when talloc_free() is called then
- * the memory is not actually released, but instead the most recently
- * established parent is destroyed. See talloc_reference() for details on
- * establishing additional parents.
- *
- * For more control on which parent is removed, see talloc_unlink().
- *
- * From the 2.0 version of talloc, as a special case, talloc_free() is
- * refused on pointers that have more than one parent, as talloc would
- * have no way of knowing which parent should be removed. To free a
+ * The talloc_free() function frees a piece of talloc memory, and all its
+ * children. You can call talloc_free() on any pointer returned by
+ * talloc().
+ *
+ * The return value of talloc_free() indicates success or failure, with 0
+ * returned for success and -1 for failure. A possible failure condition
+ * is if the pointer had a destructor attached to it and the destructor
+ * returned -1. See talloc_set_destructor() for details on
+ * destructors. Likewise, if "ptr" is NULL, then the function will make
+ * no modifications and return -1.
+ *
+ * From version 2.0 and onwards, as a special case, talloc_free() is
+ * refused on pointers that have more than one parent associated, as talloc
+ * would have no way of knowing which parent should be removed. This is
+ * different from older versions in the sense that always the reference to
+ * the most recently established parent has been destroyed. Hence to free a
* pointer that has more than one parent please use talloc_unlink().
*
* To help you find problems in your code caused by this behaviour, if
* talloc_set_log_stderr() for more information on talloc logging
* functions.
*
+ * If <code>TALLOC_FREE_FILL</code> environment variable is set,
+ * the memory occupied by the context is filled with the value of this variable.
+ * The value should be a numeric representation of the character you want to
+ * use.
+ *
+ * talloc_free() operates recursively on its children.
+ *
* @param[in] ptr The chunk to be freed.
*
- * @return Returns 0 on success and -1 on error. The only possible
+ * @return Returns 0 on success and -1 on error. A possible
* failure condition is if the pointer had a destructor
- * attached to it and the destructor returned -1.
+ * attached to it and the destructor returned -1. Likewise,
+ * if "ptr" is NULL, then the function will make no
+ * modifications and returns -1.
*
* Example:
* @code
* The function walks along the list of all children of a talloc context and
* talloc_free()s only the children, not the context itself.
*
- * @param[in] ptr The chunk that you want to free the children of.
+ * A NULL argument is handled as no-op.
+ *
+ * @param[in] ptr The chunk that you want to free the children of
+ * (NULL is allowed too)
*/
void talloc_free_children(void *ptr);
-#if DOXYGEN
+#ifdef DOXYGEN
/**
* @brief Assign a destructor function to be called when a chunk is freed.
*
*
* @param[in] new_ctx The new parent context.
*
- * @param[in] ptr Pointer to the talloc chunk to move.
+ * @param[in] pptr Pointer to a pointer to the talloc chunk to move.
+ *
+ * @return The pointer to the talloc chunk that moved.
+ * It does not have any failure modes.
*
- * @return The pointer of the talloc chunk it has been moved to,
- * NULL on error.
*/
-void *talloc_move(const void *new_ctx, const void *ptr);
+void *talloc_move(const void *new_ctx, void **pptr);
#else
-#define talloc_move(ctx, ptr) (_TALLOC_TYPEOF(*(ptr)))_talloc_move((ctx),(void *)(ptr))
+#define talloc_move(ctx, pptr) (_TALLOC_TYPEOF(*(pptr)))_talloc_move((ctx),(void *)(pptr))
void *_talloc_move(const void *new_ctx, const void *pptr);
#endif
* @brief Allocate a new 0-sized talloc chunk.
*
* This is a utility macro that creates a new memory context hanging off an
- * exiting context, automatically naming it "talloc_new: __location__" where
+ * existing context, automatically naming it "talloc_new: __location__" where
* __location__ is the source line it is called from. It is particularly
* useful for creating a new temporary working context.
*
/**
* @brief Assign a type to a talloc chunk.
*
- * This macro allows you to force the name of a pointer to be a particular type.
- * This can be used in conjunction with talloc_get_type() to do type checking on
- * void* pointers.
+ * This macro allows you to force the name of a pointer to be of a particular
+ * type. This can be used in conjunction with talloc_get_type() to do type
+ * checking on void* pointers.
*
* It is equivalent to this:
*
*
* @return The properly casted pointer given by ptr, NULL on error.
*/
-void *talloc_get_name(const void *ptr, #type);
+type *talloc_get_type(const void *ptr, #type);
#else
#define talloc_set_type(ptr, type) talloc_set_name_const(ptr, #type)
#define talloc_get_type(ptr, type) (type *)talloc_check_name(ptr, #type)
* @brief Safely turn a void pointer into a typed pointer.
*
* This macro is used together with talloc(mem_ctx, struct foo). If you had to
- * assing the talloc chunk pointer to some void pointer variable,
+ * assign the talloc chunk pointer to some void pointer variable,
* talloc_get_type_abort() is the recommended way to get the convert the void
* pointer back to a typed pointer.
*
*
* @param[in] type The type that this chunk contains
*
- * @return The ame value as ptr, type-checked and properly cast.
+ * @return The same value as ptr, type-checked and properly cast.
*/
void *talloc_get_type_abort(const void *ptr, #type);
#else
+#ifdef TALLOC_GET_TYPE_ABORT_NOOP
+#define talloc_get_type_abort(ptr, type) (type *)(ptr)
+#else
#define talloc_get_type_abort(ptr, type) (type *)_talloc_get_type_abort(ptr, #type, __location__)
+#endif
void *_talloc_get_type_abort(const void *ptr, const char *name, const char *location);
#endif
* recursively. If you use the child of the talloc pool as a parent for
* grand-children, their memory is also taken from the talloc pool.
*
+ * If there is not enough memory in the pool to allocate the new child,
+ * it will create a new talloc chunk as if the parent was a normal talloc
+ * context.
+ *
* If you talloc_free() children of a talloc pool, the memory is not given
* back to the system. Instead, free(3) is only called if the talloc_pool()
* itself is released with talloc_free().
*/
void *talloc_pool(const void *context, size_t size);
+#ifdef DOXYGEN
+/**
+ * @brief Allocate a talloc object as/with an additional pool.
+ *
+ * This is like talloc_pool(), but's it's more flexible
+ * and allows an object to be a pool for its children.
+ *
+ * @param[in] ctx The talloc context to hang the result off.
+ *
+ * @param[in] type The type that we want to allocate.
+ *
+ * @param[in] num_subobjects The expected number of subobjects, which will
+ * be allocated within the pool. This allocates
+ * space for talloc_chunk headers.
+ *
+ * @param[in] total_subobjects_size The size that all subobjects can use in total.
+ *
+ *
+ * @return The allocated talloc object, NULL on error.
+ */
+void *talloc_pooled_object(const void *ctx, #type,
+ unsigned num_subobjects,
+ size_t total_subobjects_size);
+#else
+#define talloc_pooled_object(_ctx, _type, \
+ _num_subobjects, \
+ _total_subobjects_size) \
+ (_type *)_talloc_pooled_object((_ctx), sizeof(_type), #_type, \
+ (_num_subobjects), \
+ (_total_subobjects_size))
+void *_talloc_pooled_object(const void *ctx,
+ size_t type_size,
+ const char *type_name,
+ unsigned num_subobjects,
+ size_t total_subobjects_size);
+#endif
+
/**
* @brief Free a talloc chunk and NULL out the pointer.
*
*
* @param[in] ctx The chunk to be freed.
*/
-#define TALLOC_FREE(ctx) do { talloc_free(ctx); ctx=NULL; } while(0)
+#define TALLOC_FREE(ctx) do { if (ctx != NULL) { talloc_free(ctx); ctx=NULL; } } while(0)
/* @} ******************************************************************/
* will reduce the number of parents of this pointer by 1, and will
* cause this pointer to be freed if it runs out of parents.
*
- * - you can talloc_free() the pointer itself. That will destroy the
- * most recently established parent to the pointer and leave the
- * pointer as a child of its current parent.
+ * - you can talloc_free() the pointer itself if it has at maximum one
+ * parent. This behaviour has been changed since the release of version
+ * 2.0. Further informations in the description of "talloc_free".
*
* For more control on which parent to remove, see talloc_unlink()
* @param[in] ctx The additional parent.
* @return The original pointer 'ptr', NULL if talloc ran out of
* memory in creating the reference.
*
+ * @warning You should try to avoid using this interface. It turns a beautiful
+ * talloc-tree into a graph. It is often really hard to debug if you
+ * screw something up by accident.
+ *
* Example:
* @code
* unsigned int *a, *b, *c;
* either be a context used in talloc_reference() with this pointer, or must be
* a direct parent of ptr.
*
- * Usually you can just use talloc_free() instead of talloc_unlink(), but
- * sometimes it is useful to have the additional control on which parent is
- * removed.
+ * You can just use talloc_free() instead of talloc_unlink() if there
+ * is at maximum one parent. This behaviour has been changed since the
+ * release of version 2.0. Further informations in the description of
+ * "talloc_free".
*
* @param[in] context The talloc parent to remove.
*
* this function will fail and will return -1. Likewise, if ptr is NULL,
* then the function will make no modifications and return -1.
*
+ * @warning You should try to avoid using this interface. It turns a beautiful
+ * talloc-tree into a graph. It is often really hard to debug if you
+ * screw something up by accident.
+ *
* Example:
* @code
* unsigned int *a, *b, *c;
* which will be automatically freed on program exit. This can be used
* to reduce the noise in memory leak reports.
*
+ * Never use this in code that might be used in objects loaded with
+ * dlopen and unloaded with dlclose. talloc_autofree_context()
+ * internally uses atexit(3). Some platforms like modern Linux handles
+ * this fine, but for example FreeBSD does not deal well with dlopen()
+ * and atexit() used simultaneously: dlclose() does not clean up the
+ * list of atexit-handlers, so when the program exits the code that
+ * was registered from within talloc_autofree_context() is gone, the
+ * program crashes at exit.
+ *
* @return A talloc context, NULL on error.
*/
void *talloc_autofree_context(void);
/**
* @brief Get the size of a talloc chunk.
*
- * This function lets you know the amount of memory alloced so far by
+ * This function lets you know the amount of memory allocated so far by
* this context. It does NOT account for subcontext memory.
* This can be used to calculate the size of an array.
*
* @endcode
*
* @see talloc()
- * @see talloc_array_zero()
+ * @see talloc_zero_array()
*/
void *talloc_array(const void *ctx, #type, unsigned count);
#else
void *_talloc_realloc_array(const void *ctx, void *ptr, size_t el_size, unsigned count, const char *name);
#endif
-#if DOXYGEN
+#ifdef DOXYGEN
/**
* @brief Untyped realloc to change the size of a talloc array.
*
* @return The duplicated string, NULL on error.
*/
char *talloc_strdup(const void *t, const char *p);
+
+/**
+ * @brief Append a string to given string.
+ *
+ * The destination string is reallocated to take
+ * <code>strlen(s) + strlen(a) + 1</code> characters.
+ *
+ * This functions sets the name of the new pointer to the new
+ * string. This is equivalent to:
+ *
+ * @code
+ * talloc_set_name_const(ptr, ptr)
+ * @endcode
+ *
+ * If <code>s == NULL</code> then new context is created.
+ *
+ * @param[in] s The destination to append to.
+ *
+ * @param[in] a The string you want to append.
+ *
+ * @return The concatenated strings, NULL on error.
+ *
+ * @see talloc_strdup()
+ * @see talloc_strdup_append_buffer()
+ */
char *talloc_strdup_append(char *s, const char *a);
+
+/**
+ * @brief Append a string to a given buffer.
+ *
+ * This is a more efficient version of talloc_strdup_append(). It determines the
+ * length of the destination string by the size of the talloc context.
+ *
+ * Use this very carefully as it produces a different result than
+ * talloc_strdup_append() when a zero character is in the middle of the
+ * destination string.
+ *
+ * @code
+ * char *str_a = talloc_strdup(NULL, "hello world");
+ * char *str_b = talloc_strdup(NULL, "hello world");
+ * str_a[5] = str_b[5] = '\0'
+ *
+ * char *app = talloc_strdup_append(str_a, ", hello");
+ * char *buf = talloc_strdup_append_buffer(str_b, ", hello");
+ *
+ * printf("%s\n", app); // hello, hello (app = "hello, hello")
+ * printf("%s\n", buf); // hello (buf = "hello\0world, hello")
+ * @endcode
+ *
+ * If <code>s == NULL</code> then new context is created.
+ *
+ * @param[in] s The destination buffer to append to.
+ *
+ * @param[in] a The string you want to append.
+ *
+ * @return The concatenated strings, NULL on error.
+ *
+ * @see talloc_strdup()
+ * @see talloc_strdup_append()
+ * @see talloc_array_length()
+ */
char *talloc_strdup_append_buffer(char *s, const char *a);
/**
* @return The duplicated string, NULL on error.
*/
char *talloc_strndup(const void *t, const char *p, size_t n);
+
+/**
+ * @brief Append at most n characters of a string to given string.
+ *
+ * The destination string is reallocated to take
+ * <code>strlen(s) + strnlen(a, n) + 1</code> characters.
+ *
+ * This functions sets the name of the new pointer to the new
+ * string. This is equivalent to:
+ *
+ * @code
+ * talloc_set_name_const(ptr, ptr)
+ * @endcode
+ *
+ * If <code>s == NULL</code> then new context is created.
+ *
+ * @param[in] s The destination string to append to.
+ *
+ * @param[in] a The source string you want to append.
+ *
+ * @param[in] n The number of characters you want to append from the
+ * string.
+ *
+ * @return The concatenated strings, NULL on error.
+ *
+ * @see talloc_strndup()
+ * @see talloc_strndup_append_buffer()
+ */
char *talloc_strndup_append(char *s, const char *a, size_t n);
+
+/**
+ * @brief Append at most n characters of a string to given buffer
+ *
+ * This is a more efficient version of talloc_strndup_append(). It determines
+ * the length of the destination string by the size of the talloc context.
+ *
+ * Use this very carefully as it produces a different result than
+ * talloc_strndup_append() when a zero character is in the middle of the
+ * destination string.
+ *
+ * @code
+ * char *str_a = talloc_strdup(NULL, "hello world");
+ * char *str_b = talloc_strdup(NULL, "hello world");
+ * str_a[5] = str_b[5] = '\0'
+ *
+ * char *app = talloc_strndup_append(str_a, ", hello", 7);
+ * char *buf = talloc_strndup_append_buffer(str_b, ", hello", 7);
+ *
+ * printf("%s\n", app); // hello, hello (app = "hello, hello")
+ * printf("%s\n", buf); // hello (buf = "hello\0world, hello")
+ * @endcode
+ *
+ * If <code>s == NULL</code> then new context is created.
+ *
+ * @param[in] s The destination buffer to append to.
+ *
+ * @param[in] a The source string you want to append.
+ *
+ * @param[in] n The number of characters you want to append from the
+ * string.
+ *
+ * @return The concatenated strings, NULL on error.
+ *
+ * @see talloc_strndup()
+ * @see talloc_strndup_append()
+ * @see talloc_array_length()
+ */
char *talloc_strndup_append_buffer(char *s, const char *a, size_t n);
/**
* @return The formatted string, NULL on error.
*/
char *talloc_vasprintf(const void *t, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0);
+
+/**
+ * @brief Format a string given a va_list and append it to the given destination
+ * string.
+ *
+ * @param[in] s The destination string to append to.
+ *
+ * @param[in] fmt The format string.
+ *
+ * @param[in] ap The parameters used to fill fmt.
+ *
+ * @return The formatted string, NULL on error.
+ *
+ * @see talloc_vasprintf()
+ */
char *talloc_vasprintf_append(char *s, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0);
+
+/**
+ * @brief Format a string given a va_list and append it to the given destination
+ * buffer.
+ *
+ * @param[in] s The destination buffer to append to.
+ *
+ * @param[in] fmt The format string.
+ *
+ * @param[in] ap The parameters used to fill fmt.
+ *
+ * @return The formatted string, NULL on error.
+ *
+ * @see talloc_vasprintf()
+ */
char *talloc_vasprintf_append_buffer(char *s, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0);
/**
* @brief Append a formatted string to another string.
*
* This function appends the given formatted string to the given string. Use
- * this varient when the string in the current talloc buffer may have been
+ * this variant when the string in the current talloc buffer may have been
* truncated in length.
*
* This functions sets the name of the new pointer to the new
* talloc_set_name_const(ptr, ptr)
* @endcode
*
+ * If <code>s == NULL</code> then new context is created.
+ *
* @param[in] s The string to append to.
*
* @param[in] fmt The format string.
/**
* @brief Append a formatted string to another string.
*
+ * This is a more efficient version of talloc_asprintf_append(). It determines
+ * the length of the destination string by the size of the talloc context.
+ *
+ * Use this very carefully as it produces a different result than
+ * talloc_asprintf_append() when a zero character is in the middle of the
+ * destination string.
+ *
+ * @code
+ * char *str_a = talloc_strdup(NULL, "hello world");
+ * char *str_b = talloc_strdup(NULL, "hello world");
+ * str_a[5] = str_b[5] = '\0'
+ *
+ * char *app = talloc_asprintf_append(str_a, "%s", ", hello");
+ * char *buf = talloc_strdup_append_buffer(str_b, "%s", ", hello");
+ *
+ * printf("%s\n", app); // hello, hello (app = "hello, hello")
+ * printf("%s\n", buf); // hello (buf = "hello\0world, hello")
+ * @endcode
+ *
+ * If <code>s == NULL</code> then new context is created.
+ *
* @param[in] s The string to append to
*
* @param[in] fmt The format string.
* @param[in] ... The parameters used to fill fmt.
*
* @return The formatted string, NULL on error.
+ *
+ * @see talloc_asprintf()
+ * @see talloc_asprintf_append()
*/
char *talloc_asprintf_append_buffer(char *s, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3);
* @brief Print a summary report of all memory used by ptr.
*
* This provides a more detailed report than talloc_report(). It will
- * recursively print the ensire tree of memory referenced by the
+ * recursively print the entire tree of memory referenced by the
* pointer. References in the tree are shown by giving the name of the
* pointer that is referenced.
*
*/
void talloc_enable_leak_report_full(void);
-/* @} ******************************************************************/
-
+/**
+ * @brief Set a custom "abort" function that is called on serious error.
+ *
+ * The default "abort" function is <code>abort()</code>.
+ *
+ * The "abort" function is called when:
+ *
+ * <ul>
+ * <li>talloc_get_type_abort() fails</li>
+ * <li>the provided pointer is not a valid talloc context</li>
+ * <li>when the context meta data are invalid</li>
+ * <li>when access after free is detected</li>
+ * </ul>
+ *
+ * Example:
+ *
+ * @code
+ * void my_abort(const char *reason)
+ * {
+ * fprintf(stderr, "talloc abort: %s\n", reason);
+ * abort();
+ * }
+ *
+ * talloc_set_abort_fn(my_abort);
+ * @endcode
+ *
+ * @param[in] abort_fn The new "abort" function.
+ *
+ * @see talloc_set_log_fn()
+ * @see talloc_get_type()
+ */
void talloc_set_abort_fn(void (*abort_fn)(const char *reason));
+
+/**
+ * @brief Set a logging function.
+ *
+ * @param[in] log_fn The logging function.
+ *
+ * @see talloc_set_log_stderr()
+ * @see talloc_set_abort_fn()
+ */
void talloc_set_log_fn(void (*log_fn)(const char *message));
+
+/**
+ * @brief Set stderr as the output for logs.
+ *
+ * @see talloc_set_log_fn()
+ * @see talloc_set_abort_fn()
+ */
void talloc_set_log_stderr(void);
+/**
+ * @brief Set a max memory limit for the current context hierarchy
+ * This affects all children of this context and constrain any
+ * allocation in the hierarchy to never exceed the limit set.
+ * The limit can be removed by setting 0 (unlimited) as the
+ * max_size by calling the funciton again on the sam context.
+ * Memory limits can also be nested, meaning a hild can have
+ * a stricter memory limit than a parent.
+ * Memory limits are enforced only at memory allocation time.
+ * Stealing a context into a 'limited' hierarchy properly
+ * updates memory usage but does *not* cause failure if the
+ * move causes the new parent to exceed its limits. However
+ * any further allocation on that hierarchy will then fail.
+ *
+ * @param[in] ctx The talloc context to set the limit on
+ * @param[in] max_size The (new) max_size
+ */
+int talloc_set_memlimit(const void *ctx, size_t max_size);
+
+/* @} ******************************************************************/
+
#if TALLOC_DEPRECATED
#define talloc_zero_p(ctx, type) talloc_zero(ctx, type)
#define talloc_p(ctx, type) talloc(ctx, type)
#define talloc_append_string(c, s, a) (s?talloc_strdup_append(s,a):talloc_strdup(c, a))
#endif
+#ifndef TALLOC_MAX_DEPTH
+#define TALLOC_MAX_DEPTH 10000
+#endif
+
+#ifdef __cplusplus
+} /* end of extern "C" */
+#endif
+
#endif