Skip to content

Fix data race in CPU-feature global, not just the dispatch pointers - #5

Open
alexey-milovidov wants to merge 1 commit into
v1.25-basefrom
thread-safe-cpu-features-global
Open

Fix data race in CPU-feature global, not just the dispatch pointers#5
alexey-milovidov wants to merge 1 commit into
v1.25-basefrom
thread-safe-cpu-features-global

Conversation

@alexey-milovidov

Copy link
Copy Markdown
Member

Follow-up to #4. That PR made the per-codec dispatch function pointers atomic, but each dispatcher still calls get_x86_cpu_features / get_arm_cpu_features, which lazily initialize the global libdeflate_x86_cpu_features / libdeflate_arm_cpu_features bitmask on the first call. That global was only volatile, so a plain load racing with the store in libdeflate_init_*_cpu_features is undefined behavior and was still flagged by ThreadSanitizer:

WARNING: ThreadSanitizer: data race
  Write ... libdeflate_init_x86_cpu_features cpu_features.c:210
  Read  ... get_x86_cpu_features cpu_features.h:62
  Location is global 'libdeflate_x86_cpu_features'

It reproduced as a "Server died" failure in ClickHouse when two HTTP connections first compressed a gzip response concurrently under TSan (ClickHouse/ClickHouse#108074).

Access the global with relaxed __atomic_load_n / __atomic_store_n, matching the dispatch-pointer fix. Both x86 and ARM. All bundled tests pass.

🤖 Generated with Claude Code

The previous fix (PR #4) made the per-codec dispatch function pointers
(crc32_impl, adler32_impl, ...) atomic, but each dispatcher still calls
get_x86_cpu_features() / get_arm_cpu_features(), which lazily initialize the
global libdeflate_x86_cpu_features / libdeflate_arm_cpu_features bitmask on
the first call. That global was only 'volatile', so a plain load racing with
the store in libdeflate_init_*_cpu_features() is undefined behavior and was
still flagged by ThreadSanitizer:

  WARNING: ThreadSanitizer: data race
    Write ... libdeflate_init_x86_cpu_features cpu_features.c
    Read  ... get_x86_cpu_features cpu_features.h
    Location is global 'libdeflate_x86_cpu_features'

This reproduced as a "Server died" failure when two HTTP connections first
compressed a gzip response concurrently under TSan.

Access the global with relaxed __atomic_load_n / __atomic_store_n, matching
the dispatch-pointer fix. The first-call initialization is a benign race
(every thread computes the same bitmask, a pure function of the CPU), and
relaxed ordering suffices because no other memory is published through it.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
alexey-milovidov added a commit to ClickHouse/ClickHouse that referenced this pull request Jun 30, 2026
The previous bump (cb6b5c9) made the per-codec dispatch function pointers
(`crc32_impl`, `adler32_impl`, ...) atomic, but each dispatcher still calls
`get_x86_cpu_features` / `get_arm_cpu_features`, which lazily initialize the
global `libdeflate_x86_cpu_features` / `libdeflate_arm_cpu_features` bitmask on
the first call. That global was only `volatile`, so a plain load racing with
the store in `libdeflate_init_*_cpu_features` is still undefined behavior and
was flagged by ThreadSanitizer:

    WARNING: ThreadSanitizer: data race
      Write ... libdeflate_init_x86_cpu_features cpu_features.c:210
      Read  ... get_x86_cpu_features cpu_features.h:62
      Location is global 'libdeflate_x86_cpu_features'

It reproduced as a "Server died" failure under TSan when two HTTP connections
first compressed a gzip error response concurrently (e.g.
`test_profile_max_sessions_for_user` on the amd_tsan integration shard).

The global is now accessed with relaxed `__atomic_load_n` / `__atomic_store_n`,
matching the dispatch-pointer fix. Fork commit:
ClickHouse/libdeflate@ec0718b
Related: ClickHouse/libdeflate#5

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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