tdb and ldb

Rusty Russell rusty at rustcorp.com.au
Fri Feb 3 13:31:47 MST 2012


On Thu, 2 Feb 2012 13:32:31 +0100, Volker Lendecke <Volker.Lendecke at SerNet.DE> wrote:
> On Thu, Feb 02, 2012 at 12:32:27PM +1030, Rusty Russell wrote:
> > On Wed, 01 Feb 2012 16:49:48 +1100, Andrew Bartlett <abartlet at samba.org> wrote:
> > > Rusty,
> > > 
> > > It would seem that the next logical step would be to have ldb move to
> > > directly using only the TDB2 API and library.  It isn't shared with the
> > > autoconf build, so this restriction won't cause any issues.  The
> > > unshared code in source4 and the waf build in general could then move
> > > next. 
> > 
> > There's one really compelling reason to do that: the (yet-unexistsing)
> > allocator attribute.  That will make tdb2 use the given allocator
> > (ie. talloc), so we can get have tallocated tdb_contexts and TDB_DATAs.
> 
> Given we have tdb_parse_record now I'm not sure we need a
> custom allocator for tdb_fetch or equivalents.

I hadn't thought of using tdb_parse_record() that way.  Clever!

Note that tdb_parse_record() does a copy if you're inside a transaction.
TDB2 does better, but there are still some cases where it's necessary.

> tdb_contexts are being taken care of by tdb_wrap, so I'm not sure that
> we need to extend the API with a custom allocator.

But TDB2 handles multiple opens correctly internally, so tdb_wrap is
only useful to provide a nice talloc handle.

The most compelling reason is that it's simple; API extension is really
easy for TDB2, and this gives us not just support for talloc, but for
any allocator.

Cheers,
Rusty.

tdb2: TDB_ATTRIBUTE_ALLOCATOR

This allows replacement of malloc/realloc/free, in particular, talloc
can use these hooks to make a tdb a genuine talloc object.

Note the "expand" rather than a complete realloc; some code paths have
to change to accomodate this, but it's clearer than a generic realloc
hook.

diff --git a/lib/tdb2/tdb2.h b/lib/tdb2/tdb2.h
index 44e7897..a183233 100644
--- a/lib/tdb2/tdb2.h
+++ b/lib/tdb2/tdb2.h
@@ -638,6 +638,7 @@ enum tdb_attribute_type {
 	TDB_ATTRIBUTE_STATS = 3,
 	TDB_ATTRIBUTE_OPENHOOK = 4,
 	TDB_ATTRIBUTE_FLOCK = 5,
+	TDB_ATTRIBUTE_ALLOCATOR = 6,
 	TDB_ATTRIBUTE_TDB1_HASHSIZE = 128,
 	TDB_ATTRIBUTE_TDB1_MAX_DEAD = 129,
 };
@@ -872,6 +873,29 @@ struct tdb_attribute_flock {
 };
 
 /**
+ * struct tdb_attribute_allocator - allocator for tdb to use.
+ *
+ * You can replace malloc/free with your own allocation functions.
+ * The allocator takes an "owner" pointer, which is either NULL (for
+ * the initial struct tdb_context and struct tdb_file), or a
+ * previously allocated pointer.  This is useful for relationship
+ * tracking, such as the talloc library.
+ *
+ * The expand function is realloc, but only ever used to expand an
+ * existing allocation.
+ *
+ * Be careful mixing allocators: two tdb_contexts which have the same file
+ * open will share the same struct tdb_file.  This may be allocated by one
+ * tdb's allocator, and freed by the other.
+ */
+struct tdb_attribute_allocator {
+	struct tdb_attribute_base base; /* .attr = TDB_ATTRIBUTE_ALLOCATOR */
+	void *(*alloc)(const void *owner, size_t len);
+	void *(*expand)(void *old, size_t newlen);
+	void (*free)(void *old);
+};
+
+/**
  * struct tdb_attribute_tdb1_hashsize - tdb1 hashsize
  *
  * This attribute allows setting the TDB1 hashsize; it only makes sense with
@@ -915,6 +939,7 @@ union tdb_attribute {
 	struct tdb_attribute_stats stats;
 	struct tdb_attribute_openhook openhook;
 	struct tdb_attribute_flock flock;
+	struct tdb_attribute_allocator alloc;
 	struct tdb_attribute_tdb1_hashsize tdb1_hashsize;
 	struct tdb_attribute_tdb1_max_dead tdb1_max_dead;
 };
diff --git a/lib/tdb2/check.c b/lib/tdb2/check.c
index ecd6c13..b91818d 100644
--- a/lib/tdb2/check.c
+++ b/lib/tdb2/check.c
@@ -20,9 +20,16 @@
 #include <ccan/asearch/asearch.h>
 
 /* We keep an ordered array of offsets. */
