diff options
author | Patrick Steinhardt <ps@pks.im> | 2018-02-28 12:06:59 +0000 |
---|---|---|
committer | Patrick Steinhardt <ps@pks.im> | 2018-03-10 17:45:25 +0000 |
commit | b35c30986c033408bc0e089b7b944f303b34815a (patch) | |
tree | cf8f1a1282422ea29c51d54f3d2ec963f087d271 | |
parent | 9e98f49d4bcad82d73d775e237397fdb30b5e3d5 (diff) | |
download | libgit2-b35c30986c033408bc0e089b7b944f303b34815a.tar.gz |
curl: explicitly initialize and cleanup global curl state
Our curl-based streams make use of the easy curl interface. This
interface automatically initializes and de-initializes the global curl
state by calling out to `curl_global_init` and `curl_global_cleanup`.
Thus, all global state will be repeatedly re-initialized when creating
multiple curl streams in succession. Despite being inefficient, this is
not thread-safe due to `curl_global_init` being not thread-safe itself.
Thus a multi-threaded programing handling multiple curl streams at the
same time is inherently racy.
Fix the issue by globally initializing and cleaning up curl's state.
-rw-r--r-- | src/curl_stream.c | 18 | ||||
-rw-r--r-- | src/curl_stream.h | 1 | ||||
-rw-r--r-- | src/global.c | 6 |
3 files changed, 23 insertions, 2 deletions
diff --git a/src/curl_stream.c b/src/curl_stream.c index ac0f95a88..f07370f21 100644 --- a/src/curl_stream.c +++ b/src/curl_stream.c @@ -12,6 +12,7 @@ #include "stream.h" #include "git2/transport.h" #include "buffer.h" +#include "global.h" #include "vector.h" #include "proxy.h" @@ -36,6 +37,18 @@ typedef struct { git_cred *proxy_cred; } curl_stream; +int git_curl_stream_global_init(void) +{ + if (curl_global_init(CURL_GLOBAL_ALL) != 0) { + giterr_set(GITERR_NET, "could not initialize curl"); + return -1; + } + + /* `curl_global_cleanup` is provided by libcurl */ + git__on_shutdown(curl_global_cleanup); + return 0; +} + static int seterr_curl(curl_stream *s) { giterr_set(GITERR_NET, "curl error: %s\n", s->curl_error); @@ -351,6 +364,11 @@ int git_curl_stream_new(git_stream **out, const char *host, const char *port) #include "stream.h" +int git_curl_stream_global_init(void) +{ + return 0; +} + int git_curl_stream_new(git_stream **out, const char *host, const char *port) { GIT_UNUSED(out); diff --git a/src/curl_stream.h b/src/curl_stream.h index 283f0fe40..6f192c591 100644 --- a/src/curl_stream.h +++ b/src/curl_stream.h @@ -9,6 +9,7 @@ #include "git2/sys/stream.h" +extern int git_curl_stream_global_init(void); extern int git_curl_stream_new(git_stream **out, const char *host, const char *port); #endif diff --git a/src/global.c b/src/global.c index afa57e1d6..0b347a3e2 100644 --- a/src/global.c +++ b/src/global.c @@ -10,6 +10,7 @@ #include "sysdir.h" #include "filter.h" #include "merge_driver.h" +#include "curl_stream.h" #include "openssl_stream.h" #include "thread-utils.h" #include "git2/global.h" @@ -22,7 +23,7 @@ git_mutex git__mwindow_mutex; -#define MAX_SHUTDOWN_CB 9 +#define MAX_SHUTDOWN_CB 10 static git_global_shutdown_fn git__shutdown_callbacks[MAX_SHUTDOWN_CB]; static git_atomic git__n_shutdown_callbacks; @@ -62,7 +63,8 @@ static int init_common(void) (ret = git_filter_global_init()) == 0 && (ret = git_merge_driver_global_init()) == 0 && (ret = git_transport_ssh_global_init()) == 0 && - (ret = git_openssl_stream_global_init()) == 0) + (ret = git_openssl_stream_global_init()) == 0 && + (ret = git_curl_stream_global_init()) == 0) ret = git_mwindow_global_init(); GIT_MEMORY_BARRIER; |