BUG/MEDIUM: regex: initialize the match array earlier during boot
Some checks are pending
Contrib / admin/halog/ (push) Waiting to run
Contrib / dev/flags/ (push) Waiting to run
Contrib / dev/haring/ (push) Waiting to run
Contrib / dev/hpack/ (push) Waiting to run
Contrib / dev/poll/ (push) Waiting to run
FreeBSD / clang (push) Waiting to run
VTest / Generate Build Matrix (push) Waiting to run
VTest / (push) Blocked by required conditions
Windows / Windows, gcc, all features (push) Waiting to run

As reported by @zhanhb in github issue #3410, since 3.3 with commit
fda6dc959 ("MINOR: regex: use a thread-local match pointer for pcre2"),
the local_pcre2_match array is initialized too late for use by Lua. If
a lua-load makes use of regex, it may segfault (actually using PCRE2
is fine but PCRE2_JIT will crash):

Let's change the init sequence so that the first thread's context is
initialized early at boot and other threads are initialized when they
are created. For lua-load-per-thread, all extra threads will run on
the first thread's temporary storage during init but that's not a
problem since the sole purpose is to avoid concurrent accesses.

Thanks to @zhanbb for the detailed report and quick tests. This needs
to be backported to 3.3.
This commit is contained in:
Willy Tarreau 2026-06-07 07:03:06 +02:00
parent 1e00743520
commit ac776e3819

View file

@ -442,7 +442,7 @@ static void regex_register_build_options(void)
INITCALL0(STG_REGISTER, regex_register_build_options);
#ifdef USE_PCRE2
static int init_pcre2_per_thread(void)
static int init_pcre2_one_thread(void)
{
local_pcre2_match = pcre2_match_data_create(MAX_MATCH, NULL);
if (!local_pcre2_match) {
@ -452,13 +452,32 @@ static int init_pcre2_per_thread(void)
return 1;
}
/* per-thread init for the next threads (first one already done) */
static int init_pcre2_per_thread(void)
{
if (!tid)
return 1;
return init_pcre2_one_thread();
}
/* per-thread deinit for the next threads */
static void deinit_pcre2_per_thread(void)
{
if (tid)
pcre2_match_data_free(local_pcre2_match);
}
/* late deinit for the first thread */
static void deinit_pcre2_first_thread(void)
{
pcre2_match_data_free(local_pcre2_match);
}
/* early init for the first thread */
INITCALL0(STG_INIT, init_pcre2_one_thread);
REGISTER_PER_THREAD_INIT(init_pcre2_per_thread);
REGISTER_PER_THREAD_DEINIT(deinit_pcre2_per_thread);
REGISTER_POST_DEINIT(deinit_pcre2_first_thread);
#endif
/*