Description
A data race is detected by ThreadSanitizer (TSan) when multiple threads concurrently invoke pcre2_jit_stack_create_8 for the first time in a process.
While the documentation states that JIT stacks are thread-safe when allocated per-thread, the underlying sljit allocator performs lazy initialization of global/static variables without thread synchronization primitives, leading to Undefined Behavior.
Root Cause
In src/deps/sljit/sljit_src/sljitUtils.c, the function get_page_alignment() initializes a static variable sljit_page_align on its very first call:
static SLJIT_INLINE sljit_uw get_page_alignment(void) {
static sljit_uw sljit_page_align = 0;
sljit_sw align;
if (!sljit_page_align) {
#ifdef _SC_PAGESIZE
align = sysconf(_SC_PAGESIZE);
#else
align = getpagesize();
#endif
/* Should never happen. */
if (align < 0)
align = 4096;
sljit_page_align = (sljit_uw)align - 1;
}
return sljit_page_align;
}
If multiple threads concurrently call pcre2_jit_stack_create_8 before page_alignment is initialized, they all enter this block and simultaneously write to the same memory address without a mutex or an atomic store. According to the C11/C++11 memory model, this constitutes a data race.
TSan Stack Trace
Read of size 8 at 0x7fea95cf07a0 by thread T39:
#0 get_page_alignment pcre2/src/deps/sljit/sljit_src/sljitUtils.c:153
#1 sljit_allocate_stack pcre2/src/deps/sljit/sljit_src/sljitUtils.c:255
#2 pcre2_jit_stack_create_8 pcre2/src/pcre2_jit_misc.c:149
Environment
- PCRE2 Version: 10.46 (and likely reproducible in newer versions as well)
- Compiler/Toolchain: GCC 13.2.0 / Clang with
-fsanitize=thread
- OS: Linux x86_64
Description
A data race is detected by ThreadSanitizer (TSan) when multiple threads concurrently invoke
pcre2_jit_stack_create_8for the first time in a process.While the documentation states that JIT stacks are thread-safe when allocated per-thread, the underlying
sljitallocator performs lazy initialization of global/static variables without thread synchronization primitives, leading to Undefined Behavior.Root Cause
In
src/deps/sljit/sljit_src/sljitUtils.c, the functionget_page_alignment()initializes a static variablesljit_page_alignon its very first call:If multiple threads concurrently call
pcre2_jit_stack_create_8beforepage_alignmentis initialized, they all enter this block and simultaneously write to the same memory address without a mutex or an atomic store. According to the C11/C++11 memory model, this constitutes a data race.TSan Stack Trace
Environment
-fsanitize=thread