From d61efdfe97a04f8d67e2f7180353795b5f101c9a Mon Sep 17 00:00:00 2001
From: Niels Dossche <7771979+nielsdos@users.noreply.github.com>
Date: Sat, 2 Sep 2023 20:24:39 +0200
Subject: [PATCH] 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] https://github.com/php/php-src/commit/788a701e222
[2] https://github.com/PCRE2Project/pcre2/pull/135
Closes GH-12108.
---
NEWS | 4 ++++
ext/pcre/pcre2lib/pcre2_jit_compile.c | 20 ++++++++++----------
ext/pcre/tests/gh11956.phpt | 16 ++++++++++++++++
3 files changed, 30 insertions(+), 10 deletions(-)
create mode 100644 ext/pcre/tests/gh11956.phpt
diff --git a/NEWS b/NEWS
index 6f0c68ad73c65..8c728b0744320 100644
--- a/NEWS
+++ b/NEWS
@@ -13,6 +13,10 @@ PHP NEWS
. Fixed bug GH-12186 (segfault copying/cloning a finalized HashContext).
(MaxSem)
+- PCRE:
+ . Fixed bug GH-11956 (Backport upstream fix, PCRE regular expressions with
+ JIT enabled gives different result). (nielsdos)
+
- SimpleXML:
. Fixed bug GH-12170 (Can't use xpath with comments in SimpleXML). (nielsdos)
. Fixed bug GH-12192 (SimpleXML infinite loop when getName() is called
diff --git a/ext/pcre/pcre2lib/pcre2_jit_compile.c b/ext/pcre/pcre2lib/pcre2_jit_compile.c
index 227714e577019..0b2d707ae51a7 100644
--- a/ext/pcre/pcre2lib/pcre2_jit_compile.c
+++ b/ext/pcre/pcre2lib/pcre2_jit_compile.c
@@ -11286,19 +11286,19 @@ if (exact > 1)
}
}
else if (exact == 1)
- {
compile_char1_matchingpath(common, type, cc, &backtrack->topbacktracks, TRUE);
- if (early_fail_type == type_fail_range)
- {
- OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), early_fail_ptr);
- OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), early_fail_ptr + (int)sizeof(sljit_sw));
- OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, TMP2, 0);
- OP2(SLJIT_SUB, TMP2, 0, STR_PTR, 0, TMP2, 0);
- add_jump(compiler, &backtrack->topbacktracks, CMP(SLJIT_LESS_EQUAL, TMP2, 0, TMP1, 0));
+if (early_fail_type == type_fail_range)
+ {
+ /* Range end first, followed by range start. */
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), early_fail_ptr);
+ OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), early_fail_ptr + (int)sizeof(sljit_sw));
+ OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, TMP2, 0);
+ OP2(SLJIT_SUB, TMP2, 0, STR_PTR, 0, TMP2, 0);
+ add_jump(compiler, &backtrack->topbacktracks, CMP(SLJIT_LESS_EQUAL, TMP2, 0, TMP1, 0));
- OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), early_fail_ptr + (int)sizeof(sljit_sw), STR_PTR, 0);
- }
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), early_fail_ptr, STR_PTR, 0);
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), early_fail_ptr + (int)sizeof(sljit_sw), STR_PTR, 0);
}
switch(opcode)
diff --git a/ext/pcre/tests/gh11956.phpt b/ext/pcre/tests/gh11956.phpt
new file mode 100644
index 0000000000000..91c294ffad38d
--- /dev/null
+++ b/ext/pcre/tests/gh11956.phpt
@@ -0,0 +1,16 @@
+--TEST--
+GH-11956 (PCRE regular expressions with JIT enabled gives different result)
+--INI--
+pcre.jit=1
+--FILE--
+/', '