Skip to content

Commit

Permalink
pcre2_jit_compile: avoid potential wraparound if framesize <= 0 (PCRE…
Browse files Browse the repository at this point in the history
…2Project#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
  • Loading branch information
carenas authored Oct 21, 2024
1 parent 295f94c commit ef11bee
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 32 deletions.
4 changes: 2 additions & 2 deletions RunTest
Original file line number Diff line number Diff line change
Expand Up @@ -343,10 +343,10 @@ fi
# 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
Expand Down
10 changes: 5 additions & 5 deletions doc/pcre2syntax.3
Original file line number Diff line number Diff line change
@@ -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"
Expand Down Expand Up @@ -254,7 +254,7 @@ The recognized classes are:
RLI right-to-left isolate
RLO right-to-left override
S segment separator
WS which space
WS white space
.
.
.SH "CHARACTER CLASSES"
Expand Down Expand Up @@ -398,7 +398,7 @@ of the group.
(?^) 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
Expand All @@ -411,10 +411,10 @@ The following are recognized only at the very start of a pattern or after one
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)
Expand Down Expand Up @@ -692,6 +692,6 @@ Cambridge, England.
.rs
.sp
.nf
Last updated: 24 September 2024
Last updated: 20 October 2024
Copyright (c) 1997-2024 University of Cambridge.
.fi
65 changes: 40 additions & 25 deletions src/pcre2_jit_compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -10898,7 +10898,8 @@ if (opcode == OP_ASSERT || opcode == OP_ASSERTBACK)
{
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));
Expand Down Expand Up @@ -11799,13 +11800,19 @@ if (bra == OP_BRAMINZERO)
/* 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. */
Expand Down Expand Up @@ -12053,12 +12060,7 @@ while (*cc != OP_KETRPOS)
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);
Expand Down Expand Up @@ -13504,7 +13506,7 @@ PCRE2_SPTR ccbegin;
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;
Expand Down Expand Up @@ -13656,11 +13658,14 @@ else if (SLJIT_UNLIKELY(opcode == OP_ASSERT_SCS))

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);
}
Expand Down Expand Up @@ -13704,7 +13709,8 @@ if (SLJIT_UNLIKELY(opcode == OP_COND) || SLJIT_UNLIKELY(opcode == OP_SCOND))
{
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));
Expand Down Expand Up @@ -13887,14 +13893,18 @@ if (has_alternatives)
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);
}
Expand Down Expand Up @@ -14194,6 +14204,7 @@ static SLJIT_INLINE void compile_then_trap_backtrackingpath(compiler_common *com
{
DEFINE_COMPILER;
struct sljit_jump *jump;
int framesize;
int size;

if (CURRENT_AS(then_trap_backtrack)->then_trap)
Expand All @@ -14210,11 +14221,15 @@ free_stack(common, size);
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);
Expand Down

0 comments on commit ef11bee

Please sign in to comment.