-static bool append(tdb_off_t **arr, size_t *num, tdb_off_t off)
+static bool append(struct tdb_context *tdb,
+		   tdb_off_t **arr, size_t *num, tdb_off_t off)
 {
-	tdb_off_t *new = realloc(*arr, (*num + 1) * sizeof(tdb_off_t));
+	tdb_off_t *new;
+
+	if (*num == 0) {
+		new = tdb->alloc(tdb, sizeof(tdb_off_t));
+	} else {
+		new = tdb->expand(*arr, (*num + 1) * sizeof(tdb_off_t));
+	}
 	if (!new)
 		return false;
 	new[(*num)++] = off;
@@ -708,7 +715,7 @@ static enum TDB_ERROR check_linear(struct tdb_context *tdb,
 			}
 			/* This record should be in free lists. */
 			if (frec_ftable(&rec.f) != TDB_FTABLE_NONE
-			    && !append(fr, num_free, off)) {
+			    && !append(tdb, fr, num_free, off)) {
 				return tdb_logerr(tdb, TDB_ERR_OOM,
 						  TDB_LOG_ERROR,
 						  "tdb_check: tracking %zu'th"
@@ -722,7 +729,7 @@ static enum TDB_ERROR check_linear(struct tdb_context *tdb,
 			uint64_t klen, dlen, extra;
 
 			/* This record is used! */
-			if (!append(used, num_used, off)) {
+			if (!append(tdb, used, num_used, off)) {
 				return tdb_logerr(tdb, TDB_ERR_OOM,
 						  TDB_LOG_ERROR,
 						  "tdb_check: tracking %zu'th"
@@ -864,7 +871,7 @@ enum TDB_ERROR tdb_check_(struct tdb_context *tdb,
 out:
 	tdb_allrecord_unlock(tdb, F_RDLCK);
 	tdb_unlock_expand(tdb, F_RDLCK);
-	free(fr);
-	free(used);
+	tdb->free(fr);
+	tdb->free(used);
 	return tdb->last_error = ecode;
 }
diff --git a/lib/tdb2/io.c b/lib/tdb2/io.c
index b4a6f0b..85a5062 100644
--- a/lib/tdb2/io.c
+++ b/lib/tdb2/io.c
@@ -109,7 +109,7 @@ static enum TDB_ERROR tdb_oob(struct tdb_context *tdb,
 
 		tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR,
 			   "tdb_oob len %lld beyond internal"
-			   " malloc size %lld",
+			   " alloc size %lld",
 			   (long long)(off + len),
 			   (long long)tdb->file->map_size);
 		return TDB_ERR_IO;
@@ -319,7 +319,7 @@ enum TDB_ERROR tdb_write_convert(struct tdb_context *tdb, tdb_off_t off,
 	enum TDB_ERROR ecode;
 
 	if (unlikely((tdb->flags & TDB_CONVERT))) {
-		void *conv = malloc(len);
+		void *conv = tdb->alloc(tdb, len);
 		if (!conv) {
 			return tdb_logerr(tdb, TDB_ERR_OOM, TDB_LOG_ERROR,
 					  "tdb_write: no memory converting"
@@ -328,7 +328,7 @@ enum TDB_ERROR tdb_write_convert(struct tdb_context *tdb, tdb_off_t off,
 		memcpy(conv, rec, len);
 		ecode = tdb->tdb2.io->twrite(tdb, off,
 					   tdb_convert(tdb, conv, len), len);
-		free(conv);
+		tdb->free(conv);
 	} else {
 		ecode = tdb->tdb2.io->twrite(tdb, off, rec, len);
 	}
@@ -372,16 +372,16 @@ static void *_tdb_alloc_read(struct tdb_context *tdb, tdb_off_t offset,
 	enum TDB_ERROR ecode;
 
 	/* some systems don't like zero length malloc */
-	buf = malloc(prefix + len ? prefix + len : 1);
+	buf = tdb->alloc(tdb, prefix + len ? prefix + len : 1);
 	if (!buf) {
 		tdb_logerr(tdb, TDB_ERR_OOM, TDB_LOG_USE_ERROR,
-			   "tdb_alloc_read malloc failed len=%zu",
+			   "tdb_alloc_read alloc failed len=%zu",
 			   (size_t)(prefix + len));
 		return TDB_ERR_PTR(TDB_ERR_OOM);
 	} else {
 		ecode = tdb->tdb2.io->tread(tdb, offset, buf+prefix, len);
 		if (unlikely(ecode != TDB_SUCCESS)) {
-			free(buf);
+			tdb->free(buf);
 			return TDB_ERR_PTR(ecode);
 		}
 	}
@@ -431,8 +431,8 @@ static enum TDB_ERROR tdb_expand_file(struct tdb_context *tdb,
 	}
 
 	if (tdb->flags & TDB_INTERNAL) {
-		char *new = realloc(tdb->file->map_ptr,
-				    tdb->file->map_size + addition);
+		char *new = tdb->expand(tdb->file->map_ptr,
+					tdb->file->map_size + addition);
 		if (!new) {
 			return tdb_logerr(tdb, TDB_ERR_OOM, TDB_LOG_ERROR,
 					  "No memory to expand database");
@@ -549,7 +549,7 @@ void tdb_access_release(struct tdb_context *tdb, const void *p)
 	if (hp) {
 		hdr = *hp;
 		*hp = hdr->next;
-		free(hdr);
+		tdb->free(hdr);
 	} else
 		tdb->tdb2.direct_access--;
 }
@@ -566,7 +566,7 @@ enum TDB_ERROR tdb_access_commit(struct tdb_context *tdb, void *p)
 		else
 			ecode = tdb_write(tdb, hdr->off, p, hdr->len);
 		*hp = hdr->next;
-		free(hdr);
+		tdb->free(hdr);
 	} else {
 		tdb->tdb2.direct_access--;
 		ecode = TDB_SUCCESS;
diff --git a/lib/tdb2/lock.c b/lib/tdb2/lock.c
index a71c95f..fe25a2b 100644
--- a/lib/tdb2/lock.c
+++ b/lib/tdb2/lock.c
@@ -388,10 +388,13 @@ enum TDB_ERROR tdb_nest_lock(struct tdb_context *tdb,
 				  "tdb_nest_lock: already have a hash lock?");
 	}
 #endif
-
-	new_lck = (struct tdb_lock *)realloc(
-		tdb->file->lockrecs,
-		sizeof(*tdb->file->lockrecs) * (tdb->file->num_lockrecs+1));
+	if (tdb->file->num_lockrecs == 0) {
+		new_lck = tdb->alloc(tdb->file, sizeof(*tdb->file->lockrecs));
+	} else {
+		new_lck = (struct tdb_lock *)tdb->expand(
+			tdb->file->lockrecs,
+			sizeof(*tdb->file->lockrecs) * (tdb->file->num_lockrecs+1));
+	}
 	if (new_lck == NULL) {
 		return tdb_logerr(tdb, TDB_ERR_OOM, TDB_LOG_ERROR,
 				  "tdb_nest_lock:"
diff --git a/lib/tdb2/open.c b/lib/tdb2/open.c
index 2730f21..8ecc494 100644
--- a/lib/tdb2/open.c
+++ b/lib/tdb2/open.c
@@ -164,7 +164,7 @@ static enum TDB_ERROR tdb_new_database(struct tdb_context *tdb,
 
 	if (tdb->flags & TDB_INTERNAL) {
 		tdb->file->map_size = sizeof(newdb);
-		tdb->file->map_ptr = malloc(tdb->file->map_size);
+		tdb->file->map_ptr = tdb->alloc(tdb, tdb->file->map_size);
 		if (!tdb->file->map_ptr) {
 			return tdb_logerr(tdb, TDB_ERR_OOM, TDB_LOG_ERROR,
 					  "tdb_new_database:"
@@ -198,7 +198,7 @@ static enum TDB_ERROR tdb_new_database(struct tdb_context *tdb,
 
 static enum TDB_ERROR tdb_new_file(struct tdb_context *tdb)
 {
-	tdb->file = malloc(sizeof(*tdb->file));
+	tdb->file = tdb->alloc(NULL, sizeof(*tdb->file));
 	if (!tdb->file)
 		return tdb_logerr(tdb, TDB_ERR_OOM, TDB_LOG_ERROR,
 				  "tdb_open: cannot alloc tdb_file structure");
@@ -245,6 +245,11 @@ enum TDB_ERROR tdb_set_attribute(struct tdb_context *tdb,
 		tdb->unlock_fn = attr->flock.unlock;
 		tdb->lock_data = attr->flock.data;
 		break;
+	case TDB_ATTRIBUTE_ALLOCATOR:
+		tdb->alloc = attr->alloc.alloc;
+		tdb->expand = attr->alloc.expand;
+		tdb->free = attr->alloc.free;
+		break;
 	default:
 		return tdb->last_error
 			= tdb_logerr(tdb, TDB_ERR_EINVAL,
@@ -298,6 +303,11 @@ enum TDB_ERROR tdb_get_attribute(struct tdb_context *tdb,
 		attr->flock.unlock = tdb->unlock_fn;
 		attr->flock.data = tdb->lock_data;
 		break;
+	case TDB_ATTRIBUTE_ALLOCATOR:
+		attr->alloc.alloc = tdb->alloc;;
+		attr->alloc.expand = tdb->expand;
+		attr->alloc.free = tdb->free;
+		break;
 	case TDB_ATTRIBUTE_TDB1_HASHSIZE:
 		if (!(tdb->flags & TDB_VERSION1))
 			return tdb->last_error
@@ -424,6 +434,26 @@ static enum TDB_ERROR capabilities_ok(struct tdb_context *tdb,
 	return ecode;
 }
 
+static void *default_alloc(const void *owner, size_t len)
+{
+	return malloc(len);
+}
+
+/* First allocation needs manual search of attributes. */
+static struct tdb_context *alloc_tdb(const union tdb_attribute *attr,
+				     const char *name)
+{
+	size_t len = sizeof(struct tdb_context) + (name ? strlen(name) + 1 : 0);
+
+	while (attr) {
+		if  (attr->base.attr == TDB_ATTRIBUTE_ALLOCATOR) {
+			return attr->alloc.alloc(NULL, len);
+		}
+		attr = attr->base.next;
+	}
+	return default_alloc(NULL, len);
+}
+
 struct tdb_context *tdb_open(const char *name, int tdb_flags,
 			     int open_flags, mode_t mode,
 			     union tdb_attribute *attr)
@@ -442,7 +472,7 @@ struct tdb_context *tdb_open(const char *name, int tdb_flags,
 	enum TDB_ERROR ecode;
 	int openlock;
 
-	tdb = malloc(sizeof(*tdb) + (name ? strlen(name) + 1 : 0));
+	tdb = alloc_tdb(attr, name);
 	if (!tdb) {
 		/* Can't log this */
 		errno = ENOMEM;
@@ -466,6 +496,9 @@ struct tdb_context *tdb_open(const char *name, int tdb_flags,
 	memset(&tdb->stats, 0, sizeof(tdb->stats));
 	tdb->stats.base.attr = TDB_ATTRIBUTE_STATS;
 	tdb->stats.size = sizeof(tdb->stats);
+	tdb->alloc = default_alloc;
+	tdb->expand = realloc;
+	tdb->free = free;
 
 	while (attr) {
 		switch (attr->base.attr) {
@@ -807,7 +840,7 @@ fail_errno:
 			assert(tdb->file->num_lockrecs == 0);
 			if (tdb->file->map_ptr) {
 				if (tdb->flags & TDB_INTERNAL) {
-					free(tdb->file->map_ptr);
+					tdb->free(tdb->file->map_ptr);
 				} else
 					tdb_munmap(tdb->file);
 			}
@@ -815,12 +848,12 @@ fail_errno:
 				tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR,
 					   "tdb_open: failed to close tdb fd"
 					   " on error: %s", strerror(errno));
-			free(tdb->file->lockrecs);
-			free(tdb->file);
+			tdb->free(tdb->file->lockrecs);
+			tdb->free(tdb->file);
 		}
 	}
 
-	free(tdb);
+	tdb->free(tdb);
 	errno = saved_errno;
 	return NULL;
 }
@@ -844,7 +877,7 @@ int tdb_close(struct tdb_context *tdb)
 
 	if (tdb->file->map_ptr) {
 		if (tdb->flags & TDB_INTERNAL)
-			free(tdb->file->map_ptr);
+			tdb->free(tdb->file->map_ptr);
 		else
 			tdb_munmap(tdb->file);
 	}
@@ -852,8 +885,8 @@ int tdb_close(struct tdb_context *tdb)
 		tdb_lock_cleanup(tdb);
 		if (--tdb->file->refcnt == 0) {
 			ret = close(tdb->file->fd);
-			free(tdb->file->lockrecs);
-			free(tdb->file);
+			tdb->free(tdb->file->lockrecs);
+			tdb->free(tdb->file);
 		}
 	}
 
@@ -868,7 +901,7 @@ int tdb_close(struct tdb_context *tdb)
 #ifdef TDB_TRACE
 	close(tdb->tracefd);
 #endif
-	free(tdb);
+	tdb->free(tdb);
 
 	return ret;
 }
diff --git a/lib/tdb2/private.h b/lib/tdb2/private.h
index 91d3ca0..474eb2b 100644
--- a/lib/tdb2/private.h
+++ b/lib/tdb2/private.h
@@ -630,6 +630,11 @@ struct tdb_context {
 	void *hash_data;
 	uint64_t hash_seed;
 
+	/* Allocate and free functions. */
+	void *(*alloc)(const void *owner, size_t len);
+	void *(*expand)(void *old, size_t newlen);
+	void (*free)(void *old);
+
 	/* Our open hook, if any. */
 	enum TDB_ERROR (*openhook)(int fd, void *data);
 	void *openhook_data;
diff --git a/lib/tdb2/summary.c b/lib/tdb2/summary.c
index f3a3a08..8efa8e2 100644
--- a/lib/tdb2/summary.c
+++ b/lib/tdb2/summary.c
@@ -287,7 +287,7 @@ enum TDB_ERROR tdb_summary(struct tdb_context *tdb,
 		+ (uncoalg ? strlen(uncoalg) : 0)
 		+ num_caps * (strlen(CAPABILITY_FORMAT) + 20*4);
 
-	*summary = malloc(len);
+	*summary = tdb->alloc(tdb, len);
 	if (!*summary) {
 		ecode = tdb_logerr(tdb, TDB_ERR_OOM, TDB_LOG_ERROR,
 				   "tdb_summary: failed to allocate string");
@@ -335,20 +335,20 @@ enum TDB_ERROR tdb_summary(struct tdb_context *tdb,
 	add_capabilities(tdb, num_caps, *summary);
 
 unlock:
-	free(hashesg);
-	free(freeg);
-	free(keysg);
-	free(datag);
-	free(extrag);
-	free(uncoalg);
-	free(hashes);
-	free(freet);
-	free(keys);
-	free(data);
-	free(extra);
-	free(uncoal);
-	free(ftables);
-	free(chains);
+	tdb->free(hashesg);
+	tdb->free(freeg);
+	tdb->free(keysg);
+	tdb->free(datag);
+	tdb->free(extrag);
+	tdb->free(uncoalg);
+	tdb->free(hashes);
+	tdb->free(freet);
+	tdb->free(keys);
+	tdb->free(data);
+	tdb->free(extra);
+	tdb->free(uncoal);
+	tdb->free(ftables);
+	tdb->free(chains);
 
 	tdb_allrecord_unlock(tdb, F_RDLCK);
 	tdb_unlock_expand(tdb, F_RDLCK);
diff --git a/lib/tdb2/tdb.c b/lib/tdb2/tdb.c
index 5e965ac..dfcdcd8 100644
--- a/lib/tdb2/tdb.c
+++ b/lib/tdb2/tdb.c
@@ -216,7 +216,7 @@ enum TDB_ERROR tdb_append(struct tdb_context *tdb,
 		}
 
 		/* Slow path. */
-		newdata = malloc(key.dsize + old_dlen + dbuf.dsize);
+		newdata = tdb->alloc(tdb, key.dsize + old_dlen + dbuf.dsize);
 		if (!newdata) {
 			ecode = tdb_logerr(tdb, TDB_ERR_OOM, TDB_LOG_ERROR,
 					   "tdb_append:"
@@ -242,7 +242,7 @@ enum TDB_ERROR tdb_append(struct tdb_context *tdb,
 	ecode = replace_data(tdb, &h, key, new_dbuf, off, old_room, true);
 
 out_free_newdata:
-	free(newdata);
+	tdb->free(newdata);
 out:
 	tdb_unlock_hashes(tdb, h.hlock_start, h.hlock_range, F_WRLCK);
 	return tdb->last_error = ecode;
@@ -491,16 +491,20 @@ enum TDB_ERROR COLD tdb_logerr(struct tdb_context *tdb,
 		return ecode;
 
 	va_start(ap, fmt);
-	len = vasprintf(&message, fmt, ap);
+	len = vsnprintf(NULL, 0, fmt, ap);
 	va_end(ap);
 
-	if (len < 0) {
+	message = tdb->alloc(tdb, len + 1);
+	if (!message) {
 		tdb->log_fn(tdb, TDB_LOG_ERROR, TDB_ERR_OOM,
 			    "out of memory formatting message:", tdb->log_data);
 		tdb->log_fn(tdb, level, ecode, fmt, tdb->log_data);
 	} else {
+		va_start(ap, fmt);
+		vsnprintf(message, len+1, fmt, ap);
+		va_end(ap);
 		tdb->log_fn(tdb, level, ecode, message, tdb->log_data);
-		free(message);
+		tdb->free(message);
 	}
 	errno = saved_errno;
 	return ecode;
diff --git a/lib/tdb2/tdb1_check.c b/lib/tdb2/tdb1_check.c
index a8e54b2..9aff370 100644
--- a/lib/tdb2/tdb1_check.c
+++ b/lib/tdb2/tdb1_check.c
@@ -151,7 +151,7 @@ static void put_bytes(struct tdb_context *tdb, TDB_DATA d)
 {
 	if (tdb->tdb1.transaction == NULL && tdb->file->map_ptr != NULL)
 		return;
-	free(d.dptr);
+	tdb->free(d.dptr);
 }
 
 /* We use the excellent Jenkins lookup3 hash; this is based on hash_word2.
@@ -364,16 +364,17 @@ int tdb1_check(struct tdb_context *tdb,
 		goto unlock;
 	}
 
-	/* One big malloc: pointers then bit arrays. */
+	/* One big alloc: pointers then bit arrays. */
 	alloc_len = sizeof(hashes[0]) * (1+tdb->tdb1.header.hash_size)
 		+ BITMAP_BITS / CHAR_BIT * (1+tdb->tdb1.header.hash_size);
-	hashes = (unsigned char **)calloc(1, alloc_len);
+	hashes = (unsigned char **)tdb->alloc(tdb, alloc_len);
 	if (!hashes) {
 		tdb->last_error = tdb_logerr(tdb, TDB_ERR_OOM, TDB_LOG_ERROR,
 					     "tdb_check: could not allocate %zu",
 					     alloc_len);
 		goto unlock;
 	}
+	memset(hashes, 0, alloc_len);
 
 	/* Initialize pointers */
 	hashes[0] = (unsigned char *)(&hashes[1+tdb->tdb1.header.hash_size]);
@@ -462,14 +463,14 @@ int tdb1_check(struct tdb_context *tdb,
 		goto free;
 	}
 
-	free(hashes);
+	tdb->free(hashes);
 	if (locked) {
 		tdb_unlockall_read(tdb);
 	}
 	return 0;
 
 free:
-	free(hashes);
+	tdb->free(hashes);
 unlock:
 	if (locked) {
 		tdb_unlockall_read(tdb);
diff --git a/lib/tdb2/tdb1_io.c b/lib/tdb2/tdb1_io.c
index f3d139d..49e5e6f 100644
--- a/lib/tdb2/tdb1_io.c
+++ b/lib/tdb2/tdb1_io.c
@@ -44,7 +44,7 @@ static int tdb1_oob(struct tdb_context *tdb, tdb1_off_t len, int probe)
 	if (tdb->flags & TDB_INTERNAL) {
 		if (!probe) {
 			tdb->last_error = tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR,
-						"tdb1_oob len %d beyond internal malloc size %d",
+						"tdb1_oob len %d beyond internal alloc size %d",
 						(int)len, (int)tdb->file->map_size);
 		}
 		return -1;
@@ -367,8 +367,8 @@ int tdb1_expand(struct tdb_context *tdb, tdb1_off_t size)
 	tdb->file->map_size += size;
 
 	if (tdb->flags & TDB_INTERNAL) {
-		char *new_map_ptr = (char *)realloc(tdb->file->map_ptr,
-						    tdb->file->map_size);
+		char *new_map_ptr = (char *)tdb->expand(tdb->file->map_ptr,
+							tdb->file->map_size);
 		if (!new_map_ptr) {
 			tdb->last_error = tdb_logerr(tdb, TDB_ERR_OOM,
 						     TDB_LOG_ERROR,
@@ -424,15 +424,15 @@ unsigned char *tdb1_alloc_read(struct tdb_context *tdb, tdb1_off_t offset, tdb1_
 
 	/* some systems don't like zero length malloc */
 
-	if (!(buf = (unsigned char *)malloc(len ? len : 1))) {
+	if (!(buf = (unsigned char *)tdb->alloc(tdb, len ? len : 1))) {
 		tdb->last_error = tdb_logerr(tdb, TDB_ERR_OOM, TDB_LOG_ERROR,
-					     "tdb1_alloc_read malloc failed"
+					     "tdb1_alloc_read alloc failed"
 					     " len=%d (%s)",
 					     len, strerror(errno));
 		return NULL;
 	}
 	if (tdb->tdb1.io->tdb1_read(tdb, offset, buf, len, 0) == -1) {
-		SAFE_FREE(buf);
+		SAFE_FREE(tdb, buf);
 		return NULL;
 	}
 	return buf;
@@ -468,7 +468,7 @@ enum TDB_ERROR tdb1_parse_data(struct tdb_context *tdb, TDB_DATA key,
 	}
 
 	result = parser(key, data, private_data);
-	free(data.dptr);
+	tdb->free(data.dptr);
 	return result;
 }
 
diff --git a/lib/tdb2/tdb1_lock.c b/lib/tdb2/tdb1_lock.c
index 5cc0ad6..d6026ea 100644
--- a/lib/tdb2/tdb1_lock.c
+++ b/lib/tdb2/tdb1_lock.c
@@ -555,6 +555,6 @@ void tdb1_release_transaction_locks(struct tdb_context *tdb)
 	}
 	tdb->file->num_lockrecs = active;
 	if (tdb->file->num_lockrecs == 0) {
-		SAFE_FREE(tdb->file->lockrecs);
+		SAFE_FREE(tdb, tdb->file->lockrecs);
 	}
 }
diff --git a/lib/tdb2/tdb1_open.c b/lib/tdb2/tdb1_open.c
index e668616..9f30d54 100644
--- a/lib/tdb2/tdb1_open.c
+++ b/lib/tdb2/tdb1_open.c
@@ -87,10 +87,11 @@ enum TDB_ERROR tdb1_new_database(struct tdb_context *tdb,
 
 	/* We make it up in memory, then write it out if not internal */
 	size = sizeof(struct tdb1_header) + (hash_size+1)*sizeof(tdb1_off_t);
-	if (!(newdb = (struct tdb1_header *)calloc(size, 1))) {
+	if (!(newdb = (struct tdb1_header *)tdb->alloc(tdb, size))) {
 		return tdb_logerr(tdb, TDB_ERR_OOM, TDB_LOG_ERROR,
 				  "Could not allocate new database header");
 	}
+	memset(newdb, 0, sizeof(*newdb));
 
 	/* Fill in the header */
 	newdb->version = TDB1_VERSION;
@@ -134,7 +135,7 @@ enum TDB_ERROR tdb1_new_database(struct tdb_context *tdb,
 	ret = TDB_SUCCESS;
 
   fail:
-	SAFE_FREE(newdb);
+	SAFE_FREE(tdb, newdb);
 	return ret;
 }
 
diff --git a/lib/tdb2/tdb1_private.h b/lib/tdb2/tdb1_private.h
index 68dc39f..3dd131a 100644
--- a/lib/tdb2/tdb1_private.h
+++ b/lib/tdb2/tdb1_private.h
@@ -78,7 +78,7 @@
 
 /* free memory if the pointer is valid and zero the pointer */
 #ifndef SAFE_FREE
-#define SAFE_FREE(x) do { if ((x) != NULL) {free((void *)x); (x)=NULL;} } while(0)
+#define SAFE_FREE(tdb, x) do { if ((x) != NULL) { tdb->free((void *)x); (x)=NULL;} } while(0)
 #endif
 
 #define TDB1_BUCKET(hash) ((hash) % tdb->tdb1.header.hash_size)
diff --git a/lib/tdb2/tdb1_summary.c b/lib/tdb2/tdb1_summary.c
index b74b8f4..506ea49 100644
--- a/lib/tdb2/tdb1_summary.c
+++ b/lib/tdb2/tdb1_summary.c
@@ -165,7 +165,7 @@ char *tdb1_summary(struct tdb_context *tdb)
 
 	/* 20 is max length of a %zu. */
 	len = strlen(SUMMARY_FORMAT1) + 35*20 + 1;
-	ret = (char *)malloc(len);
+	ret = (char *)tdb->alloc(tdb, len);
 	if (!ret)
 		goto unlock;
 
diff --git a/lib/tdb2/tdb1_tdb.c b/lib/tdb2/tdb1_tdb.c
index 869672a..2e83955 100644
--- a/lib/tdb2/tdb1_tdb.c
+++ b/lib/tdb2/tdb1_tdb.c
@@ -647,7 +647,7 @@ int tdb1_append(struct tdb_context *tdb, TDB_DATA key, TDB_DATA new_dbuf)
 	dbuf = _tdb1_fetch(tdb, key);
 
 	if (dbuf.dptr == NULL) {
-		dbuf.dptr = (unsigned char *)malloc(new_dbuf.dsize);
+		dbuf.dptr = (unsigned char *)tdb->alloc(tdb, new_dbuf.dsize);
 	} else {
 		unsigned int new_len = dbuf.dsize + new_dbuf.dsize;
 		unsigned char *new_dptr;
@@ -655,9 +655,9 @@ int tdb1_append(struct tdb_context *tdb, TDB_DATA key, TDB_DATA new_dbuf)
 		/* realloc '0' is special: don't do that. */
 		if (new_len == 0)
 			new_len = 1;
-		new_dptr = (unsigned char *)realloc(dbuf.dptr, new_len);
+		new_dptr = (unsigned char *)tdb->expand(dbuf.dptr, new_len);
 		if (new_dptr == NULL) {
-			free(dbuf.dptr);
+			tdb->free(dbuf.dptr);
 		}
 		dbuf.dptr = new_dptr;
 	}
@@ -674,7 +674,7 @@ int tdb1_append(struct tdb_context *tdb, TDB_DATA key, TDB_DATA new_dbuf)
 
 failed:
 	tdb1_unlock(tdb, TDB1_BUCKET(hash), F_WRLCK);
-	SAFE_FREE(dbuf.dptr);
+	SAFE_FREE(tdb, dbuf.dptr);
 	return ret;
 }
 
diff --git a/lib/tdb2/tdb1_transaction.c b/lib/tdb2/tdb1_transaction.c
index 411caef..d749850 100644
--- a/lib/tdb2/tdb1_transaction.c
+++ b/lib/tdb2/tdb1_transaction.c
@@ -242,10 +242,11 @@ static int transaction1_write(struct tdb_context *tdb, tdb1_off_t off,
 		uint8_t **new_blocks;
 		/* expand the blocks array */
 		if (tdb->tdb1.transaction->blocks == NULL) {
-			new_blocks = (uint8_t **)malloc(
-				(blk+1)*sizeof(uint8_t *));
+			new_blocks = (uint8_t **)
+				tdb->alloc(tdb->tdb1.transaction,
+					   (blk+1)*sizeof(uint8_t *));
 		} else {
-			new_blocks = (uint8_t **)realloc(
+			new_blocks = (uint8_t **)tdb->expand(
 				tdb->tdb1.transaction->blocks,
 				(blk+1)*sizeof(uint8_t *));
 		}
@@ -262,12 +263,16 @@ static int transaction1_write(struct tdb_context *tdb, tdb1_off_t off,
 
 	/* allocate and fill a block? */
 	if (tdb->tdb1.transaction->blocks[blk] == NULL) {
-		tdb->tdb1.transaction->blocks[blk] = (uint8_t *)calloc(tdb->tdb1.transaction->block_size, 1);
+		tdb->tdb1.transaction->blocks[blk] = (uint8_t *)
+			tdb->alloc(tdb->tdb1.transaction,
+				   tdb->tdb1.transaction->block_size);
 		if (tdb->tdb1.transaction->blocks[blk] == NULL) {
 			tdb->last_error = TDB_ERR_OOM;
 			tdb->tdb1.transaction->transaction_error = 1;
 			return -1;
 		}
+		memset(tdb->tdb1.transaction->blocks[blk], 0,
+		       tdb->tdb1.transaction->block_size);
 		if (tdb->tdb1.transaction->old_map_size > blk * tdb->tdb1.transaction->block_size) {
 			tdb1_len_t len2 = tdb->tdb1.transaction->block_size;
 			if (len2 + (blk * tdb->tdb1.transaction->block_size) > tdb->tdb1.transaction->old_map_size) {
@@ -276,7 +281,7 @@ static int transaction1_write(struct tdb_context *tdb, tdb1_off_t off,
 			if (tdb->tdb1.transaction->io_methods->tdb1_read(tdb, blk * tdb->tdb1.transaction->block_size,
 								   tdb->tdb1.transaction->blocks[blk],
 								   len2, 0) != 0) {
-				SAFE_FREE(tdb->tdb1.transaction->blocks[blk]);
+				SAFE_FREE(tdb, tdb->tdb1.transaction->blocks[blk]);
 				tdb->last_error = TDB_ERR_IO;
 				goto fail;
 			}
@@ -474,11 +479,12 @@ static int _tdb1_transaction_start(struct tdb_context *tdb)
 	}
 
 	tdb->tdb1.transaction = (struct tdb1_transaction *)
-		calloc(sizeof(struct tdb1_transaction), 1);
+		tdb->alloc(tdb, sizeof(struct tdb1_transaction));
 	if (tdb->tdb1.transaction == NULL) {
 		tdb->last_error = TDB_ERR_OOM;
 		return -1;
 	}
+	memset(tdb->tdb1.transaction, 0, sizeof(*tdb->tdb1.transaction));
 
 	/* a page at a time seems like a reasonable compromise between compactness and efficiency */
 	tdb->tdb1.transaction->block_size = tdb->tdb1.page_size;
@@ -487,8 +493,8 @@ static int _tdb1_transaction_start(struct tdb_context *tdb)
 	   discussed with Volker, there are a number of ways we could
 	   make this async, which we will probably do in the future */
 	if (tdb1_transaction_lock(tdb, F_WRLCK, TDB_LOCK_WAIT) == -1) {
-		SAFE_FREE(tdb->tdb1.transaction->blocks);
-		SAFE_FREE(tdb->tdb1.transaction);
+		SAFE_FREE(tdb, tdb->tdb1.transaction->blocks);
+		SAFE_FREE(tdb, tdb->tdb1.transaction);
 		return -1;
 	}
 
@@ -506,11 +512,14 @@ static int _tdb1_transaction_start(struct tdb_context *tdb)
 	/* setup a copy of the hash table heads so the hash scan in
 	   traverse can be fast */
 	tdb->tdb1.transaction->hash_heads = (uint32_t *)
-		calloc(tdb->tdb1.header.hash_size+1, sizeof(uint32_t));
+		tdb->alloc(tdb->tdb1.transaction, 
+			   (tdb->tdb1.header.hash_size+1) * sizeof(uint32_t));
 	if (tdb->tdb1.transaction->hash_heads == NULL) {
 		tdb->last_error = TDB_ERR_OOM;
 		goto fail;
 	}
+	memset(tdb->tdb1.transaction->hash_heads, 0,
+	       (tdb->tdb1.header.hash_size+1) * sizeof(uint32_t));
 	if (tdb->tdb1.io->tdb1_read(tdb, TDB1_FREELIST_TOP, tdb->tdb1.transaction->hash_heads,
 				   TDB1_HASHTABLE_SIZE(tdb), 0) != 0) {
 		tdb_logerr(tdb, tdb->last_error, TDB_LOG_ERROR,
@@ -535,9 +544,9 @@ fail:
 	tdb1_allrecord_unlock(tdb, F_RDLCK);
 fail_allrecord_lock:
 	tdb1_transaction_unlock(tdb, F_WRLCK);
-	SAFE_FREE(tdb->tdb1.transaction->blocks);
-	SAFE_FREE(tdb->tdb1.transaction->hash_heads);
-	SAFE_FREE(tdb->tdb1.transaction);
+	SAFE_FREE(tdb, tdb->tdb1.transaction->blocks);
+	SAFE_FREE(tdb, tdb->tdb1.transaction->hash_heads);
+	SAFE_FREE(tdb, tdb->tdb1.transaction);
 	return -1;
 }
 
@@ -603,10 +612,10 @@ static int _tdb1_transaction_cancel(struct tdb_context *tdb)
 	/* free all the transaction blocks */
 	for (i=0;i<tdb->tdb1.transaction->num_blocks;i++) {
 		if (tdb->tdb1.transaction->blocks[i] != NULL) {
-			free(tdb->tdb1.transaction->blocks[i]);
+			tdb->free(tdb->tdb1.transaction->blocks[i]);
 		}
 	}
-	SAFE_FREE(tdb->tdb1.transaction->blocks);
+	SAFE_FREE(tdb, tdb->tdb1.transaction->blocks);
 
 	if (tdb->tdb1.transaction->magic_offset) {
 		const struct tdb1_methods *methods = tdb->tdb1.transaction->io_methods;
@@ -628,8 +637,8 @@ static int _tdb1_transaction_cancel(struct tdb_context *tdb)
 	/* restore the normal io methods */
 	tdb->tdb1.io = tdb->tdb1.transaction->io_methods;
 
-	SAFE_FREE(tdb->tdb1.transaction->hash_heads);
-	SAFE_FREE(tdb->tdb1.transaction);
+	SAFE_FREE(tdb, tdb->tdb1.transaction->hash_heads);
+	SAFE_FREE(tdb, tdb->tdb1.transaction);
 
 	return ret;
 }
@@ -811,7 +820,7 @@ static int transaction1_setup_recovery(struct tdb_context *tdb,
 		return -1;
 	}
 
-	data = (unsigned char *)malloc(recovery_size + sizeof(*rec));
+	data = (unsigned char *)tdb->alloc(tdb, recovery_size + sizeof(*rec));
 	if (data == NULL) {
 		tdb->last_error = TDB_ERR_OOM;
 		return -1;
@@ -850,7 +859,7 @@ static int transaction1_setup_recovery(struct tdb_context *tdb,
 			tdb->last_error = tdb_logerr(tdb, TDB_ERR_CORRUPT,
 						TDB_LOG_ERROR,
 						"tdb1_transaction_setup_recovery: transaction data over new region boundary");
-			free(data);
+			tdb->free(data);
 			return -1;
 		}
 		memcpy(p, &offset, 4);
@@ -862,7 +871,7 @@ static int transaction1_setup_recovery(struct tdb_context *tdb,
 		   new data, so we have to call the original tdb1_read
 		   method to get it */
 		if (methods->tdb1_read(tdb, offset, p + 8, length, 0) != 0) {
-			free(data);
+			tdb->free(data);
 			tdb->last_error = TDB_ERR_IO;
 			return -1;
 		}
@@ -881,14 +890,14 @@ static int transaction1_setup_recovery(struct tdb_context *tdb,
 		tdb_logerr(tdb, tdb->last_error, TDB_LOG_ERROR,
 			   "tdb1_transaction_setup_recovery:"
 			   " failed to write recovery data");
-		free(data);
+		tdb->free(data);
 		return -1;
 	}
 	if (transaction1_write_existing(tdb, recovery_offset, data, sizeof(*rec) + recovery_size) == -1) {
 		tdb_logerr(tdb, tdb->last_error, TDB_LOG_ERROR,
 			   "tdb1_transaction_setup_recovery: failed to write"
 			   " secondary recovery data");
-		free(data);
+		tdb->free(data);
 		return -1;
 	}
 
@@ -896,11 +905,11 @@ static int transaction1_setup_recovery(struct tdb_context *tdb,
 	   data before we update the magic to indicate that the recovery
 	   data is present */
 	if (transaction1_sync(tdb, recovery_offset, sizeof(*rec) + recovery_size) == -1) {
-		free(data);
+		tdb->free(data);
 		return -1;
 	}
 
-	free(data);
+	tdb->free(data);
 
 	magic = TDB1_RECOVERY_MAGIC;
 	TDB1_CONV(magic);
@@ -1138,7 +1147,7 @@ int tdb1_transaction_commit(struct tdb_context *tdb)
 				   "tdb1_transaction_commit: write failed");
 			return -1;
 		}
-		SAFE_FREE(tdb->tdb1.transaction->blocks[i]);
+		SAFE_FREE(tdb, tdb->tdb1.transaction->blocks[i]);
 	}
 
 	/* Do this before we drop lock or blocks. */
@@ -1146,7 +1155,7 @@ int tdb1_transaction_commit(struct tdb_context *tdb)
 		need_repack = repack_worthwhile(tdb);
 	}
 
-	SAFE_FREE(tdb->tdb1.transaction->blocks);
+	SAFE_FREE(tdb, tdb->tdb1.transaction->blocks);
 	tdb->tdb1.transaction->num_blocks = 0;
 
 	/* ensure the new data is on disk */
@@ -1231,7 +1240,7 @@ int tdb1_transaction_recover(struct tdb_context *tdb)
 
 	recovery_eof = rec.key_len;
 
-	data = (unsigned char *)malloc(rec.data_len);
+	data = (unsigned char *)tdb->alloc(tdb, rec.data_len);
 	if (data == NULL) {
 		tdb->last_error = tdb_logerr(tdb, TDB_ERR_OOM, TDB_LOG_ERROR,
 					"tdb1_transaction_recover:"
@@ -1259,7 +1268,7 @@ int tdb1_transaction_recover(struct tdb_context *tdb)
 		memcpy(&len, p+4, 4);
 
 		if (tdb->tdb1.io->tdb1_write(tdb, ofs, p+8, len) == -1) {
-			free(data);
+			tdb->free(data);
 			tdb_logerr(tdb, tdb->last_error, TDB_LOG_ERROR,
 				   "tdb1_transaction_recover: failed to recover"
 				   " %d bytes at offset %d", len, ofs);
@@ -1268,7 +1277,7 @@ int tdb1_transaction_recover(struct tdb_context *tdb)
 		p += 8 + len;
 	}
 
-	free(data);
+	tdb->free(data);
 
 	if (transaction1_sync(tdb, 0, tdb->file->map_size) == -1) {
 		tdb_logerr(tdb, tdb->last_error, TDB_LOG_ERROR,
diff --git a/lib/tdb2/tdb1_traverse.c b/lib/tdb2/tdb1_traverse.c
index d9d3649..4c2d692 100644
--- a/lib/tdb2/tdb1_traverse.c
+++ b/lib/tdb2/tdb1_traverse.c
@@ -191,7 +191,7 @@ static int tdb1_traverse_internal(struct tdb_context *tdb,
 		/* Drop chain lock, call out */
 		if (tdb1_unlock(tdb, tl->hash, tl->lock_rw) != 0) {
 			ret = -1;
-			SAFE_FREE(key.dptr);
+			SAFE_FREE(tdb, key.dptr);
 			goto out;
 		}
 		if (fn && fn(tdb, key, dbuf, private_data)) {
@@ -202,10 +202,10 @@ static int tdb1_traverse_internal(struct tdb_context *tdb,
 					   " unlock_record failed!");
 				ret = -1;
 			}
-			SAFE_FREE(key.dptr);
+			SAFE_FREE(tdb, key.dptr);
 			goto out;
 		}
-		SAFE_FREE(key.dptr);
+		SAFE_FREE(tdb, key.dptr);
 	}
 out:
 	tdb->tdb1.travlocks.next = tl->next;
@@ -324,17 +324,17 @@ TDB_DATA tdb1_nextkey(struct tdb_context *tdb, TDB_DATA oldkey)
 		    || memcmp(k, oldkey.dptr, oldkey.dsize) != 0) {
 			/* No, it wasn't: unlock it and start from scratch */
 			if (tdb1_unlock_record(tdb, tdb->tdb1.travlocks.off) != 0) {
-				SAFE_FREE(k);
+				SAFE_FREE(tdb, k);
 				return tdb1_null;
 			}
 			if (tdb1_unlock(tdb, tdb->tdb1.travlocks.hash, tdb->tdb1.travlocks.lock_rw) != 0) {
-				SAFE_FREE(k);
+				SAFE_FREE(tdb, k);
 				return tdb1_null;
 			}
 			tdb->tdb1.travlocks.off = 0;
 		}
 
-		SAFE_FREE(k);
+		SAFE_FREE(tdb, k);
 	}
 
 	if (!tdb->tdb1.travlocks.off) {
diff --git a/lib/tdb2/transaction.c b/lib/tdb2/transaction.c
index dd94510..a559f35 100644
--- a/lib/tdb2/transaction.c
+++ b/lib/tdb2/transaction.c
@@ -25,7 +25,7 @@
 */
 
 #include "private.h"
-#define SAFE_FREE(x) do { if ((x) != NULL) {free((void *)x); (x)=NULL;} } while(0)
+#define SAFE_FREE(tdb, x) do { if ((x) != NULL) {tdb->free((void *)x); (x)=NULL;} } while(0)
 
 /*
   transaction design:
@@ -223,10 +223,10 @@ static enum TDB_ERROR transaction_write(struct tdb_context *tdb, tdb_off_t off,
 		uint8_t **new_blocks;
 		/* expand the blocks array */
 		if (tdb->tdb2.transaction->blocks == NULL) {
-			new_blocks = (uint8_t **)malloc(
+			new_blocks = (uint8_t **)tdb->alloc(tdb,
 				(blk+1)*sizeof(uint8_t *));
 		} else {
-			new_blocks = (uint8_t **)realloc(
+			new_blocks = (uint8_t **)tdb->expand(
 				tdb->tdb2.transaction->blocks,
 				(blk+1)*sizeof(uint8_t *));
 		}
@@ -245,13 +245,15 @@ static enum TDB_ERROR transaction_write(struct tdb_context *tdb, tdb_off_t off,
 
 	/* allocate and fill a block? */
 	if (tdb->tdb2.transaction->blocks[blk] == NULL) {
-		tdb->tdb2.transaction->blocks[blk] = (uint8_t *)calloc(PAGESIZE, 1);
+		tdb->tdb2.transaction->blocks[blk] = (uint8_t *)
+			tdb->alloc(tdb->tdb2.transaction->blocks, PAGESIZE);
 		if (tdb->tdb2.transaction->blocks[blk] == NULL) {
 			ecode = tdb_logerr(tdb, TDB_ERR_OOM, TDB_LOG_ERROR,
 					   "transaction_write:"
 					   " failed to allocate");
 			goto fail;
 		}
+		memset(tdb->tdb2.transaction->blocks[blk], 0, PAGESIZE);
 		if (tdb->tdb2.transaction->old_map_size > blk * PAGESIZE) {
 			tdb_len_t len2 = PAGESIZE;
 			if (len2 + (blk * PAGESIZE) > tdb->tdb2.transaction->old_map_size) {
@@ -268,7 +270,7 @@ static enum TDB_ERROR transaction_write(struct tdb_context *tdb, tdb_off_t off,
 						   " failed to"
 						   " read old block: %s",
 						   strerror(errno));
-				SAFE_FREE(tdb->tdb2.transaction->blocks[blk]);
+				SAFE_FREE(tdb, tdb->tdb2.transaction->blocks[blk]);
 				goto fail;
 			}
 			if (blk == tdb->tdb2.transaction->num_blocks-1) {
@@ -479,7 +481,7 @@ static void _tdb_transaction_cancel(struct tdb_context *tdb)
 			free(tdb->tdb2.transaction->blocks[i]);
 		}
 	}
-	SAFE_FREE(tdb->tdb2.transaction->blocks);
+	SAFE_FREE(tdb, tdb->tdb2.transaction->blocks);
 
 	if (tdb->tdb2.transaction->magic_offset) {
 		const struct tdb_methods *methods = tdb->tdb2.transaction->io_methods;
@@ -510,7 +512,7 @@ static void _tdb_transaction_cancel(struct tdb_context *tdb)
 	if (tdb_has_open_lock(tdb))
 		tdb_unlock_open(tdb, F_WRLCK);
 
-	SAFE_FREE(tdb->tdb2.transaction);
+	SAFE_FREE(tdb, tdb->tdb2.transaction);
 }
 
 /*
@@ -574,21 +576,22 @@ enum TDB_ERROR tdb_transaction_start(struct tdb_context *tdb)
 	}
 
 	tdb->tdb2.transaction = (struct tdb_transaction *)
-		calloc(sizeof(struct tdb_transaction), 1);
+		tdb->alloc(tdb, sizeof(struct tdb_transaction));
 	if (tdb->tdb2.transaction == NULL) {
 		return tdb->last_error = tdb_logerr(tdb, TDB_ERR_OOM,
 						    TDB_LOG_ERROR,
 						    "tdb_transaction_start:"
 						    " cannot allocate");
 	}
+	memset(tdb->tdb2.transaction, 0, sizeof(*tdb->tdb2.transaction));
 
 	/* get the transaction write lock. This is a blocking lock. As
 	   discussed with Volker, there are a number of ways we could
 	   make this async, which we will probably do in the future */
 	ecode = tdb_transaction_lock(tdb, F_WRLCK);
 	if (ecode != TDB_SUCCESS) {
-		SAFE_FREE(tdb->tdb2.transaction->blocks);
-		SAFE_FREE(tdb->tdb2.transaction);
+		SAFE_FREE(tdb, tdb->tdb2.transaction->blocks);
+		SAFE_FREE(tdb, tdb->tdb2.transaction);
 		return tdb->last_error = ecode;
 	}
 
@@ -612,8 +615,8 @@ enum TDB_ERROR tdb_transaction_start(struct tdb_context *tdb)
 
 fail_allrecord_lock:
 	tdb_transaction_unlock(tdb, F_WRLCK);
-	SAFE_FREE(tdb->tdb2.transaction->blocks);
-	SAFE_FREE(tdb->tdb2.transaction);
+	SAFE_FREE(tdb, tdb->tdb2.transaction->blocks);
+	SAFE_FREE(tdb, tdb->tdb2.transaction);
 	return tdb->last_error = ecode;
 }
 
@@ -738,7 +741,7 @@ static struct tdb_recovery_record *alloc_recovery(struct tdb_context *tdb,
 	unsigned char *p;
 	const struct tdb_methods *old_methods = tdb->tdb2.io;
 
-	rec = malloc(sizeof(*rec) + tdb_recovery_size(tdb));
+	rec = tdb->alloc(tdb, sizeof(*rec) + tdb_recovery_size(tdb));
 	if (!rec) {
 		tdb_logerr(tdb, TDB_ERR_OOM, TDB_LOG_ERROR,
 			   "transaction_setup_recovery:"
@@ -820,7 +823,7 @@ static struct tdb_recovery_record *alloc_recovery(struct tdb_context *tdb,
 	return rec;
 
 fail:
-	free(rec);
+	tdb->free(rec);
 	tdb->tdb2.io = old_methods;
 	return TDB_ERR_PTR(ecode);
 }
@@ -1148,10 +1151,10 @@ enum TDB_ERROR tdb_transaction_commit(struct tdb_context *tdb)
 
 			return tdb->last_error = ecode;
 		}
-		SAFE_FREE(tdb->tdb2.transaction->blocks[i]);
+		SAFE_FREE(tdb, tdb->tdb2.transaction->blocks[i]);
 	}
 
-	SAFE_FREE(tdb->tdb2.transaction->blocks);
+	SAFE_FREE(tdb, tdb->tdb2.transaction->blocks);
 	tdb->tdb2.transaction->num_blocks = 0;
 
 	/* ensure the new data is on disk */
@@ -1231,7 +1234,7 @@ enum TDB_ERROR tdb_transaction_recover(struct tdb_context *tdb)
 
 	recovery_eof = rec.eof;
 
-	data = (unsigned char *)malloc(rec.len);
+	data = (unsigned char *)tdb->alloc(tdb, rec.len);
 	if (data == NULL) {
 		return tdb_logerr(tdb, TDB_ERR_OOM, TDB_LOG_ERROR,
 				  "tdb_transaction_recover:"


More information about the samba-technical mailing list