Skip to content

Commit 77e72f5

Browse files
committed
Prevent regex cache reuse when JIT flag does not match php.ini
1 parent 0d922aa commit 77e72f5

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
@@ -41,6 +41,8 @@
4141

4242
#define PREG_JIT (1<<3)
4343

44+
#define PREG_JIT_ATTEMPTED (1<<4)
45+
4446
#define PCRE_CACHE_SIZE 4096
4547

4648
struct _pcre_cache_entry {
@@ -618,7 +620,12 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache_ex(zend_string *regex, in
618620
char *p, *pp;
619621
char *pattern;
620622
size_t pattern_len;
623+
#ifdef HAVE_PCRE_JIT_SUPPORT
624+
bool jit_enabled = PCRE_G(jit);
625+
uint32_t poptions = jit_enabled ? PREG_JIT_ATTEMPTED : 0;
626+
#else
621627
uint32_t poptions = 0;
628+
#endif
622629
const uint8_t *tables = NULL;
623630
zval *zv;
624631
pcre_cache_entry new_entry;
@@ -638,10 +645,19 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache_ex(zend_string *regex, in
638645
back the compiled pattern, otherwise go on and compile it. */
639646
zv = zend_hash_find(&PCRE_G(pcre_cache), key);
640647
if (zv) {
641-
if (key != regex) {
642-
zend_string_release_ex(key, 0);
648+
pcre_cache_entry *pce = (pcre_cache_entry*)Z_PTR_P(zv);
649+
#ifdef HAVE_PCRE_JIT_SUPPORT
650+
if ((bool)(pce->preg_options & PREG_JIT_ATTEMPTED) == jit_enabled) {
651+
#endif
652+
if (key != regex) {
653+
zend_string_release_ex(key, 0);
654+
}
655+
return pce;
656+
#ifdef HAVE_PCRE_JIT_SUPPORT
657+
} else {
658+
zend_hash_del(&PCRE_G(pcre_cache), key);
643659
}
644-
return (pcre_cache_entry*)Z_PTR_P(zv);
660+
#endif
645661
}
646662

647663
p = ZSTR_VAL(regex);
@@ -821,7 +837,7 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache_ex(zend_string *regex, in
821837
}
822838

823839
#ifdef HAVE_PCRE_JIT_SUPPORT
824-
if (PCRE_G(jit)) {
840+
if (jit_enabled) {
825841
/* Enable PCRE JIT compiler */
826842
rc = pcre2_jit_compile(re, PCRE2_JIT_COMPLETE);
827843
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)