Commit d3b29fb94bf1c1d0caec39b4a2c3d2061c63efec

Arthur Schreiber 2015-10-01T00:50:37

refdb and odb backends must provide `free` function As refdb and odb backends can be allocated by client code, libgit2 can’t know whether an alternative memory allocator was used, and thus should not try to call `git__free` on those objects. Instead, odb and refdb backend implementations must always provide their own `free` functions to ensure memory gets freed correctly.

diff --git a/include/git2/sys/odb_backend.h b/include/git2/sys/odb_backend.h
index fe102ff..e423a92 100644
--- a/include/git2/sys/odb_backend.h
+++ b/include/git2/sys/odb_backend.h
@@ -83,6 +83,10 @@ struct git_odb_backend {
 		git_odb_writepack **, git_odb_backend *, git_odb *odb,
 		git_transfer_progress_cb progress_cb, void *progress_payload);
 
+	/**
+	 * Frees any resources held by the odb (including the `git_odb_backend`
+	 * itself). An odb backend implementation must provide this function.
+	 */
 	void (* free)(git_odb_backend *);
 };
 
diff --git a/include/git2/sys/refdb_backend.h b/include/git2/sys/refdb_backend.h
index 01fce80..5129ad8 100644
--- a/include/git2/sys/refdb_backend.h
+++ b/include/git2/sys/refdb_backend.h
@@ -130,8 +130,8 @@ struct git_refdb_backend {
 	int (*ensure_log)(git_refdb_backend *backend, const char *refname);
 
 	/**
-	 * Frees any resources held by the refdb.  A refdb implementation may
-	 * provide this function; if it is not provided, nothing will be done.
+	 * Frees any resources held by the refdb (including the `git_refdb_backend`
+	 * itself). A refdb backend implementation must provide this function.
 	 */
 	void (*free)(git_refdb_backend *backend);
 
diff --git a/src/odb.c b/src/odb.c
index b2d6351..2b2c35f 100644
--- a/src/odb.c
+++ b/src/odb.c
@@ -600,8 +600,7 @@ static void odb_free(git_odb *db)
 		backend_internal *internal = git_vector_get(&db->backends, i);
 		git_odb_backend *backend = internal->backend;
 
-		if (backend->free) backend->free(backend);
-		else git__free(backend);
+		backend->free(backend);
 
 		git__free(internal);
 	}
diff --git a/src/refdb.c b/src/refdb.c
index 16fb519..debba12 100644
--- a/src/refdb.c
+++ b/src/refdb.c
@@ -61,12 +61,8 @@ int git_refdb_open(git_refdb **out, git_repository *repo)
 
 static void refdb_free_backend(git_refdb *db)
 {
-	if (db->backend) {
-		if (db->backend->free)
-			db->backend->free(db->backend);
-		else
-			git__free(db->backend);
-	}
+	if (db->backend)
+		db->backend->free(db->backend);
 }
 
 int git_refdb_set_backend(git_refdb *db, git_refdb_backend *backend)
diff --git a/tests/odb/sorting.c b/tests/odb/sorting.c
index 147a160..d24c49c 100644
--- a/tests/odb/sorting.c
+++ b/tests/odb/sorting.c
@@ -14,6 +14,7 @@ static git_odb_backend *new_backend(size_t position)
 	if (b == NULL)
 		return NULL;
 
+	b->base.free = (void (*)(git_odb_backend *)) git__free;
 	b->base.version = GIT_ODB_BACKEND_VERSION;
 	b->position = position;
 	return (git_odb_backend *)b;