Commit b46c35943a201a6e9be606215327c7da9d4f53c9

Patrick Steinhardt 2019-01-02T09:33:55

global: move init callbacks into an array We currently have an explicit callchain of all the initialization callbacks in our `init_common` function. This is perfectly fine, but requires us to manually keep track of how many shutdown callbacks there may be installed: to avoid allocations before libgit2 is fully initialized, we assume that every initializer may register at most one shutdown function. These shutdown functions are stored in a static array of size `MAX_SHUTDOWN_CB`, which then needs to be updated manually whenever a new initializer function is being added. The situation can be easily fixed: convert the callchain of init functions into an array and iterate over it to initialize all subsystems. This allows us to define the `git__shutdown_callbacks` array with the same size as the initializer array and rids us of the need to always update `MAX_SHUTDOWN_CB`.

diff --git a/src/global.c b/src/global.c
index 86a35a2..418c036 100644
--- a/src/global.c
+++ b/src/global.c
@@ -26,9 +26,23 @@
 
 git_mutex git__mwindow_mutex;
 
-#define MAX_SHUTDOWN_CB 10
+typedef int (*git_global_init_fn)(void);
+
+static git_global_init_fn git__init_callbacks[] = {
+	git_allocator_global_init,
+	git_hash_global_init,
+	git_sysdir_global_init,
+	git_filter_global_init,
+	git_merge_driver_global_init,
+	git_transport_ssh_global_init,
+	git_stream_registry_global_init,
+	git_openssl_stream_global_init,
+	git_mbedtls_stream_global_init,
+	git_mwindow_global_init
+};
+
+static git_global_shutdown_fn git__shutdown_callbacks[ARRAY_SIZE(git__init_callbacks)];
 
-static git_global_shutdown_fn git__shutdown_callbacks[MAX_SHUTDOWN_CB];
 static git_atomic git__n_shutdown_callbacks;
 static git_atomic git__n_inits;
 char *git__user_agent;
@@ -37,7 +51,7 @@ char *git__ssl_ciphers;
 void git__on_shutdown(git_global_shutdown_fn callback)
 {
 	int count = git_atomic_inc(&git__n_shutdown_callbacks);
-	assert(count <= MAX_SHUTDOWN_CB && count > 0);
+	assert(count <= (int) ARRAY_SIZE(git__shutdown_callbacks) && count > 0);
 	git__shutdown_callbacks[count - 1] = callback;
 }
 
@@ -52,6 +66,7 @@ static void git__global_state_cleanup(git_global_st *st)
 
 static int init_common(void)
 {
+	size_t i;
 	int ret;
 
 	/* Initialize the CRT debug allocator first, before our first malloc */
@@ -60,17 +75,10 @@ static int init_common(void)
 	git_win32__stack_init();
 #endif
 
-	/* Initialize any other subsystems that have global state */
-	if ((ret = git_allocator_global_init()) == 0 &&
-		(ret = git_hash_global_init()) == 0 &&
-		(ret = git_sysdir_global_init()) == 0 &&
-		(ret = git_filter_global_init()) == 0 &&
-		(ret = git_merge_driver_global_init()) == 0 &&
-		(ret = git_transport_ssh_global_init()) == 0 &&
-		(ret = git_stream_registry_global_init()) == 0 &&
-		(ret = git_openssl_stream_global_init()) == 0 &&
-		(ret = git_mbedtls_stream_global_init()) == 0)
-		ret = git_mwindow_global_init();
+	/* Initialize subsystems that have global state */
+	for (i = 0; i < ARRAY_SIZE(git__init_callbacks); i++)
+		if ((ret = git__init_callbacks[i]()) != 0)
+			break;
 
 	GIT_MEMORY_BARRIER;