Skip to content

fix(http): initialize libcurl global state once at startup#33

Open
ratazzi wants to merge 1 commit into
masterfrom
fix/curl-global-init
Open

fix(http): initialize libcurl global state once at startup#33
ratazzi wants to merge 1 commit into
masterfrom
fix/curl-global-init

Conversation

@ratazzi

@ratazzi ratazzi commented Jul 16, 2026

Copy link
Copy Markdown
Owner

Problem

Two related issues with libcurl global state:

  1. The main HTTP client never called curl_global_init(), relying on curl_easy_init()'s lazy fallback, which is documented as not thread-safe. The download manager spawns worker threads that each create easy handles, so when the first curl call of the process happened inside those workers (e.g. a provision consisting only of remote_file resources), multiple threads could race the global initialization, including OpenSSL setup.

  2. KMSClient called curl_global_init in init and curl_global_cleanup in deinit. The pair is neither reference-counted nor thread-safe, so destroying one client while any other transfer was in flight tore down shared global state under it.

Fix

  • Call curl_global_init(CURL_GLOBAL_ALL) once in main while the process is still single-threaded, paired with curl_global_cleanup on exit.
  • Add the CURL_GLOBAL_ALL constant to curl.zig (replacing the magic 0x03).
  • Drop the per-instance init/cleanup from KMSClient.

Testing

  • zig build test passes; hola --version and a provision run with the HTTP stack work as before.
  • Debug-build cold start unaffected (~29ms including the new init).

curl_easy_init() falls back to lazy curl_global_init(), which is
documented as not thread-safe. The download manager spawns worker
threads that each create easy handles, so when the first curl call of
the process happened inside those workers (e.g. a provision consisting
only of remote_file resources), several threads could race the global
initialization, including OpenSSL setup.

Additionally, KMSClient called curl_global_init in init and
curl_global_cleanup in deinit. The pair is neither reference-counted
nor thread-safe, so destroying one client while any other transfer was
in flight tore down shared global state.

Call curl_global_init(CURL_GLOBAL_ALL) once in main while the process
is still single-threaded, pair it with curl_global_cleanup on exit, and
drop the per-instance init/cleanup from KMSClient.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant