You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Different preg_match result with -d pcre.jit=0 #11374
is there any easy workaround until php-src/PCRE is fixed?
Sure: turn on JIT 😉
Otherwise, maybe? You could experiment with the regex - add/remove optimizations, that sort of thing - to see if you can trigger some different internal code paths to bypass wherever the bug is. It'd be easier to do that if you could narrow down the source of the problem first, of course.
And there's always the option of breaking it down into smaller regexes... I mean really, that's 100+ lines of (formatted) regex in there. May or may not help, but it might be a nice gain regardless.
In my case there's PCRE JIT Support => not compiled in so I can't enable it (asdf's PHP on M1 Mac). I can workaround it with Docker setup, but I just wanted to point that it's not always possible to use PCRE JIT.
@mvorisek As you have probably seen I had to revert the last PR due to bit performance implications. I also closed #11511 for the same reason. The performance drop is smaller but still more than I'd expect. The alternative approach would be to clear the cache, but that would require at least an e-mail to the mailing list. I don't think it's worth it, given this is an edge case and should be fixed in PCRE. If you'd like to start this discussion, please send a mail to the internals list. Here's a patch:
diff --git a/ext/pcre/php_pcre.c b/ext/pcre/php_pcre.c
index 6249a80..c381706 100644
--- a/ext/pcre/php_pcre.c+++ b/ext/pcre/php_pcre.c@@ -638,10 +638,15 @@ 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);+ if (!(pce->preg_options & PREG_JIT) == !PCRE_G(jit)) {+ if (key != regex) {+ zend_string_release_ex(key, 0);+ }+ return (pcre_cache_entry*)Z_PTR_P(zv);+ } else {+ zend_hash_del(&PCRE_G(pcre_cache), key);
}
- return (pcre_cache_entry*)Z_PTR_P(zv);
}
p = ZSTR_VAL(regex);
It should have almost zero performance effect and will keep cache for usecases which switch the PCRE JIT flag for one regex and then restore the PCRE JIT flag back.
as always/currently ;-) (PCRE JIT flag is enabled by default)
No. Currently, regexes are compiled, then JIT is attempted, and then executed with JIT if succeeded. Otherwise it is interpreted. Later executions don't retry compilation.
Activity
damianwadley commentedon Jun 5, 2023
Huh. It's backwards: normally these sorts of bugs happen with jit=1 and turning it off allows the regex to work...
That's a gigantic regex. Can you boil it down to something manageable that still reproduces?
And either way, does it also happen with the
pcretestutility? If so then it's an upstream bug, which is my suspicion, and not PHP itself.https://www.pcre.org/original/doc/html/pcretest.html
damianwadley commentedon Jun 5, 2023
Sure: turn on JIT 😉
Otherwise, maybe? You could experiment with the regex - add/remove optimizations, that sort of thing - to see if you can trigger some different internal code paths to bypass wherever the bug is. It'd be easier to do that if you could narrow down the source of the problem first, of course.
And there's always the option of breaking it down into smaller regexes... I mean really, that's 100+ lines of (formatted) regex in there. May or may not help, but it might be a nice gain regardless.
Wirone commentedon Jun 5, 2023
In my case there's
PCRE JIT Support => not compiled inso I can't enable it (asdf's PHP on M1 Mac). I can workaround it with Docker setup, but I just wanted to point that it's not always possible to use PCRE JIT.iluuu1994 commentedon Jun 5, 2023
The issue is indeed cause by JIT, not the other way around. Simpler reproducible case:
This is the correct output, with
pcre.jit=0.This is the incorrect output, with
pcre.jit=1.Note the missing capture for group
2.Looking at the
offsets, without JIT:With JIT:
So, the issue seems to originate from PCRE. I'll check if the issue was already fixed/reported upstream.
Edit: Things are a bit more complicated. Removing the
(\*?)captures 2 groups instead of the original 4, which makes no sense to me.mvorisek commentedon Jun 5, 2023
Here is online repro - https://3v4l.org/W4UkB, problem is present somewhere between PCRE >8.41 and <= 10.32 versions.
iluuu1994 commentedon Jun 5, 2023
Yeah so it does seem JIT is the odd one out after all, although the output doesn't make sense to me.
remicollet commentedon Jun 5, 2023
iluuu1994 commentedon Jun 5, 2023
The problem is reproducible with pcre-only.
3 remaining items
iluuu1994 commentedon Jun 27, 2023
@mvorisek As you have probably seen I had to revert the last PR due to bit performance implications. I also closed #11511 for the same reason. The performance drop is smaller but still more than I'd expect. The alternative approach would be to clear the cache, but that would require at least an e-mail to the mailing list. I don't think it's worth it, given this is an edge case and should be fixed in PCRE. If you'd like to start this discussion, please send a mail to the internals list. Here's a patch:
Patch
mvorisek commentedon Jun 27, 2023
What about:
It should have almost zero performance effect and will keep cache for usecases which switch the PCRE JIT flag for one regex and then restore the PCRE JIT flag back.
iluuu1994 commentedon Jun 27, 2023
This will repeatedly try jitting regexes that have failed JIT compilation. You need a separate flag as in #11511 to avoid that.
Let's see if this is faster than #11511. It avoids an additional
PCRE_G(jit)check, so it might be slightly faster.mvorisek commentedon Jun 27, 2023
as always/currently ;-) (PCRE JIT flag is enabled by default)
iluuu1994 commentedon Jun 27, 2023
No. Currently, regexes are compiled, then JIT is attempted, and then executed with JIT if succeeded. Otherwise it is interpreted. Later executions don't retry compilation.
Fix GH-11374: Different preg_match result with -d pcre.jit=0
Merge branch 'PHP-8.1' into PHP-8.2
Merge branch 'PHP-8.2' into PHP-8.3
Merge branch 'PHP-8.3'