📄 talloc.c
字号:
}/* A talloc version of realloc. The context argument is only used if ptr is NULL*/void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *name){ struct talloc_chunk *tc; void *new_ptr; /* size zero is equivalent to free() */ if (size == 0) { talloc_free(ptr); return NULL; } if (size >= MAX_TALLOC_SIZE) { return NULL; } /* realloc(NULL) is equavalent to malloc() */ if (ptr == NULL) { return talloc_named_const(context, size, name); } tc = talloc_chunk_from_ptr(ptr); /* don't allow realloc on referenced pointers */ if (tc->refs) { return NULL; } /* by resetting magic we catch users of the old memory */ tc->magic = TALLOC_MAGIC_FREE;#if ALWAYS_REALLOC new_ptr = malloc(size + sizeof(*tc)); if (new_ptr) { memcpy(new_ptr, tc, tc->size + sizeof(*tc)); free(tc); }#else new_ptr = realloc(tc, size + sizeof(*tc));#endif if (!new_ptr) { tc->magic = TALLOC_MAGIC; return NULL; } tc = new_ptr; tc->magic = TALLOC_MAGIC; if (tc->parent) { tc->parent->child = new_ptr; } if (tc->child) { tc->child->parent = new_ptr; } if (tc->prev) { tc->prev->next = tc; } if (tc->next) { tc->next->prev = tc; } tc->size = size; talloc_set_name_const(tc+1, name); return (void *)(tc+1);}/* move a lump of memory from one talloc context to another return the ptr on success, or NULL if it could not be transferred*/void *talloc_steal(const void *new_ctx, const void *ptr){ struct talloc_chunk *tc, *new_tc; if (!ptr) { return NULL; } if (new_ctx == NULL) { new_ctx = null_context; } tc = talloc_chunk_from_ptr(ptr); if (new_ctx == NULL) { if (tc->parent) { _TLIST_REMOVE(tc->parent->child, tc); if (tc->parent->child) { tc->parent->child->parent = tc->parent; } } else { if (tc->prev) tc->prev->next = tc->next; if (tc->next) tc->next->prev = tc->prev; } tc->parent = tc->next = tc->prev = NULL; return discard_const_p(void, ptr); } new_tc = talloc_chunk_from_ptr(new_ctx); if (tc == new_tc) { return discard_const_p(void, ptr); } if (tc->parent) { _TLIST_REMOVE(tc->parent->child, tc); if (tc->parent->child) { tc->parent->child->parent = tc->parent; } } else { if (tc->prev) tc->prev->next = tc->next; if (tc->next) tc->next->prev = tc->prev; } tc->parent = new_tc; if (new_tc->child) new_tc->child->parent = NULL; _TLIST_ADD(new_tc->child, tc); return discard_const_p(void, ptr);}/* return the total size of a talloc pool (subtree)*/off_t talloc_total_size(const void *ptr){ off_t total = 0; struct talloc_chunk *c, *tc; if (ptr == NULL) { ptr = null_context; } if (ptr == NULL) { return 0; } tc = talloc_chunk_from_ptr(ptr); total = tc->size; for (c=tc->child;c;c=c->next) { total += talloc_total_size(c+1); } return total;}/* return the total number of blocks in a talloc pool (subtree)*/off_t talloc_total_blocks(const void *ptr){ off_t total = 0; struct talloc_chunk *c, *tc = talloc_chunk_from_ptr(ptr); total++; for (c=tc->child;c;c=c->next) { total += talloc_total_blocks(c+1); } return total;}/* return the number of external references to a pointer*/static int talloc_reference_count(const void *ptr){ struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr); struct talloc_reference_handle *h; int ret = 0; for (h=tc->refs;h;h=h->next) { ret++; } return ret;}/* report on memory usage by all children of a pointer, giving a full tree view*/static void talloc_report_depth(const void *ptr, FILE *f, int depth){ struct talloc_chunk *c, *tc = talloc_chunk_from_ptr(ptr); for (c=tc->child;c;c=c->next) { if (c->name == TALLOC_MAGIC_REFERENCE) { struct talloc_reference_handle *handle = (void *)(c+1); const char *name2 = talloc_get_name(handle->ptr); fprintf(f, "%*sreference to: %s\n", depth*4, "", name2); } else { const char *name = talloc_get_name(c+1); fprintf(f, "%*s%-30s contains %6lu bytes in %3lu blocks (ref %d)\n", depth*4, "", name, (unsigned long)talloc_total_size(c+1), (unsigned long)talloc_total_blocks(c+1), talloc_reference_count(c+1)); talloc_report_depth(c+1, f, depth+1); } }}/* report on memory usage by all children of a pointer, giving a full tree view*/void talloc_report_full(const void *ptr, FILE *f){ if (ptr == NULL) { ptr = null_context; } if (ptr == NULL) return; fprintf(f,"full talloc report on '%s' (total %lu bytes in %lu blocks)\n", talloc_get_name(ptr), (unsigned long)talloc_total_size(ptr), (unsigned long)talloc_total_blocks(ptr)); talloc_report_depth(ptr, f, 1);}/* report on memory usage by all children of a pointer*/void talloc_report(const void *ptr, FILE *f){ struct talloc_chunk *c, *tc; if (ptr == NULL) { ptr = null_context; } if (ptr == NULL) return; fprintf(f,"talloc report on '%s' (total %lu bytes in %lu blocks)\n", talloc_get_name(ptr), (unsigned long)talloc_total_size(ptr), (unsigned long)talloc_total_blocks(ptr)); tc = talloc_chunk_from_ptr(ptr); for (c=tc->child;c;c=c->next) { fprintf(f, "\t%-30s contains %6lu bytes in %3lu blocks\n", talloc_get_name(c+1), (unsigned long)talloc_total_size(c+1), (unsigned long)talloc_total_blocks(c+1)); }}/* report on any memory hanging off the null context*/static void talloc_report_null(void){ if (talloc_total_size(null_context) != 0) { talloc_report(null_context, stderr); }}/* report on any memory hanging off the null context*/static void talloc_report_null_full(void){ if (talloc_total_size(null_context) != 0) { talloc_report_full(null_context, stderr); }}/* enable leak reporting on exit*/void talloc_enable_leak_report(void){ null_context = talloc_named_const(NULL, 0, "null_context"); atexit(talloc_report_null);}/* enable full leak reporting on exit*/void talloc_enable_leak_report_full(void){ null_context = talloc_named_const(NULL, 0, "null_context"); atexit(talloc_report_null_full);}/* talloc and zero memory. */void *_talloc_zero(const void *ctx, size_t size, const char *name){ void *p = talloc_named_const(ctx, size, name); if (p) { memset(p, '\0', size); } return p;}/* memdup with a talloc. */void *_talloc_memdup(const void *t, const void *p, size_t size, const char *name){ void *newp = talloc_named_const(t, size, name); if (newp) { memcpy(newp, p, size); } return newp;}/* strdup with a talloc */char *talloc_strdup(const void *t, const char *p){ char *ret; if (!p) { return NULL; } ret = talloc_memdup(t, p, strlen(p) + 1); if (ret) { talloc_set_name_const(ret, ret); } return ret;}/* strndup with a talloc */char *talloc_strndup(const void *t, const char *p, size_t n){ size_t len; char *ret; for (len=0; p[len] && len<n; len++) ; ret = _talloc(t, len + 1); if (!ret) { return NULL; } memcpy(ret, p, len); ret[len] = 0; talloc_set_name_const(ret, ret); return ret;}char *talloc_vasprintf(const void *t, const char *fmt, va_list ap){ int len; char *ret; va_list ap2; va_copy(ap2, ap); len = vsnprintf(NULL, 0, fmt, ap2); ret = _talloc(t, len+1); if (ret) { va_copy(ap2, ap); vsnprintf(ret, len+1, fmt, ap2); talloc_set_name_const(ret, ret); } return ret;}/* Perform string formatting, and return a pointer to newly allocated memory holding the result, inside a memory pool. */char *talloc_asprintf(const void *t, const char *fmt, ...){ va_list ap; char *ret; va_start(ap, fmt); ret = talloc_vasprintf(t, fmt, ap); va_end(ap); return ret;}/** * Realloc @p s to append the formatted result of @p fmt and @p ap, * and return @p s, which may have moved. Good for gradually * accumulating output into a string buffer. **/static char *talloc_vasprintf_append(char *s, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0);static char *talloc_vasprintf_append(char *s, const char *fmt, va_list ap){ int len, s_len; va_list ap2; va_copy(ap2, ap); if (s) { s_len = strlen(s); } else { s_len = 0; } len = vsnprintf(NULL, 0, fmt, ap2); s = talloc_realloc(NULL, s, s_len + len+1); if (!s) return NULL; va_copy(ap2, ap); vsnprintf(s+s_len, len+1, fmt, ap2); talloc_set_name_const(s, s); return s;}/* Realloc @p s to append the formatted result of @p fmt and return @p s, which may have moved. Good for gradually accumulating output into a string buffer. */char *talloc_asprintf_append(char *s, const char *fmt, ...){ va_list ap; va_start(ap, fmt); s = talloc_vasprintf_append(s, fmt, ap); va_end(ap); return s;}/* alloc an array, checking for integer overflow in the array size*/void *talloc_array_size(const void *ctx, size_t el_size, unsigned count, const char *name){ if (count >= MAX_TALLOC_SIZE/el_size) { return NULL; } return talloc_named_const(ctx, el_size * count, name);}/* alloc an zero array, checking for integer overflow in the array size*/void *_talloc_zero_array(const void *ctx, size_t el_size, unsigned count, const char *name){ if (count >= MAX_TALLOC_SIZE/el_size) { return NULL; } return _talloc_zero(ctx, el_size * count, name);}/* realloc an array, checking for integer overflow in the array size*/void *talloc_realloc_array(const void *ctx, void *ptr, size_t el_size, unsigned count, const char *name){ if (count >= MAX_TALLOC_SIZE/el_size) { return NULL; } ptr = talloc_realloc(ctx, ptr, el_size * count); if (ptr) { talloc_set_name_const(ptr, name); } return ptr;}/* a function version of talloc_realloc(), so it can be passed as a function pointer to libraries that want a realloc function (a realloc function encapsulates all the basic capabilities of an allocation library, which is why this is useful)*/void *talloc_realloc_fn(const void *context, void *ptr, size_t size){ return _talloc_realloc(context, ptr, size, NULL);}static void talloc_autofree(void){ talloc_free(cleanup_context); cleanup_context = NULL;}/* return a context which will be auto-freed on exit this is useful for reducing the noise in leak reports*/void *talloc_autofree_context(void){ if (cleanup_context == NULL) { cleanup_context = talloc_named_const(NULL, 0, "autofree_context"); atexit(talloc_autofree); } return cleanup_context;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -