diff --git a/ChangeLog b/ChangeLog
index 4d94eb4be..57bfe579a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -107,6 +107,10 @@ well as interpreting \b and \v as characters.
24. Fixed a bug in JIT affecting greedy bounded repeats. The upper limit of
repeats inside a repeated bracket might be incorrectly checked.
+25. Fixed a bug in JIT affecting caseful matching of backreferences. When
+utf is disabled, and dupnames is enabled, caseless matching was used even
+if caseful matching was needed.
+
Version 10.44 07-June-2024
--------------------------
diff --git a/src/pcre2_jit_compile.c b/src/pcre2_jit_compile.c
index 127c393d5..ab3f2a632 100644
--- a/src/pcre2_jit_compile.c
+++ b/src/pcre2_jit_compile.c
@@ -613,13 +613,12 @@ typedef struct compare_context {
/* Local space layout. */
/* Max limit of recursions. */
#define LIMIT_MATCH (0 * sizeof(sljit_sw))
-/* Two local variables for possessive quantifiers (char1 cannot use them). */
-#define POSSESSIVE0 (1 * sizeof(sljit_sw))
-#define POSSESSIVE1 (2 * sizeof(sljit_sw))
/* Local variables. Their number is computed by check_opcode_types. */
-#define LOCAL0 (3 * sizeof(sljit_sw))
-#define LOCAL1 (4 * sizeof(sljit_sw))
-#define LOCAL2 (5 * sizeof(sljit_sw))
+#define LOCAL0 (1 * sizeof(sljit_sw))
+#define LOCAL1 (2 * sizeof(sljit_sw))
+#define LOCAL2 (3 * sizeof(sljit_sw))
+#define LOCAL3 (4 * sizeof(sljit_sw))
+#define LOCAL4 (5 * sizeof(sljit_sw))
/* The output vector is stored on the stack, and contains pointers
to characters. The vector data is divided into two groups: the first
group contains the start / end character pointers, and the second is
@@ -1125,13 +1124,33 @@ switch(*cc)
}
}
+static sljit_s32 ref_update_local_size(compiler_common *common, PCRE2_SPTR cc, sljit_s32 current_locals_size)
+{
+/* Depends on do_casefulcmp(), do_caselesscmp(), and compile_ref_matchingpath() */
+int locals_size = 2 * SSIZE_OF(sw);
+SLJIT_UNUSED_ARG(common);
+
+#ifdef SUPPORT_UNICODE
+if ((*cc == OP_REFI || *cc == OP_DNREFI) && (common->utf || common->ucp))
+ locals_size = 3 * SSIZE_OF(sw);
+#endif
+
+cc += PRIV(OP_lengths)[*cc];
+/* Although do_casefulcmp() uses only one local, the allocate_stack()
+calls during the repeat destroys LOCAL1 variables. */
+if (*cc >= OP_CRSTAR && *cc <= OP_CRPOSRANGE)
+ locals_size += 2 * SSIZE_OF(sw);
+
+return (current_locals_size >= locals_size) ? current_locals_size : locals_size;
+}
+
static BOOL check_opcode_types(compiler_common *common, PCRE2_SPTR cc, PCRE2_SPTR ccend)
{
int count;
PCRE2_SPTR slot;
PCRE2_SPTR assert_back_end = cc - 1;
PCRE2_SPTR assert_na_end = cc - 1;
-sljit_s32 locals_size = 2 * sizeof(sljit_sw);
+sljit_s32 locals_size = 2 * SSIZE_OF(sw);
BOOL set_recursive_head = FALSE;
BOOL set_capture_last = FALSE;
BOOL set_mark = FALSE;
@@ -1147,13 +1166,39 @@ while (cc < ccend)
cc += 1;
break;
- case OP_REFI:
-#ifdef SUPPORT_UNICODE
- if (common->utf || common->ucp)
- locals_size = 3 * sizeof(sljit_sw);
+ case OP_TYPEUPTO:
+ case OP_TYPEEXACT:
+ if (cc[1 + IMM2_SIZE] == OP_EXTUNI && locals_size <= 3 * SSIZE_OF(sw))
+ locals_size = 3 * SSIZE_OF(sw);
+ cc += (2 + IMM2_SIZE) - 1;
+ break;
+
+ case OP_TYPEPOSSTAR:
+ case OP_TYPEPOSPLUS:
+ case OP_TYPEPOSQUERY:
+ if (cc[1] == OP_EXTUNI && locals_size <= 3 * SSIZE_OF(sw))
+ locals_size = 3 * SSIZE_OF(sw);
+ cc += 2 - 1;
+ break;
+
+ case OP_TYPEPOSUPTO:
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+ if (common->utf)
+ {
+ if (cc[1 + IMM2_SIZE] == OP_EXTUNI && locals_size <= 4 * SSIZE_OF(sw))
+ locals_size = 4 * SSIZE_OF(sw);
+ else if (locals_size <= 3 * SSIZE_OF(sw))
+ locals_size = 3 * SSIZE_OF(sw);
+ }
#endif
- /* Fall through. */
+ if (cc[1 + IMM2_SIZE] == OP_EXTUNI && locals_size <= 3 * SSIZE_OF(sw))
+ locals_size = 3 * SSIZE_OF(sw);
+ cc += (2 + IMM2_SIZE) - 1;
+ break;
+
+ case OP_REFI:
case OP_REF:
+ locals_size = ref_update_local_size(common, cc, locals_size);
common->optimized_cbracket[GET2(cc, 1)] = 0;
cc += PRIV(OP_lengths)[*cc];
break;
@@ -1188,12 +1233,9 @@ while (cc < ccend)
break;
case OP_DNREFI:
-#ifdef SUPPORT_UNICODE
- if (common->utf || common->ucp)
- locals_size = 3 * sizeof(sljit_sw);
-#endif
- /* Fall through */
case OP_DNREF:
+ locals_size = ref_update_local_size(common, cc, locals_size);
+ /* Fall through */
case OP_DNCREF:
count = GET2(cc, 1 + IMM2_SIZE);
slot = common->name_table + GET2(cc, 1) * common->name_entry_size;
@@ -1272,6 +1314,21 @@ while (cc < ccend)
return FALSE;
#endif
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+ case OP_CRPOSRANGE:
+ if (GET2(cc, 1) < GET2(cc, 1 + IMM2_SIZE) && locals_size <= 3 * SSIZE_OF(sw))
+ locals_size = 3 * SSIZE_OF(sw);
+ cc += 1 + 2 * IMM2_SIZE;
+ break;
+
+ case OP_POSUPTO:
+ case OP_POSUPTOI:
+ case OP_NOTPOSUPTO:
+ case OP_NOTPOSUPTOI:
+ if (common->utf && locals_size <= 3 * SSIZE_OF(sw))
+ locals_size = 3 * SSIZE_OF(sw);
+#endif
+ /* Fall through */
default:
cc = next_opcode(common, cc);
if (cc == NULL)
@@ -1280,7 +1337,7 @@ while (cc < ccend)
}
}
-SLJIT_ASSERT((locals_size & (sizeof(sljit_sw) - 1)) == 0);
+SLJIT_ASSERT((locals_size & (SSIZE_OF(sw) - 1)) == 0);
#if defined SLJIT_DEBUG && SLJIT_DEBUG
common->locals_size = locals_size;
#endif
@@ -3345,12 +3402,10 @@ OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 12345);
OP1(SLJIT_MOV, TMP3, 0, TMP1, 0);
OP1(SLJIT_MOV, RETURN_ADDR, 0, TMP1, 0);
#if defined SLJIT_DEBUG && SLJIT_DEBUG
-if (common->locals_size >= (int)sizeof(sljit_sw))
- OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCAL0, TMP1, 0);
-if (common->locals_size >= 2 * (int)sizeof(sljit_sw))
- OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCAL1, TMP1, 0);
-if (common->locals_size >= 3 * (int)sizeof(sljit_sw))
- OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCAL2, TMP1, 0);
+SLJIT_ASSERT(common->locals_size >= 2 * SSIZE_OF(sw));
+/* These two are also used by the stackalloc calls. */
+OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCAL0, TMP1, 0);
+OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCAL1, TMP1, 0);
#endif
#endif
add_stub(common, CMP(SLJIT_LESS, STACK_TOP, 0, STACK_LIMIT, 0));
@@ -6892,7 +6947,7 @@ struct sljit_jump *jump;
SLJIT_UNUSED_ARG(ucp);
SLJIT_COMPILE_ASSERT(ctype_word == 0x10, ctype_word_must_be_16);
-SLJIT_ASSERT(common->locals_size >= 2 * (int)sizeof(sljit_sw));
+SLJIT_ASSERT(common->locals_size >= 2 * SSIZE_OF(sw));
sljit_emit_op_dst(compiler, SLJIT_FAST_ENTER, SLJIT_MEM1(SLJIT_SP), LOCAL0);
/* Get type of the previous char, and put it to TMP3. */
OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0);
@@ -7399,7 +7454,8 @@ else
char2_reg = RETURN_ADDR;
}
-SLJIT_ASSERT(common->locals_size >= (int)sizeof(sljit_sw));
+/* Update ref_update_local_size() when this changes. */
+SLJIT_ASSERT(common->locals_size >= SSIZE_OF(sw));
sljit_emit_op_dst(compiler, SLJIT_FAST_ENTER, SLJIT_MEM1(SLJIT_SP), LOCAL0);
OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
@@ -7487,7 +7543,8 @@ if (sljit_emit_mem_update(compiler, MOV_UCHAR | SLJIT_MEM_SUPP | SLJIT_MEM_POST,
else if (sljit_emit_mem_update(compiler, MOV_UCHAR | SLJIT_MEM_SUPP | SLJIT_MEM_PRE, char1_reg, SLJIT_MEM1(TMP1), IN_UCHARS(1)) == SLJIT_SUCCESS)
opt_type = 2;
-SLJIT_ASSERT(common->locals_size >= 2 * (int)sizeof(sljit_sw));
+/* Update ref_update_local_size() when this changes. */
+SLJIT_ASSERT(common->locals_size >= 2 * SSIZE_OF(sw));
sljit_emit_op_dst(compiler, SLJIT_FAST_ENTER, SLJIT_MEM1(SLJIT_SP), LOCAL0);
OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
@@ -7989,7 +8046,7 @@ sljit_u32 items;
int typereg = TMP1;
#endif /* SUPPORT_UNICODE */
-SLJIT_ASSERT(common->locals_size >= (int)sizeof(sljit_sw));
+SLJIT_ASSERT(common->locals_size >= SSIZE_OF(sw));
/* Scanning the necessary info. */
cc++;
ccbegin = cc;
@@ -9831,7 +9888,8 @@ else
#if defined SUPPORT_UNICODE
if ((common->utf || common->ucp) && (*cc == OP_REFI || *cc == OP_DNREFI))
{
- SLJIT_ASSERT(common->locals_size >= 3 * (int)sizeof(sljit_sw));
+ /* Update ref_update_local_size() when this changes. */
+ SLJIT_ASSERT(common->locals_size >= 3 * SSIZE_OF(sw));
if (ref)
OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1));
@@ -9970,7 +10028,7 @@ else
if (common->mode == PCRE2_JIT_COMPLETE)
add_jump(compiler, backtracks, partial);
- add_jump(compiler, *cc == OP_REF ? &common->casefulcmp : &common->caselesscmp, JUMP(SLJIT_FAST_CALL));
+ add_jump(compiler, (*cc == OP_REF || *cc == OP_DNREF) ? &common->casefulcmp : &common->caselesscmp, JUMP(SLJIT_FAST_CALL));
add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP2, 0, SLJIT_IMM, 0));
if (common->mode != PCRE2_JIT_COMPLETE)
@@ -9982,7 +10040,7 @@ else
OP2(SLJIT_ADD, TMP2, 0, TMP2, 0, STR_END, 0);
partial = CMP(SLJIT_EQUAL, TMP2, 0, SLJIT_IMM, 0);
OP1(SLJIT_MOV, STR_PTR, 0, STR_END, 0);
- add_jump(compiler, *cc == OP_REF ? &common->casefulcmp : &common->caselesscmp, JUMP(SLJIT_FAST_CALL));
+ add_jump(compiler, (*cc == OP_REF || *cc == OP_DNREF) ? &common->casefulcmp : &common->caselesscmp, JUMP(SLJIT_FAST_CALL));
add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP2, 0, SLJIT_IMM, 0));
JUMPHERE(partial);
check_partial(common, FALSE);
@@ -10006,6 +10064,7 @@ DEFINE_COMPILER;
BOOL ref = (*cc == OP_REF || *cc == OP_REFI);
backtrack_common *backtrack;
PCRE2_UCHAR type;
+int local_start = LOCAL2;
int offset = 0;
struct sljit_label *label;
struct sljit_jump *zerolength;
@@ -10022,10 +10081,19 @@ else
cc += IMM2_SIZE;
if (*ccbegin == OP_REFI || *ccbegin == OP_DNREFI)
+ {
cc += 1;
+#ifdef SUPPORT_UNICODE
+ if (common->utf || common->ucp)
+ local_start = LOCAL3;
+#endif
+ }
+
type = cc[1 + IMM2_SIZE];
SLJIT_COMPILE_ASSERT((OP_CRSTAR & 0x1) == 0, crstar_opcode_must_be_even);
+/* Update ref_update_local_size() when this changes. */
+SLJIT_ASSERT(local_start + 2 * SSIZE_OF(sw) <= (int)LOCAL0 + common->locals_size);
minimize = (type & 0x1) != 0;
switch(type)
{
@@ -10077,7 +10145,7 @@ if (!minimize)
{
compile_dnref_search(common, ccbegin, NULL);
OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP2), 0);
- OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), POSSESSIVE1, TMP2, 0);
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), local_start + SSIZE_OF(sw), TMP2, 0);
zerolength = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_MEM1(TMP2), sizeof(sljit_sw));
}
/* Restore if not zero length. */
@@ -10100,24 +10168,24 @@ if (!minimize)
{
compile_dnref_search(common, ccbegin, &backtrack->own_backtracks);
OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP2), 0);
- OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), POSSESSIVE1, TMP2, 0);
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), local_start + SSIZE_OF(sw), TMP2, 0);
zerolength = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_MEM1(TMP2), sizeof(sljit_sw));
}
}
if (min > 1 || max > 1)
- OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), POSSESSIVE0, SLJIT_IMM, 0);
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), local_start, SLJIT_IMM, 0);
label = LABEL();
if (!ref)
- OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), POSSESSIVE1);
+ OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), local_start + SSIZE_OF(sw));
compile_ref_matchingpath(common, ccbegin, &backtrack->own_backtracks, FALSE, FALSE);
if (min > 1 || max > 1)
{
- OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), POSSESSIVE0);
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), local_start);
OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, 1);
- OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), POSSESSIVE0, TMP1, 0);
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), local_start, TMP1, 0);
if (min > 1)
CMPTO(SLJIT_LESS, TMP1, 0, SLJIT_IMM, min, label);
if (max > 1)
@@ -10385,7 +10453,7 @@ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), CALLOUT_ARG_OFFSET(mark), (common->mark_pt
SLJIT_ASSERT(TMP1 == SLJIT_R0 && STR_PTR == SLJIT_R1);
/* Needed to save important temporary registers. */
-SLJIT_ASSERT(common->locals_size >= (int)sizeof(sljit_sw));
+SLJIT_ASSERT(common->locals_size >= SSIZE_OF(sw));
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCAL0, STR_PTR, 0);
/* SLJIT_R0 = arguments */
OP1(SLJIT_MOV, SLJIT_R1, 0, STACK_TOP, 0);
@@ -11776,7 +11844,7 @@ else switch (opcode)
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr + sizeof(sljit_sw), TMP1, 0);
/* Nested scs blocks will not update this variable. */
- if (common->restore_end_ptr == private_data_ptr + (int)sizeof(sljit_sw))
+ if (common->restore_end_ptr == private_data_ptr + SSIZE_OF(sw))
common->restore_end_ptr = 0;
break;
}
@@ -12199,9 +12267,9 @@ else
{
SLJIT_ASSERT(*opcode == OP_CLASS || *opcode == OP_NCLASS || *opcode == OP_XCLASS);
*type = *opcode;
+ class_len = (*type < OP_XCLASS) ? (int)(1 + (32 / sizeof(PCRE2_UCHAR))) : GET(cc, 1);
+ *opcode = cc[class_len];
cc++;
- class_len = (*type < OP_XCLASS) ? (int)(1 + (32 / sizeof(PCRE2_UCHAR))) : GET(cc, 0);
- *opcode = cc[class_len - 1];
if (*opcode >= OP_CRSTAR && *opcode <= OP_CRMINQUERY)
{
@@ -12358,7 +12426,7 @@ if (type != OP_EXTUNI)
else
{
tmp_base = SLJIT_MEM1(SLJIT_SP);
- tmp_offset = POSSESSIVE0;
+ tmp_offset = LOCAL2;
}
/* Handle fixed part first. */
@@ -12382,6 +12450,7 @@ if (exact > 1)
}
else
{
+ SLJIT_ASSERT(tmp_base == TMP3 || common->locals_size >= 3 * SSIZE_OF(sw));
OP1(SLJIT_MOV, tmp_base, tmp_offset, SLJIT_IMM, exact);
label = LABEL();
compile_char1_matchingpath(common, type, cc, &backtrack->own_backtracks, TRUE);
@@ -12421,16 +12490,19 @@ switch(opcode)
OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_IMM, 0);
if (opcode == OP_UPTO)
- OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), POSSESSIVE0, SLJIT_IMM, max);
+ {
+ SLJIT_ASSERT(common->locals_size >= 3 * SSIZE_OF(sw));
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCAL2, SLJIT_IMM, max);
+ }
label = LABEL();
compile_char1_matchingpath(common, type, cc, &BACKTRACK_AS(char_iterator_backtrack)->u.backtracks, TRUE);
if (opcode == OP_UPTO)
{
- OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), POSSESSIVE0);
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), LOCAL2);
OP2(SLJIT_SUB | SLJIT_SET_Z, TMP1, 0, TMP1, 0, SLJIT_IMM, 1);
jump = JUMP(SLJIT_ZERO);
- OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), POSSESSIVE0, TMP1, 0);
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCAL2, TMP1, 0);
}
/* We cannot use TMP3 because of allocate_stack. */
@@ -12717,6 +12789,7 @@ switch(opcode)
#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
if (type == OP_EXTUNI || common->utf)
{
+ SLJIT_ASSERT(tmp_base == TMP3 || common->locals_size >= 3 * SSIZE_OF(sw));
OP1(SLJIT_MOV, tmp_base, tmp_offset, STR_PTR, 0);
detect_partial_match(common, &no_match);
label = LABEL();
@@ -12752,22 +12825,30 @@ switch(opcode)
case OP_POSUPTO:
SLJIT_ASSERT(early_fail_ptr == 0);
+ SLJIT_ASSERT(tmp_base == TMP3 || common->locals_size >= 3 * SSIZE_OF(sw));
#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
if (common->utf)
{
- OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), POSSESSIVE1, STR_PTR, 0);
+ SLJIT_ASSERT(common->locals_size >= 3 * SSIZE_OF(sw));
+ if (tmp_base != TMP3)
+ {
+ SLJIT_ASSERT(type == OP_EXTUNI && common->locals_size >= 4 * SSIZE_OF(sw));
+ tmp_offset = LOCAL3;
+ }
+
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCAL2, STR_PTR, 0);
OP1(SLJIT_MOV, tmp_base, tmp_offset, SLJIT_IMM, max);
detect_partial_match(common, &no_match);
label = LABEL();
compile_char1_matchingpath(common, type, cc, &no_match, FALSE);
- OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), POSSESSIVE1, STR_PTR, 0);
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCAL2, STR_PTR, 0);
OP2(SLJIT_SUB | SLJIT_SET_Z, tmp_base, tmp_offset, tmp_base, tmp_offset, SLJIT_IMM, 1);
add_jump(compiler, &no_match, JUMP(SLJIT_ZERO));
detect_partial_match_to(common, label);
set_jumps(no_match, LABEL());
- OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), POSSESSIVE1);
+ OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), LOCAL2);
break;
}
#endif
@@ -12807,6 +12888,7 @@ switch(opcode)
case OP_POSQUERY:
SLJIT_ASSERT(early_fail_ptr == 0);
+ SLJIT_ASSERT(tmp_base == TMP3 || common->locals_size >= 3 * SSIZE_OF(sw));
OP1(SLJIT_MOV, tmp_base, tmp_offset, STR_PTR, 0);
compile_char1_matchingpath(common, type, cc, &no_match, TRUE);
OP1(SLJIT_MOV, tmp_base, tmp_offset, STR_PTR, 0);
@@ -14038,7 +14120,7 @@ else if (opcode == OP_ASSERT_SCS)
set_jumps(CURRENT_AS(bracket_backtrack)->u.no_capture, LABEL());
/* Nested scs blocks will not update this variable. */
- if (common->restore_end_ptr == private_data_ptr + (int)sizeof(sljit_sw))
+ if (common->restore_end_ptr == private_data_ptr + SSIZE_OF(sw))
common->restore_end_ptr = 0;
}
else if (opcode == OP_ONCE)
@@ -15241,7 +15323,7 @@ SLJIT_ASSERT(common->restore_end_ptr == 0);
/* This is a (really) rare case. */
set_jumps(common->stackalloc, LABEL());
/* RETURN_ADDR is not a saved register. */
-SLJIT_ASSERT(common->locals_size >= 2 * (int)sizeof(sljit_sw));
+SLJIT_ASSERT(common->locals_size >= 2 * SSIZE_OF(sw));
sljit_emit_op_dst(compiler, SLJIT_FAST_ENTER, SLJIT_MEM1(SLJIT_SP), LOCAL0);
SLJIT_ASSERT(TMP1 == SLJIT_R0 && STR_PTR == SLJIT_R1);
diff --git a/src/pcre2_jit_test.c b/src/pcre2_jit_test.c
index 28bc7af94..0a0033128 100644
--- a/src/pcre2_jit_test.c
+++ b/src/pcre2_jit_test.c
@@ -608,6 +608,7 @@ static struct regression_test_case regression_test_cases[] = {
{ CMU | PCRE2_DUPNAMES, A, 0, 0, "(?:(?AA)|(?BB))\\k{1,3}M", "aaaaaaaabbbbaabbbbm" },
{ CMU | PCRE2_DUPNAMES, A, 0, 0, "(?:(?AA)|(?BB))\\k{0,3}?M", "aaaaaabbbbbbaabbbbbbbbbbm" },
{ CMU | PCRE2_DUPNAMES, A, 0, 0, "(?:(?AA)|(?BB))\\k{2,3}?", "aaaabbbbaaaabbbbbbbbbb" },
+ { MU | PCRE2_DUPNAMES, A, 0, 0, "^(?P..)(?P..)\\k{2,4}", "AaAAAaAaAaaA" },
{ MU | PCRE2_MATCH_UNSET_BACKREF, A, 0, 0, "(a)|\\1+c", "xxc" },
{ MU | PCRE2_MATCH_UNSET_BACKREF, A, 0, 0, "\\1+?()", "" },
@@ -818,6 +819,8 @@ static struct regression_test_case regression_test_cases[] = {
{ MU, A, PCRE2_PARTIAL_SOFT, 0, "abc|(?<=xxa)bc", "xxab" },
{ MU, A, PCRE2_PARTIAL_SOFT, 0, "a\\B", "a" },
{ MU, A, PCRE2_PARTIAL_HARD, 0, "a\\b", "a" },
+ { M | PCRE2_DUPNAMES, A, PCRE2_PARTIAL_HARD, 0, "^(?P..)(?P..)\\k{2,4}", "AaAAAaAaAaA" },
+ { M | PCRE2_DUPNAMES, A, PCRE2_PARTIAL_HARD, 0, "^(?P..)(?P..)\\k{2,4}", "AaAAAaAaAaa" },
/* (*MARK) verb. */
{ MU, A, 0, 0, "a(*MARK:aa)a", "ababaa" },