mirror of
https://github.com/samba-team/samba.git
synced 2025-03-05 20:58:40 +03:00
r2744: ben elliston taught me about gcov today, which allows you to measure
the % coverage in terms of lines of code of a test suite. I thought a good first place to start with gcov was the talloc test suite. When I started the test suite covered about 60% of all lines of code in talloc.c, and now it covers about 99%. The only lines not covered are talloc corruption errors, as that would cause smb_panic() to fire. It will be interesting to try gcov on the main Samba test suite for smbd. We won't achieve 100% coverage, but it would be nice to get to 90% or more. I also modified the talloc.c sources to be able to be build standalone, using: gcc -c -D_STANDALONE_ -Iinlcude lib/talloc.c that should make it much easier to re-use talloc in other projects
This commit is contained in:
parent
43079cfc80
commit
8d4dc99b82
@ -1068,7 +1068,9 @@ time_t timegm(struct tm *tm);
|
||||
#include <sys/xattr.h>
|
||||
#endif
|
||||
|
||||
#define discard_const_p(type, ptr) (type *)discard_const(ptr)
|
||||
#define discard_const_p(type, ptr) ((type *)discard_const(ptr))
|
||||
|
||||
#define TALLOC_ABORT(reason) smb_panic(reason)
|
||||
|
||||
#endif /* _INCLUDES_H */
|
||||
|
||||
|
@ -49,5 +49,44 @@ typedef void TALLOC_CTX;
|
||||
#define data_blob(ptr, size) data_blob_named(ptr, size, __location__)
|
||||
#define data_blob_talloc(ctx, ptr, size) data_blob_talloc_named(ctx, ptr, size, __location__)
|
||||
|
||||
#ifndef PRINTF_ATTRIBUTE
|
||||
#define PRINTF_ATTRIBUTE(a1, a2)
|
||||
#endif
|
||||
|
||||
|
||||
/* The following definitions come from lib/talloc.c */
|
||||
void *_talloc(const void *context, size_t size);
|
||||
void talloc_set_destructor(const void *ptr, int (*destructor)(void *));
|
||||
void talloc_increase_ref_count(const void *ptr);
|
||||
void *talloc_reference(const void *context, const void *ptr);
|
||||
void *talloc_unreference(const void *context, const void *ptr);
|
||||
void talloc_set_name(const void *ptr, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3);
|
||||
void talloc_set_name_const(const void *ptr, const char *name);
|
||||
void *talloc_named(const void *context, size_t size,
|
||||
const char *fmt, ...) PRINTF_ATTRIBUTE(3,4);
|
||||
void *talloc_named_const(const void *context, size_t size, const char *name);
|
||||
const char *talloc_get_name(const void *ptr);
|
||||
void *talloc_init(const char *fmt, ...) PRINTF_ATTRIBUTE(1,2);
|
||||
int talloc_free(void *ptr);
|
||||
void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *name);
|
||||
void *talloc_steal(const void *new_ctx, const void *ptr);
|
||||
off_t talloc_total_size(const void *ptr);
|
||||
off_t talloc_total_blocks(const void *ptr);
|
||||
void talloc_report_full(const void *ptr, FILE *f);
|
||||
void talloc_report(const void *ptr, FILE *f);
|
||||
void talloc_enable_leak_report(void);
|
||||
void talloc_enable_leak_report_full(void);
|
||||
void *talloc_zero(const void *ctx, size_t size);
|
||||
void *_talloc_memdup(const void *t, const void *p, size_t size, const char *name);
|
||||
char *talloc_strdup(const void *t, const char *p);
|
||||
char *talloc_strndup(const void *t, const char *p, size_t n);
|
||||
char *talloc_vasprintf(const void *t, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0);
|
||||
char *talloc_asprintf(const void *t, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3);
|
||||
char *talloc_asprintf_append(char *s,
|
||||
const char *fmt, ...) PRINTF_ATTRIBUTE(2,3);
|
||||
void *talloc_array(const void *ctx, size_t el_size, unsigned count, const char *name);
|
||||
void *talloc_realloc_array(const void *ctx, void *ptr, size_t el_size, unsigned count, const char *name);
|
||||
void *talloc_ldb_alloc(void *context, void *ptr, size_t size);
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -1,7 +1,9 @@
|
||||
/*
|
||||
Samba Unix SMB/CIFS implementation.
|
||||
|
||||
Samba temporary memory allocation functions - new interface
|
||||
Samba trivial allocation library - new interface
|
||||
|
||||
NOTE: Please read talloc_guide.txt for full documentation
|
||||
|
||||
Copyright (C) Andrew Tridgell 2004
|
||||
|
||||
@ -24,14 +26,42 @@
|
||||
inspired by http://swapped.cc/halloc/
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
if you need to build this outside of the Samba source tree then please define _STANDALONE_
|
||||
*/
|
||||
#ifdef _STANDALONE_
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include "talloc.h"
|
||||
#else
|
||||
#include "includes.h"
|
||||
#endif
|
||||
|
||||
#define MAX_TALLOC_SIZE 0x10000000
|
||||
#define TALLOC_MAGIC 0xe814ec4f
|
||||
#define TALLOC_MAGIC_FREE 0x7faebef3
|
||||
#define TALLOC_MAGIC_REFERENCE ((const char *)1)
|
||||
|
||||
/* by default we abort when given a bad pointer (such as when talloc_free() is called
|
||||
on a pointer that came from malloc() */
|
||||
#ifndef TALLOC_ABORT
|
||||
#define TALLOC_ABORT(reason) abort()
|
||||
#endif
|
||||
|
||||
#ifndef discard_const_p
|
||||
#define discard_const_p(type, ptr) ((type *)(ptr))
|
||||
#endif
|
||||
|
||||
/* this null_context is only used if talloc_enable_leak_report() or
|
||||
talloc_enable_leak_report_full() is called, otherwise it remains
|
||||
NULL
|
||||
*/
|
||||
static const void *null_context;
|
||||
|
||||
|
||||
struct talloc_reference_handle {
|
||||
struct talloc_reference_handle *next, *prev;
|
||||
void *ptr;
|
||||
@ -44,7 +74,7 @@ struct talloc_chunk {
|
||||
struct talloc_chunk *parent, *child;
|
||||
struct talloc_reference_handle *refs;
|
||||
size_t size;
|
||||
uint_t magic;
|
||||
unsigned magic;
|
||||
talloc_destructor_t destructor;
|
||||
const char *name;
|
||||
};
|
||||
@ -52,17 +82,45 @@ struct talloc_chunk {
|
||||
/* panic if we get a bad magic value */
|
||||
static struct talloc_chunk *talloc_chunk_from_ptr(const void *ptr)
|
||||
{
|
||||
struct talloc_chunk *tc = ((struct talloc_chunk *)discard_const(ptr))-1;
|
||||
if (tc->magic != TALLOC_MAGIC) {
|
||||
struct talloc_chunk *tc = discard_const_p(struct talloc_chunk, ptr)-1;
|
||||
if (tc->magic != TALLOC_MAGIC) {
|
||||
if (tc->magic == TALLOC_MAGIC_FREE) {
|
||||
smb_panic("Bad talloc magic value - double free\n");
|
||||
TALLOC_ABORT("Bad talloc magic value - double free");
|
||||
} else {
|
||||
smb_panic("Bad talloc magic value\n");
|
||||
TALLOC_ABORT("Bad talloc magic value - unknown value");
|
||||
}
|
||||
}
|
||||
|
||||
return tc;
|
||||
}
|
||||
|
||||
/* hook into the front of the list */
|
||||
#define _TLIST_ADD(list, p) \
|
||||
do { \
|
||||
if (!(list)) { \
|
||||
(list) = (p); \
|
||||
(p)->next = (p)->prev = NULL; \
|
||||
} else { \
|
||||
(list)->prev = (p); \
|
||||
(p)->next = (list); \
|
||||
(p)->prev = NULL; \
|
||||
(list) = (p); \
|
||||
}\
|
||||
} while (0)
|
||||
|
||||
/* remove an element from a list - element doesn't have to be in list. */
|
||||
#define _TLIST_REMOVE(list, p) \
|
||||
do { \
|
||||
if ((p) == (list)) { \
|
||||
(list) = (p)->next; \
|
||||
if (list) (list)->prev = NULL; \
|
||||
} else { \
|
||||
if ((p)->prev) (p)->prev->next = (p)->next; \
|
||||
if ((p)->next) (p)->next->prev = (p)->prev; \
|
||||
} \
|
||||
if ((p) && ((p) != (list))) (p)->next = (p)->prev = NULL; \
|
||||
} while (0)
|
||||
|
||||
|
||||
/*
|
||||
return the parent chunk of a pointer
|
||||
@ -90,9 +148,7 @@ void *_talloc(const void *context, size_t size)
|
||||
}
|
||||
|
||||
tc = malloc(sizeof(*tc)+size);
|
||||
if (tc == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
if (tc == NULL) return NULL;
|
||||
|
||||
tc->size = size;
|
||||
tc->magic = TALLOC_MAGIC;
|
||||
@ -110,7 +166,7 @@ void *_talloc(const void *context, size_t size)
|
||||
parent->child->parent = NULL;
|
||||
}
|
||||
|
||||
DLIST_ADD(parent->child, tc);
|
||||
_TLIST_ADD(parent->child, tc);
|
||||
} else {
|
||||
tc->next = tc->prev = tc->parent = NULL;
|
||||
}
|
||||
@ -150,7 +206,7 @@ static int talloc_reference_destructor(void *ptr)
|
||||
if (tc1->destructor != (talloc_destructor_t)-1) {
|
||||
tc1->destructor = NULL;
|
||||
}
|
||||
DLIST_REMOVE(tc2->refs, handle);
|
||||
_TLIST_REMOVE(tc2->refs, handle);
|
||||
talloc_free(handle);
|
||||
return 0;
|
||||
}
|
||||
@ -168,16 +224,15 @@ void *talloc_reference(const void *context, const void *ptr)
|
||||
{
|
||||
struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
|
||||
struct talloc_reference_handle *handle;
|
||||
handle = talloc_named_const(context, sizeof(*handle), ".reference");
|
||||
if (handle == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
handle = talloc_named_const(context, sizeof(*handle), TALLOC_MAGIC_REFERENCE);
|
||||
if (handle == NULL) return NULL;
|
||||
|
||||
/* note that we hang the destructor off the handle, not the
|
||||
main context as that allows the caller to still setup their
|
||||
own destructor on the context if they want to */
|
||||
talloc_set_destructor(handle, talloc_reference_destructor);
|
||||
handle->ptr = discard_const(ptr);
|
||||
DLIST_ADD(tc->refs, handle);
|
||||
handle->ptr = discard_const_p(void, ptr);
|
||||
_TLIST_ADD(tc->refs, handle);
|
||||
return handle->ptr;
|
||||
}
|
||||
|
||||
@ -204,9 +259,9 @@ void *talloc_unreference(const void *context, const void *ptr)
|
||||
}
|
||||
|
||||
talloc_set_destructor(h, NULL);
|
||||
DLIST_REMOVE(tc->refs, h);
|
||||
_TLIST_REMOVE(tc->refs, h);
|
||||
talloc_free(h);
|
||||
return discard_const(ptr);
|
||||
return discard_const_p(void, ptr);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -226,7 +281,7 @@ static void talloc_set_name_v(const void *ptr, const char *fmt, va_list ap)
|
||||
/*
|
||||
add a name to an existing pointer
|
||||
*/
|
||||
void talloc_set_name(const void *ptr, const char *fmt, ...) _PRINTF_ATTRIBUTE(2,3)
|
||||
void talloc_set_name(const void *ptr, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
@ -249,16 +304,13 @@ void talloc_set_name_const(const void *ptr, const char *name)
|
||||
talloc_named() operates just like talloc() except that it allows you
|
||||
to name the pointer.
|
||||
*/
|
||||
void *talloc_named(const void *context, size_t size,
|
||||
const char *fmt, ...) _PRINTF_ATTRIBUTE(3,4)
|
||||
void *talloc_named(const void *context, size_t size, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
void *ptr;
|
||||
|
||||
ptr = _talloc(context, size);
|
||||
if (ptr == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
if (ptr == NULL) return NULL;
|
||||
|
||||
va_start(ap, fmt);
|
||||
talloc_set_name_v(ptr, fmt, ap);
|
||||
@ -292,6 +344,9 @@ void *talloc_named_const(const void *context, size_t size, const char *name)
|
||||
const char *talloc_get_name(const void *ptr)
|
||||
{
|
||||
struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
|
||||
if (tc->name == TALLOC_MAGIC_REFERENCE) {
|
||||
return ".reference";
|
||||
}
|
||||
if (tc->name) {
|
||||
return tc->name;
|
||||
}
|
||||
@ -301,15 +356,13 @@ const char *talloc_get_name(const void *ptr)
|
||||
/*
|
||||
this is for compatibility with older versions of talloc
|
||||
*/
|
||||
void *talloc_init(const char *fmt, ...) _PRINTF_ATTRIBUTE(1,2)
|
||||
void *talloc_init(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
void *ptr;
|
||||
|
||||
ptr = _talloc(NULL, 0);
|
||||
if (ptr == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
if (ptr == NULL) return NULL;
|
||||
|
||||
va_start(ap, fmt);
|
||||
talloc_set_name_v(ptr, fmt, ap);
|
||||
@ -375,7 +428,7 @@ int talloc_free(void *ptr)
|
||||
}
|
||||
|
||||
if (tc->parent) {
|
||||
DLIST_REMOVE(tc->parent->child, tc);
|
||||
_TLIST_REMOVE(tc->parent->child, tc);
|
||||
if (tc->parent->child) {
|
||||
tc->parent->child->parent = tc->parent;
|
||||
}
|
||||
@ -407,6 +460,10 @@ void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *n
|
||||
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);
|
||||
@ -423,9 +480,9 @@ void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *n
|
||||
tc->magic = TALLOC_MAGIC_FREE;
|
||||
|
||||
new_ptr = realloc(tc, size + sizeof(*tc));
|
||||
if (!new_ptr) {
|
||||
tc->magic = TALLOC_MAGIC;
|
||||
return NULL;
|
||||
if (!new_ptr) {
|
||||
tc->magic = TALLOC_MAGIC;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tc = new_ptr;
|
||||
@ -463,7 +520,7 @@ void *talloc_steal(const void *new_ctx, const void *ptr)
|
||||
|
||||
if (new_ctx == NULL) {
|
||||
if (tc->parent) {
|
||||
DLIST_REMOVE(tc->parent->child, tc);
|
||||
_TLIST_REMOVE(tc->parent->child, tc);
|
||||
if (tc->parent->child) {
|
||||
tc->parent->child->parent = tc->parent;
|
||||
}
|
||||
@ -473,17 +530,17 @@ void *talloc_steal(const void *new_ctx, const void *ptr)
|
||||
}
|
||||
|
||||
tc->parent = tc->next = tc->prev = NULL;
|
||||
return discard_const(ptr);
|
||||
return discard_const_p(void, ptr);
|
||||
}
|
||||
|
||||
new_tc = talloc_chunk_from_ptr(new_ctx);
|
||||
|
||||
if (tc == new_tc) {
|
||||
return discard_const(ptr);
|
||||
return discard_const_p(void, ptr);
|
||||
}
|
||||
|
||||
if (tc->parent) {
|
||||
DLIST_REMOVE(tc->parent->child, tc);
|
||||
_TLIST_REMOVE(tc->parent->child, tc);
|
||||
if (tc->parent->child) {
|
||||
tc->parent->child->parent = tc->parent;
|
||||
}
|
||||
@ -494,9 +551,9 @@ void *talloc_steal(const void *new_ctx, const void *ptr)
|
||||
|
||||
tc->parent = new_tc;
|
||||
if (new_tc->child) new_tc->child->parent = NULL;
|
||||
DLIST_ADD(new_tc->child, tc);
|
||||
_TLIST_ADD(new_tc->child, tc);
|
||||
|
||||
return discard_const(ptr);
|
||||
return discard_const_p(void, ptr);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -561,12 +618,12 @@ 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) {
|
||||
const char *name = talloc_get_name(c+1);
|
||||
if (strcmp(name, ".reference") == 0) {
|
||||
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,
|
||||
@ -630,10 +687,9 @@ void talloc_report(const void *ptr, FILE *f)
|
||||
*/
|
||||
static void talloc_report_null(void)
|
||||
{
|
||||
if (talloc_total_size(null_context) == 0) {
|
||||
return;
|
||||
if (talloc_total_size(null_context) != 0) {
|
||||
talloc_report(null_context, stderr);
|
||||
}
|
||||
talloc_report(null_context, stderr);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -641,10 +697,9 @@ static void talloc_report_null(void)
|
||||
*/
|
||||
static void talloc_report_null_full(void)
|
||||
{
|
||||
if (talloc_total_size(null_context) == 0) {
|
||||
return;
|
||||
if (talloc_total_size(null_context) != 0) {
|
||||
talloc_report_full(null_context, stderr);
|
||||
}
|
||||
talloc_report_full(null_context, stderr);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -715,9 +770,11 @@ char *talloc_strdup(const void *t, const char *p)
|
||||
*/
|
||||
char *talloc_strndup(const void *t, const char *p, size_t n)
|
||||
{
|
||||
size_t len = strnlen(p, 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);
|
||||
@ -725,7 +782,15 @@ char *talloc_strndup(const void *t, const char *p, size_t n)
|
||||
return ret;
|
||||
}
|
||||
|
||||
char *talloc_vasprintf(const void *t, const char *fmt, va_list ap) _PRINTF_ATTRIBUTE(2,0)
|
||||
#ifndef VA_COPY
|
||||
#ifdef HAVE_VA_COPY
|
||||
#define VA_COPY(dest, src) __va_copy(dest, src)
|
||||
#else
|
||||
#define VA_COPY(dest, src) (dest) = (src)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
char *talloc_vasprintf(const void *t, const char *fmt, va_list ap)
|
||||
{
|
||||
int len;
|
||||
char *ret;
|
||||
@ -750,7 +815,7 @@ char *talloc_vasprintf(const void *t, const char *fmt, va_list ap) _PRINTF_ATTRI
|
||||
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, ...) _PRINTF_ATTRIBUTE(2,3)
|
||||
char *talloc_asprintf(const void *t, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char *ret;
|
||||
@ -768,11 +833,9 @@ char *talloc_asprintf(const void *t, const char *fmt, ...) _PRINTF_ATTRIBUTE(2,3
|
||||
* 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) PRINTF_ATTRIBUTE(2,0);
|
||||
|
||||
static char *talloc_vasprintf_append(char *s,
|
||||
const char *fmt, va_list ap)
|
||||
static char *talloc_vasprintf_append(char *s, const char *fmt, va_list ap)
|
||||
{
|
||||
int len, s_len;
|
||||
va_list ap2;
|
||||
@ -802,8 +865,7 @@ static char *talloc_vasprintf_append(char *s,
|
||||
s, which may have moved. Good for gradually accumulating output
|
||||
into a string buffer.
|
||||
*/
|
||||
char *talloc_asprintf_append(char *s,
|
||||
const char *fmt, ...) _PRINTF_ATTRIBUTE(2,3)
|
||||
char *talloc_asprintf_append(char *s, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
@ -816,7 +878,7 @@ char *talloc_asprintf_append(char *s,
|
||||
/*
|
||||
alloc an array, checking for integer overflow in the array size
|
||||
*/
|
||||
void *talloc_array(const void *ctx, size_t el_size, uint_t count, const char *name)
|
||||
void *talloc_array(const void *ctx, size_t el_size, unsigned count, const char *name)
|
||||
{
|
||||
if (count == 0 ||
|
||||
count >= MAX_TALLOC_SIZE/el_size) {
|
||||
@ -829,7 +891,7 @@ void *talloc_array(const void *ctx, size_t el_size, uint_t count, const char *na
|
||||
/*
|
||||
realloc an array, checking for integer overflow in the array size
|
||||
*/
|
||||
void *talloc_realloc_array(const void *ctx, void *ptr, size_t el_size, uint_t count, const char *name)
|
||||
void *talloc_realloc_array(const void *ctx, void *ptr, size_t el_size, unsigned count, const char *name)
|
||||
{
|
||||
if (count == 0 ||
|
||||
count >= MAX_TALLOC_SIZE/el_size) {
|
||||
|
@ -24,8 +24,8 @@
|
||||
|
||||
#define CHECK_BLOCKS(ptr, tblocks) do { \
|
||||
if (talloc_total_blocks(ptr) != (tblocks)) { \
|
||||
printf("(%d) failed: wrong '%s' tree size: got %u expected %u\n", \
|
||||
__LINE__, #ptr, \
|
||||
printf(__location__ " failed: wrong '%s' tree blocks: got %u expected %u\n", \
|
||||
#ptr, \
|
||||
(unsigned)talloc_total_blocks(ptr), \
|
||||
(unsigned)tblocks); \
|
||||
talloc_report_full(ptr, stdout); \
|
||||
@ -33,6 +33,17 @@
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define CHECK_SIZE(ptr, tsize) do { \
|
||||
if (talloc_total_size(ptr) != (tsize)) { \
|
||||
printf(__location__ " failed: wrong '%s' tree size: got %u expected %u\n", \
|
||||
#ptr, \
|
||||
(unsigned)talloc_total_size(ptr), \
|
||||
(unsigned)tsize); \
|
||||
talloc_report_full(ptr, stdout); \
|
||||
return False; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
test references
|
||||
*/
|
||||
@ -77,10 +88,7 @@ static BOOL test_ref1(void)
|
||||
|
||||
CHECK_BLOCKS(root, 1);
|
||||
|
||||
if (talloc_total_size(root) != 0) {
|
||||
printf("failed: non-zero total size\n");
|
||||
return False;
|
||||
}
|
||||
CHECK_SIZE(root, 0);
|
||||
|
||||
talloc_free(root);
|
||||
|
||||
@ -136,10 +144,7 @@ static BOOL test_ref2(void)
|
||||
talloc_free(r1);
|
||||
talloc_report_full(root, stdout);
|
||||
|
||||
if (talloc_total_size(root) != 0) {
|
||||
printf("failed: non-zero total size\n");
|
||||
return False;
|
||||
}
|
||||
CHECK_SIZE(root, 0);
|
||||
|
||||
talloc_free(root);
|
||||
|
||||
@ -177,10 +182,7 @@ static BOOL test_ref3(void)
|
||||
talloc_free(p2);
|
||||
talloc_report_full(root, stdout);
|
||||
|
||||
if (talloc_total_size(root) != 0) {
|
||||
printf("failed: non-zero total size\n");
|
||||
return False;
|
||||
}
|
||||
CHECK_SIZE(root, 0);
|
||||
|
||||
talloc_free(root);
|
||||
|
||||
@ -228,10 +230,7 @@ static BOOL test_ref4(void)
|
||||
talloc_free(p1);
|
||||
talloc_report_full(root, stdout);
|
||||
|
||||
if (talloc_total_size(root) != 0) {
|
||||
printf("failed: non-zero total size\n");
|
||||
return False;
|
||||
}
|
||||
CHECK_SIZE(root, 0);
|
||||
|
||||
talloc_free(root);
|
||||
|
||||
@ -275,13 +274,290 @@ static BOOL test_unref1(void)
|
||||
talloc_free(p1);
|
||||
talloc_report_full(root, stdout);
|
||||
|
||||
if (talloc_total_size(root) != 0) {
|
||||
printf("failed: non-zero total size\n");
|
||||
CHECK_SIZE(root, 0);
|
||||
|
||||
talloc_free(root);
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
static int fail_destructor(void *ptr)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
miscellaneous tests to try to get a higher test coverage percentage
|
||||
*/
|
||||
static BOOL test_misc(void)
|
||||
{
|
||||
void *root, *p1;
|
||||
char *p2;
|
||||
double *d;
|
||||
|
||||
printf("TESTING MISCELLANEOUS\n");
|
||||
|
||||
root = talloc(NULL, 0);
|
||||
|
||||
p1 = talloc(root, 0x7fffffff);
|
||||
if (p1) {
|
||||
printf("failed: large talloc allowed\n");
|
||||
return False;
|
||||
}
|
||||
|
||||
p1 = talloc_strdup(root, "foo");
|
||||
talloc_increase_ref_count(p1);
|
||||
talloc_increase_ref_count(p1);
|
||||
talloc_increase_ref_count(p1);
|
||||
CHECK_BLOCKS(p1, 1);
|
||||
CHECK_BLOCKS(root, 2);
|
||||
talloc_free(p1);
|
||||
CHECK_BLOCKS(p1, 1);
|
||||
CHECK_BLOCKS(root, 2);
|
||||
talloc_unreference(NULL, p1);
|
||||
CHECK_BLOCKS(p1, 1);
|
||||
CHECK_BLOCKS(root, 2);
|
||||
if (talloc_unreference(root, p1) != NULL) {
|
||||
printf("failed: talloc_unreference() of non-reference context should return NULL\n");
|
||||
return False;
|
||||
}
|
||||
talloc_free(p1);
|
||||
CHECK_BLOCKS(p1, 1);
|
||||
CHECK_BLOCKS(root, 2);
|
||||
|
||||
talloc_set_name(p1, "my name is %s", "foo");
|
||||
if (strcmp(talloc_get_name(p1), "my name is foo") != 0) {
|
||||
printf("failed: wrong name after talloc_set_name\n");
|
||||
return False;
|
||||
}
|
||||
CHECK_BLOCKS(p1, 2);
|
||||
CHECK_BLOCKS(root, 3);
|
||||
|
||||
talloc_set_name_const(p1, NULL);
|
||||
if (strcmp(talloc_get_name(p1), "UNNAMED") != 0) {
|
||||
printf("failed: wrong name after talloc_set_name(NULL)\n");
|
||||
return False;
|
||||
}
|
||||
CHECK_BLOCKS(p1, 2);
|
||||
CHECK_BLOCKS(root, 3);
|
||||
|
||||
|
||||
if (talloc_free(NULL) != -1) {
|
||||
printf("talloc_free(NULL) should give -1\n");
|
||||
return False;
|
||||
}
|
||||
|
||||
talloc_set_destructor(p1, fail_destructor);
|
||||
if (talloc_free(p1) != -1) {
|
||||
printf("Failed destructor should cause talloc_free to fail\n");
|
||||
return False;
|
||||
}
|
||||
talloc_set_destructor(p1, NULL);
|
||||
|
||||
talloc_report(root, stdout);
|
||||
|
||||
|
||||
p2 = talloc_zero(p1, 20);
|
||||
if (p2[19] != 0) {
|
||||
printf("Failed to give zero memory\n");
|
||||
return False;
|
||||
}
|
||||
talloc_free(p2);
|
||||
|
||||
if (talloc_strdup(root, NULL) != NULL) {
|
||||
printf("failed: strdup on NULL should give NULL\n");
|
||||
return False;
|
||||
}
|
||||
|
||||
p2 = talloc_strndup(p1, "foo", 2);
|
||||
if (strcmp("fo", p2) != 0) {
|
||||
printf("failed: strndup doesn't work\n");
|
||||
return False;
|
||||
}
|
||||
p2 = talloc_asprintf_append(p2, "o%c", 'd');
|
||||
if (strcmp("food", p2) != 0) {
|
||||
printf("failed: talloc_asprintf_append doesn't work\n");
|
||||
return False;
|
||||
}
|
||||
CHECK_BLOCKS(p2, 1);
|
||||
CHECK_BLOCKS(p1, 3);
|
||||
|
||||
p2 = talloc_asprintf_append(NULL, "hello %s", "world");
|
||||
if (strcmp("hello world", p2) != 0) {
|
||||
printf("failed: talloc_asprintf_append doesn't work\n");
|
||||
return False;
|
||||
}
|
||||
CHECK_BLOCKS(p2, 1);
|
||||
CHECK_BLOCKS(p1, 3);
|
||||
talloc_free(p2);
|
||||
|
||||
d = talloc_array_p(p1, double, 0x20000000);
|
||||
if (d) {
|
||||
printf("failed: integer overflow not detected\n");
|
||||
return False;
|
||||
}
|
||||
|
||||
d = talloc_realloc_p(p1, d, double, 0x20000000);
|
||||
if (d) {
|
||||
printf("failed: integer overflow not detected\n");
|
||||
return False;
|
||||
}
|
||||
|
||||
talloc_free(p1);
|
||||
CHECK_BLOCKS(root, 1);
|
||||
|
||||
talloc_report(root, stdout);
|
||||
talloc_report(NULL, stdout);
|
||||
|
||||
CHECK_SIZE(root, 0);
|
||||
|
||||
talloc_free(root);
|
||||
|
||||
CHECK_SIZE(NULL, 0);
|
||||
|
||||
talloc_enable_leak_report();
|
||||
talloc_enable_leak_report_full();
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
test realloc
|
||||
*/
|
||||
static BOOL test_realloc(void)
|
||||
{
|
||||
void *root, *p1, *p2;
|
||||
|
||||
printf("TESTING REALLOC\n");
|
||||
|
||||
root = talloc(NULL, 0);
|
||||
|
||||
p1 = talloc(root, 10);
|
||||
CHECK_SIZE(p1, 10);
|
||||
|
||||
p1 = talloc_realloc(NULL, p1, 20);
|
||||
CHECK_SIZE(p1, 20);
|
||||
|
||||
talloc(p1, 0);
|
||||
|
||||
p2 = talloc_realloc(p1, NULL, 30);
|
||||
|
||||
talloc(p1, 0);
|
||||
|
||||
p2 = talloc_realloc(p1, p2, 40);
|
||||
|
||||
CHECK_SIZE(p2, 40);
|
||||
CHECK_SIZE(root, 60);
|
||||
CHECK_BLOCKS(p1, 4);
|
||||
|
||||
p1 = talloc_realloc(NULL, p1, 20);
|
||||
CHECK_SIZE(p1, 60);
|
||||
|
||||
talloc_increase_ref_count(p2);
|
||||
if (talloc_realloc(NULL, p2, 5) != NULL) {
|
||||
printf("failed: talloc_realloc() on a referenced pointer should fail\n");
|
||||
return False;
|
||||
}
|
||||
CHECK_BLOCKS(p1, 4);
|
||||
|
||||
talloc_realloc(NULL, p2, 0);
|
||||
talloc_realloc(NULL, p2, 0);
|
||||
CHECK_BLOCKS(p1, 3);
|
||||
|
||||
if (talloc_realloc(NULL, p1, 0x7fffffff) != NULL) {
|
||||
printf("failed: oversize talloc should fail\n");
|
||||
return False;
|
||||
}
|
||||
|
||||
talloc_realloc(NULL, p1, 0);
|
||||
|
||||
CHECK_BLOCKS(root, 1);
|
||||
CHECK_SIZE(root, 0);
|
||||
|
||||
talloc_free(root);
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
/*
|
||||
test steal
|
||||
*/
|
||||
static BOOL test_steal(void)
|
||||
{
|
||||
void *root, *p1, *p2;
|
||||
|
||||
printf("TESTING STEAL\n");
|
||||
|
||||
root = talloc(NULL, 0);
|
||||
|
||||
p1 = talloc_array_p(root, char, 10);
|
||||
CHECK_SIZE(p1, 10);
|
||||
|
||||
p2 = talloc_realloc_p(root, NULL, char, 20);
|
||||
CHECK_SIZE(p1, 10);
|
||||
CHECK_SIZE(root, 30);
|
||||
|
||||
if (talloc_steal(p1, NULL) != NULL) {
|
||||
printf("failed: stealing NULL should give NULL\n");
|
||||
return False;
|
||||
}
|
||||
|
||||
if (talloc_steal(p1, p1) != p1) {
|
||||
printf("failed: stealing to ourselves is a nop\n");
|
||||
return False;
|
||||
}
|
||||
CHECK_BLOCKS(root, 3);
|
||||
CHECK_SIZE(root, 30);
|
||||
|
||||
talloc_steal(NULL, p1);
|
||||
talloc_steal(NULL, p2);
|
||||
CHECK_BLOCKS(root, 1);
|
||||
CHECK_SIZE(root, 0);
|
||||
|
||||
talloc_free(p1);
|
||||
talloc_steal(root, p2);
|
||||
CHECK_BLOCKS(root, 2);
|
||||
CHECK_SIZE(root, 20);
|
||||
|
||||
talloc_free(p2);
|
||||
|
||||
CHECK_BLOCKS(root, 1);
|
||||
CHECK_SIZE(root, 0);
|
||||
|
||||
talloc_free(root);
|
||||
|
||||
p1 = talloc(NULL, 3);
|
||||
CHECK_SIZE(NULL, 3);
|
||||
talloc_free(p1);
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
/*
|
||||
test ldb alloc fn
|
||||
*/
|
||||
static BOOL test_ldb(void)
|
||||
{
|
||||
void *root, *p1;
|
||||
|
||||
printf("TESTING LDB\n");
|
||||
|
||||
root = talloc(NULL, 0);
|
||||
|
||||
p1 = talloc_ldb_alloc(root, NULL, 10);
|
||||
CHECK_BLOCKS(root, 2);
|
||||
CHECK_SIZE(root, 10);
|
||||
p1 = talloc_ldb_alloc(root, p1, 20);
|
||||
CHECK_BLOCKS(root, 2);
|
||||
CHECK_SIZE(root, 20);
|
||||
p1 = talloc_ldb_alloc(root, p1, 0);
|
||||
CHECK_BLOCKS(root, 1);
|
||||
CHECK_SIZE(root, 0);
|
||||
|
||||
talloc_free(root);
|
||||
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
@ -340,6 +616,10 @@ BOOL torture_local_talloc(int dummy)
|
||||
ret &= test_ref3();
|
||||
ret &= test_ref4();
|
||||
ret &= test_unref1();
|
||||
ret &= test_misc();
|
||||
ret &= test_realloc();
|
||||
ret &= test_steal();
|
||||
ret &= test_ldb();
|
||||
ret &= test_speed();
|
||||
|
||||
return ret;
|
||||
|
@ -125,7 +125,9 @@ After creating a reference you can free it in one of the following
|
||||
ways:
|
||||
|
||||
- you can talloc_free() a parent of the original pointer. That will
|
||||
destroy the reference and make the pointer a child of "context".
|
||||
destroy the reference and make the pointer a child of the
|
||||
"context" argument from the most recently called
|
||||
talloc_reference() on the pointer.
|
||||
|
||||
- you can talloc_free() the pointer itself. That will destroy the
|
||||
most recently established reference to the pointer and leave the
|
||||
|
Loading…
x
Reference in New Issue
Block a user