pcre2_jit_compile: avoid potential wraparound if framesize <= 0 (#531)
Change the minimum framesize value to match what the code can
support, while at it, refactor some of the conditionals used
so that extracting the framesize is more reliable (as the
assert is polymorphic) and update other seemingly unrelated bits
diff --git a/RunTest b/RunTest
index 068e439..a165b03 100755
--- a/RunTest
+++ b/RunTest
@@ -343,10 +343,10 @@
# If it is possible to set the system stack size and -bigstack was given,
# set up a large stack.
-$sim ./pcre2test -S 64 /dev/null /dev/null
+$sim ./pcre2test -S 32 /dev/null /dev/null
support_setstack=$?
if [ $support_setstack -eq 0 -a "$bigstack" != "" ] ; then
- setstack="-S 64"
+ setstack="-S 32"
else
setstack=""
fi
diff --git a/doc/pcre2syntax.3 b/doc/pcre2syntax.3
index eda042b..4e769f1 100644
--- a/doc/pcre2syntax.3
+++ b/doc/pcre2syntax.3
@@ -1,4 +1,4 @@
-.TH PCRE2SYNTAX 3 "24 September 2024" "PCRE2 10.45"
+.TH PCRE2SYNTAX 3 "20 October 2024" "PCRE2 10.45"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH "PCRE2 REGULAR EXPRESSION SYNTAX SUMMARY"
@@ -254,7 +254,7 @@
RLI right-to-left isolate
RLO right-to-left override
S segment separator
- WS which space
+ WS white space
.
.
.SH "CHARACTER CLASSES"
@@ -398,7 +398,7 @@
(?^) unset imnrsx options
.sp
(?aP) implies (?aT) as well, though this has no additional effect. However, it
-means that (?-aP) is really (?-PT) which disables all ASCII restrictions for
+means that (?-aP) also implies (?-aT) and disables all ASCII restrictions for
POSIX classes.
.P
Unsetting x or xx unsets both. Several options may be set at once, and a
@@ -411,10 +411,10 @@
of the newline or \eR sequences or options with similar syntax. More than one
of them may appear. For the first three, d is a decimal number.
.sp
- (*CASELESS_RESTRICT) set PCRE2_EXTRA_CASELESS_RESTRICT when matching
(*LIMIT_DEPTH=d) set the backtracking limit to d
(*LIMIT_HEAP=d) set the heap size limit to d * 1024 bytes
(*LIMIT_MATCH=d) set the match limit to d
+ (*CASELESS_RESTRICT) set PCRE2_EXTRA_CASELESS_RESTRICT when matching
(*NOTEMPTY) set PCRE2_NOTEMPTY when matching
(*NOTEMPTY_ATSTART) set PCRE2_NOTEMPTY_ATSTART when matching
(*NO_AUTO_POSSESS) no auto-possessification (PCRE2_NO_AUTO_POSSESS)
@@ -692,6 +692,6 @@
.rs
.sp
.nf
-Last updated: 24 September 2024
+Last updated: 20 October 2024
Copyright (c) 1997-2024 University of Cambridge.
.fi
diff --git a/src/pcre2_jit_compile.c b/src/pcre2_jit_compile.c
index 2cb9dee..0fdd468 100644
--- a/src/pcre2_jit_compile.c
+++ b/src/pcre2_jit_compile.c
@@ -10898,7 +10898,8 @@
{
JUMPTO(SLJIT_JUMP, backtrack->matchingpath);
JUMPHERE(brajump);
- if (framesize >= 0)
+ SLJIT_ASSERT(framesize != 0);
+ if (framesize > 0)
{
OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL));
@@ -11799,13 +11800,19 @@
/* We need to release the end pointer to perform the
backtrack for the zero-length iteration. When
framesize is < 0, OP_ONCE will do the release itself. */
- if (opcode == OP_ONCE && BACKTRACK_AS(bracket_backtrack)->u.framesize >= 0)
+ if (opcode == OP_ONCE)
{
- OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
- add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL));
- OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (BACKTRACK_AS(bracket_backtrack)->u.framesize - 1) * sizeof(sljit_sw));
+ int framesize = BACKTRACK_AS(bracket_backtrack)->u.framesize;
+
+ SLJIT_ASSERT(framesize != 0);
+ if (framesize > 0)
+ {
+ OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
+ add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL));
+ OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (framesize - 1) * sizeof(sljit_sw));
+ }
}
- else if (ket == OP_KETRMIN && opcode != OP_ONCE)
+ else if (ket == OP_KETRMIN)
free_stack(common, 1);
}
/* Continue to the normal backtrack. */
@@ -12053,12 +12060,7 @@
add_jump(compiler, &emptymatch, CMP(SLJIT_EQUAL, TMP1, 0, STR_PTR, 0));
if (!zero)
- {
- if (framesize < 0)
- OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize - 1), SLJIT_IMM, 0);
- else
- OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0);
- }
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0);
}
JUMPTO(SLJIT_JUMP, loop);
@@ -13504,7 +13506,7 @@
PCRE2_SPTR ccprev;
PCRE2_UCHAR bra = OP_BRA;
PCRE2_UCHAR ket;
-assert_backtrack *assert;
+const assert_backtrack *assert;
BOOL has_alternatives;
BOOL needs_control_head = FALSE;
BOOL has_vreverse;
@@ -13656,11 +13658,14 @@
if (SLJIT_UNLIKELY(opcode == OP_ONCE))
{
- if (CURRENT_AS(bracket_backtrack)->u.framesize >= 0)
+ int framesize = CURRENT_AS(bracket_backtrack)->u.framesize;
+
+ SLJIT_ASSERT(framesize != 0);
+ if (framesize > 0)
{
OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL));
- OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (CURRENT_AS(bracket_backtrack)->u.framesize - 1) * sizeof(sljit_sw));
+ OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (framesize - 1) * sizeof(sljit_sw));
}
once = JUMP(SLJIT_JUMP);
}
@@ -13704,7 +13709,8 @@
{
SLJIT_ASSERT(has_alternatives);
assert = CURRENT_AS(bracket_backtrack)->u.assert;
- if (assert->framesize >= 0 && (ccbegin[1 + LINK_SIZE] == OP_ASSERT || ccbegin[1 + LINK_SIZE] == OP_ASSERTBACK))
+ SLJIT_ASSERT(assert->framesize != 0);
+ if (assert->framesize > 0 && (ccbegin[1 + LINK_SIZE] == OP_ASSERT || ccbegin[1 + LINK_SIZE] == OP_ASSERTBACK))
{
OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), assert->private_data_ptr);
add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL));
@@ -13887,14 +13893,18 @@
if (cond != NULL)
{
SLJIT_ASSERT(opcode == OP_COND || opcode == OP_SCOND);
- assert = CURRENT_AS(bracket_backtrack)->u.assert;
- if ((ccbegin[1 + LINK_SIZE] == OP_ASSERT_NOT || ccbegin[1 + LINK_SIZE] == OP_ASSERTBACK_NOT) && assert->framesize >= 0)
+ if (ccbegin[1 + LINK_SIZE] == OP_ASSERT_NOT || ccbegin[1 + LINK_SIZE] == OP_ASSERTBACK_NOT)
{
- OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), assert->private_data_ptr);
- add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL));
- OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(-2));
- OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (assert->framesize - 1) * sizeof(sljit_sw));
- OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), assert->private_data_ptr, TMP1, 0);
+ assert = CURRENT_AS(bracket_backtrack)->u.assert;
+ SLJIT_ASSERT(assert->framesize != 0);
+ if (assert->framesize > 0)
+ {
+ OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), assert->private_data_ptr);
+ add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL));
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(-2));
+ OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (assert->framesize - 1) * sizeof(sljit_sw));
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), assert->private_data_ptr, TMP1, 0);
+ }
}
JUMPHERE(cond);
}
@@ -14194,6 +14204,7 @@
{
DEFINE_COMPILER;
struct sljit_jump *jump;
+int framesize;
int size;
if (CURRENT_AS(then_trap_backtrack)->then_trap)
@@ -14210,11 +14221,15 @@
jump = JUMP(SLJIT_JUMP);
set_jumps(CURRENT_AS(then_trap_backtrack)->quit, LABEL());
+
+framesize = CURRENT_AS(then_trap_backtrack)->framesize;
+SLJIT_ASSERT(framesize != 0);
+
/* STACK_TOP is set by THEN. */
-if (CURRENT_AS(then_trap_backtrack)->framesize >= 0)
+if (framesize > 0)
{
add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL));
- OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (CURRENT_AS(then_trap_backtrack)->framesize - 1) * sizeof(sljit_sw));
+ OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (framesize - 1) * sizeof(sljit_sw));
}
OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
free_stack(common, 3);