]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MEDIUM: regex: initialize the match array earlier during boot
authorWilly Tarreau <w@1wt.eu>
Sun, 7 Jun 2026 05:03:06 +0000 (07:03 +0200)
committerWilly Tarreau <w@1wt.eu>
Sun, 7 Jun 2026 05:46:32 +0000 (07:46 +0200)
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.

src/regex.c

index 0f192f725a816fa3476302c9102a8d53278956d6..3e1348e2e7b2f6eea89bf9d8b0937af0e42b42fb 100644 (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
 
 /*