Skip to content

Commit 32f85cf

Browse files
committed
Prevent regex cache reuse when JIT flag does not match php.ini
1 parent 48f0b10 commit 32f85cf

File tree

2 files changed

+52
-4
lines changed

2 files changed

+52
-4
lines changed

ext/pcre/php_pcre.c

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@
3838

3939
#define PREG_JIT (1<<3)
4040

41+
#define PREG_JIT_ATTEMPTED (1<<4)
42+
4143
#define PCRE_CACHE_SIZE 4096
4244

4345
#ifdef HAVE_PCRE_JIT_SUPPORT
@@ -601,7 +603,12 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache_ex(zend_string *regex, in
601603
char *p, *pp;
602604
char *pattern;
603605
size_t pattern_len;
606+
#ifdef HAVE_PCRE_JIT_SUPPORT
607+
bool jit_enabled = PCRE_G(jit);
608+
uint32_t poptions = jit_enabled ? PREG_JIT_ATTEMPTED : 0;
609+
#else
604610
uint32_t poptions = 0;
611+
#endif
605612
const uint8_t *tables = NULL;
606613
zval *zv;
607614
pcre_cache_entry new_entry;
@@ -621,10 +628,19 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache_ex(zend_string *regex, in
621628
back the compiled pattern, otherwise go on and compile it. */
622629
zv = zend_hash_find(&PCRE_G(pcre_cache), key);
623630
if (zv) {
624-
if (key != regex) {
625-
zend_string_release_ex(key, 0);
631+
pcre_cache_entry *pce = (pcre_cache_entry*)Z_PTR_P(zv);
632+
#ifdef HAVE_PCRE_JIT_SUPPORT
633+
if ((bool)(pce->preg_options & PREG_JIT_ATTEMPTED) == jit_enabled) {
634+
#endif
635+
if (key != regex) {
636+
zend_string_release_ex(key, 0);
637+
}
638+
return pce;
639+
#ifdef HAVE_PCRE_JIT_SUPPORT
640+
} else {
641+
zend_hash_del(&PCRE_G(pcre_cache), key);
626642
}
627-
return (pcre_cache_entry*)Z_PTR_P(zv);
643+
#endif
628644
}
629645

630646
p = ZSTR_VAL(regex);
@@ -791,7 +807,7 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache_ex(zend_string *regex, in
791807
}
792808

793809
#ifdef HAVE_PCRE_JIT_SUPPORT
794-
if (PCRE_G(jit)) {
810+
if (jit_enabled) {
795811
/* Enable PCRE JIT compiler */
796812
rc = pcre2_jit_compile(re, PCRE2_JIT_COMPLETE);
797813
if (EXPECTED(rc >= 0)) {

ext/pcre/tests/gh11374.phpt

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
--TEST--
2+
GH-11374 PCRE cache entry must not be reused when PCRE JIT flag has changed
3+
--SKIPIF--
4+
<?php
5+
if (ini_get("pcre.jit") === false) {
6+
die("skip no jit built");
7+
}
8+
--FILE--
9+
<?php
10+
11+
// testing if PCRE cache entry was reused or not is not possible from userland, so instead we test
12+
// if PCRE JIT flag can be cleared and the pcre_match pass
13+
14+
foreach ([true, false, true] as $pcreJit) {
15+
ini_set('pcre.jit', $pcreJit ? '1' : '0');
16+
var_dump(ini_get('pcre.jit'));
17+
18+
var_dump(preg_match('/^a(b+)/', 'abbc', $matches));
19+
var_dump($matches === ['abb', 'bb']);
20+
}
21+
22+
?>
23+
--EXPECT--
24+
string(1) "1"
25+
int(1)
26+
bool(true)
27+
string(1) "0"
28+
int(1)
29+
bool(true)
30+
string(1) "1"
31+
int(1)
32+
bool(true)

0 commit comments

Comments
 (0)