Skip to content

Commit 0933fdc

Browse files
committed
global: adjust init count under lock
Our global initialization functions `git_libgit2_init()` and `git_libgit2_shutdown()` both adjust a global init counter to determine whether we are the first respectively last user of libgit2. On Unix-systems do not do so under lock, though, which opens the possibility of a race between these two functions: Thread 1 Thread 2 git__n_inits = 0; git_libgit2_init(); git_atomic_inc(&git__n_inits); /* git__n_inits == 1 */ git_libgit2_shutdown(); if (git_atomic_dec(&git__n_inits) != 0) /* git__n_inits == 0, no early exit here */ pthread_mutex_lock(&_init_mutex); shutdown_common(); pthread_mutex_unlock(&_init_mutex); pthread_mutex_lock(&_init_mutex); init_once(); pthread_mutex_unlock(&_init_mutex); So we can end up in a situation where we try to shutdown shared data structures before they have been initialized. Fix the race by always locking `_init_mutex` before incrementing or decrementing `git__n_inits`.
1 parent 0fd0bfe commit 0933fdc

File tree

1 file changed

+11
-10
lines changed

1 file changed

+11
-10
lines changed

src/global.c

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -272,10 +272,10 @@ int git_libgit2_init(void)
272272
{
273273
int ret, err;
274274

275-
ret = git_atomic_inc(&git__n_inits);
276-
277275
if ((err = pthread_mutex_lock(&_init_mutex)) != 0)
278276
return err;
277+
278+
ret = git_atomic_inc(&git__n_inits);
279279
err = pthread_once(&_once_init, init_once);
280280
err |= pthread_mutex_unlock(&_init_mutex);
281281

@@ -289,13 +289,13 @@ int git_libgit2_shutdown(void)
289289
{
290290
void *ptr = NULL;
291291
pthread_once_t new_once = PTHREAD_ONCE_INIT;
292-
int ret;
292+
int error, ret;
293293

294-
if ((ret = git_atomic_dec(&git__n_inits)) != 0)
295-
return ret;
294+
if ((error = pthread_mutex_lock(&_init_mutex)) != 0)
295+
return error;
296296

297-
if ((ret = pthread_mutex_lock(&_init_mutex)) != 0)
298-
return ret;
297+
if ((ret = git_atomic_dec(&git__n_inits)) != 0)
298+
goto out;
299299

300300
/* Shut down any subsystems that have global state */
301301
shutdown_common();
@@ -310,10 +310,11 @@ int git_libgit2_shutdown(void)
310310
git_mutex_free(&git__mwindow_mutex);
311311
_once_init = new_once;
312312

313-
if ((ret = pthread_mutex_unlock(&_init_mutex)) != 0)
314-
return ret;
313+
out:
314+
if ((error = pthread_mutex_unlock(&_init_mutex)) != 0)
315+
return error;
315316

316-
return 0;
317+
return ret;
317318
}
318319

319320
git_global_st *git__global_state(void)

0 commit comments

Comments
 (0)