Skip to content

Prevent regex cache reuse when JIT flag does not match php.ini #11545

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 21 additions & 4 deletions ext/pcre/php_pcre.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@

#define PREG_JIT (1<<3)

#define PREG_JIT_ATTEMPTED (1<<4)

#define PCRE_CACHE_SIZE 4096

#ifdef HAVE_PCRE_JIT_SUPPORT
Expand Down Expand Up @@ -601,7 +603,12 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache_ex(zend_string *regex, in
char *p, *pp;
char *pattern;
size_t pattern_len;
#ifdef HAVE_PCRE_JIT_SUPPORT
bool jit_enabled = PCRE_G(jit);
uint32_t poptions = jit_enabled ? PREG_JIT_ATTEMPTED : 0;
#else
uint32_t poptions = 0;
#endif
const uint8_t *tables = NULL;
zval *zv;
pcre_cache_entry new_entry;
Expand All @@ -621,10 +628,20 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache_ex(zend_string *regex, in
back the compiled pattern, otherwise go on and compile it. */
zv = zend_hash_find(&PCRE_G(pcre_cache), key);
if (zv) {
if (key != regex) {
zend_string_release_ex(key, 0);
pcre_cache_entry *pce = (pcre_cache_entry*)Z_PTR_P(zv);
#ifdef HAVE_PCRE_JIT_SUPPORT
bool recompile = (bool)(pce->preg_options & PREG_JIT_ATTEMPTED) != jit_enabled;
#else
bool recompile = false;
#endif
if (recompile) {
zend_hash_del(&PCRE_G(pcre_cache), key);
} else {
if (key != regex) {
zend_string_release_ex(key, 0);
}
return pce;
}
return (pcre_cache_entry*)Z_PTR_P(zv);
}

p = ZSTR_VAL(regex);
Expand Down Expand Up @@ -791,7 +808,7 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache_ex(zend_string *regex, in
}

#ifdef HAVE_PCRE_JIT_SUPPORT
if (PCRE_G(jit)) {
if (jit_enabled) {
/* Enable PCRE JIT compiler */
rc = pcre2_jit_compile(re, PCRE2_JIT_COMPLETE);
if (EXPECTED(rc >= 0)) {
Expand Down
32 changes: 32 additions & 0 deletions ext/pcre/tests/gh11374.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
--TEST--
GH-11374 PCRE cache entry must not be reused when PCRE JIT flag has changed
--SKIPIF--
<?php
if (ini_get("pcre.jit") === false) {
die("skip no jit built");
}
--FILE--
<?php

// testing if PCRE cache entry was reused or not is not possible from userland, so instead we test
// if PCRE JIT flag can be cleared and the pcre_match pass

foreach ([true, false, true] as $pcreJit) {
ini_set('pcre.jit', $pcreJit ? '1' : '0');
var_dump(ini_get('pcre.jit'));

var_dump(preg_match('/^a(b+)/', 'abbc', $matches));
var_dump($matches === ['abb', 'bb']);
}

?>
--EXPECT--
string(1) "1"
int(1)
bool(true)
string(1) "0"
int(1)
bool(true)
string(1) "1"
int(1)
bool(true)