Skip to content

Commit 66e66e6

Browse files
committed
Prevent regex cache reuse when JIT flag does not match php.ini
1 parent 4a77a1e commit 66e66e6

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
@@ -40,6 +40,8 @@
4040

4141
#define PREG_JIT (1<<3)
4242

43+
#define PREG_JIT_ATTEMPTED (1<<4)
44+
4345
#define PCRE_CACHE_SIZE 4096
4446

4547
#ifdef HAVE_PCRE_JIT_SUPPORT
@@ -603,7 +605,12 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache_ex(zend_string *regex, in
603605
char *p, *pp;
604606
char *pattern;
605607
size_t pattern_len;
608+
#ifdef HAVE_PCRE_JIT_SUPPORT
609+
bool jit_enabled = PCRE_G(jit);
610+
uint32_t poptions = jit_enabled ? PREG_JIT_ATTEMPTED : 0;
611+
#else
606612
uint32_t poptions = 0;
613+
#endif
607614
const uint8_t *tables = NULL;
608615
zval *zv;
609616
pcre_cache_entry new_entry;
@@ -623,10 +630,19 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache_ex(zend_string *regex, in
623630
back the compiled pattern, otherwise go on and compile it. */
624631
zv = zend_hash_find(&PCRE_G(pcre_cache), key);
625632
if (zv) {
626-
if (key != regex) {
627-
zend_string_release_ex(key, 0);
633+
pcre_cache_entry *pce = (pcre_cache_entry*)Z_PTR_P(zv);
634+
#ifdef HAVE_PCRE_JIT_SUPPORT
635+
if ((bool)(pce->preg_options & PREG_JIT_ATTEMPTED) == jit_enabled) {
636+
#endif
637+
if (key != regex) {
638+
zend_string_release_ex(key, 0);
639+
}
640+
return pce;
641+
#ifdef HAVE_PCRE_JIT_SUPPORT
642+
} else {
643+
zend_hash_del(&PCRE_G(pcre_cache), key);
628644
}
629-
return (pcre_cache_entry*)Z_PTR_P(zv);
645+
#endif
630646
}
631647

632648
p = ZSTR_VAL(regex);
@@ -805,7 +821,7 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache_ex(zend_string *regex, in
805821
}
806822

807823
#ifdef HAVE_PCRE_JIT_SUPPORT
808-
if (PCRE_G(jit)) {
824+
if (jit_enabled) {
809825
/* Enable PCRE JIT compiler */
810826
rc = pcre2_jit_compile(re, PCRE2_JIT_COMPLETE);
811827
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)