Skip to content

Commit d61efdf

Browse files
committed
Fix GH-11956: PCRE regular expressions with JIT enabled gives different result
The code in the attached test used to work correctly in PHP 8.0, but not in 8.1+. This is because PHP 8.1+ uses a more modern version of pcre2 than PHP 8.0, and that pcre2 versions has a regression. While upgrading pcre2lib seems to be only done for the master branch, it is possible to backport upstream fixes to stable branches. This has been already done in the past in for JIT regressions [1], so it is not unprecedented. We backport the upstream pcre2 fix [2]. [1] 788a701e222 [2] PCRE2Project/pcre2#135 Closes GH-12108.
1 parent 910f579 commit d61efdf

File tree

3 files changed

+30
-10
lines changed

3 files changed

+30
-10
lines changed

NEWS

+4
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ PHP NEWS
1313
. Fixed bug GH-12186 (segfault copying/cloning a finalized HashContext).
1414
(MaxSem)
1515

16+
- PCRE:
17+
. Fixed bug GH-11956 (Backport upstream fix, PCRE regular expressions with
18+
JIT enabled gives different result). (nielsdos)
19+
1620
- SimpleXML:
1721
. Fixed bug GH-12170 (Can't use xpath with comments in SimpleXML). (nielsdos)
1822
. Fixed bug GH-12192 (SimpleXML infinite loop when getName() is called

ext/pcre/pcre2lib/pcre2_jit_compile.c

+10-10
Original file line numberDiff line numberDiff line change
@@ -11286,19 +11286,19 @@ if (exact > 1)
1128611286
}
1128711287
}
1128811288
else if (exact == 1)
11289-
{
1129011289
compile_char1_matchingpath(common, type, cc, &backtrack->topbacktracks, TRUE);
1129111290

11292-
if (early_fail_type == type_fail_range)
11293-
{
11294-
OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), early_fail_ptr);
11295-
OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), early_fail_ptr + (int)sizeof(sljit_sw));
11296-
OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, TMP2, 0);
11297-
OP2(SLJIT_SUB, TMP2, 0, STR_PTR, 0, TMP2, 0);
11298-
add_jump(compiler, &backtrack->topbacktracks, CMP(SLJIT_LESS_EQUAL, TMP2, 0, TMP1, 0));
11291+
if (early_fail_type == type_fail_range)
11292+
{
11293+
/* Range end first, followed by range start. */
11294+
OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), early_fail_ptr);
11295+
OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), early_fail_ptr + (int)sizeof(sljit_sw));
11296+
OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, TMP2, 0);
11297+
OP2(SLJIT_SUB, TMP2, 0, STR_PTR, 0, TMP2, 0);
11298+
add_jump(compiler, &backtrack->topbacktracks, CMP(SLJIT_LESS_EQUAL, TMP2, 0, TMP1, 0));
1129911299

11300-
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), early_fail_ptr + (int)sizeof(sljit_sw), STR_PTR, 0);
11301-
}
11300+
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), early_fail_ptr, STR_PTR, 0);
11301+
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), early_fail_ptr + (int)sizeof(sljit_sw), STR_PTR, 0);
1130211302
}
1130311303

1130411304
switch(opcode)

ext/pcre/tests/gh11956.phpt

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
--TEST--
2+
GH-11956 (PCRE regular expressions with JIT enabled gives different result)
3+
--INI--
4+
pcre.jit=1
5+
--FILE--
6+
<?php
7+
preg_match( '/<(\w+)[\s\w\-]+ id="S44_i89ew">/', '<br><div id="S44_i89ew">', $matches );
8+
var_dump($matches);
9+
?>
10+
--EXPECT--
11+
array(2) {
12+
[0]=>
13+
string(20) "<div id="S44_i89ew">"
14+
[1]=>
15+
string(2) "di"
16+
}

0 commit comments

Comments
 (0)