Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ library installation directories.
pattern is called recursively, which could prevent valid matches requiring
backtracking after the recursive call.

3. (#1040) Fixed the start_match field passed to interpreter callouts after \K
resets the start of a match, including restoration on backtracking.


Version 10.49 28-September-2026
-------------------------------
Expand Down
7 changes: 3 additions & 4 deletions src/pcre2_match.c
Original file line number Diff line number Diff line change
Expand Up @@ -307,15 +307,15 @@ do_callout(heapframe *F, match_block *mb, PCRE2_SIZE *lengthptr)

callout_ovector = (PCRE2_SIZE *)(Fovector)-2;

/* The cb->version, cb->subject, cb->subject_length, and cb->start_match fields
are set externally. The first 3 never change; the last is updated for each
bumpalong. */
/* The cb->version, cb->subject, and cb->subject_length fields are set
externally and never change. */

cb = mb->cb;
cb->capture_top = (uint32_t)Foffset_top / 2 + 1;
cb->capture_last = Fcapture_last;
cb->offset_vector = callout_ovector;
cb->mark = mb->nomatch_mark;
cb->start_match = (PCRE2_SIZE)(Fstart_match - mb->start_subject);
cb->current_position = (PCRE2_SIZE)(Feptr - mb->start_subject);
cb->pattern_position = GET(Fecode, 1);
cb->next_item_length = GET(Fecode, 1 + LINK_SIZE);
Expand Down Expand Up @@ -8719,7 +8719,6 @@ pcre2_match(const pcre2_code *code, PCRE2_SPTR subject, PCRE2_SIZE length, PCRE2
/* OK, we can now run the match. If "hitend" is set afterwards, remember the
first starting point for which a partial match was found. */

cb.start_match = (PCRE2_SIZE)(start_match - subject);
cb.callout_flags |= PCRE2_CALLOUT_STARTMATCH;

mb->start_used_ptr = start_match;
Expand Down
33 changes: 33 additions & 0 deletions testdata/testinput2
Original file line number Diff line number Diff line change
Expand Up @@ -8453,4 +8453,37 @@ a)"xI
abc\=ps,substitute_replacement_only,replace=>$_<
abc\=ps,substitute_replacement_only,replace=>$'<

# Callout start offsets after resetting the start of a match.

/(?C1)A\K(?C2)B(?C3)C/
_ABC_
_ABC_ABC_\=offset=4

/A\K(?C"after")BC/
_ABC_

/A\K(?C1)B\K(?C2)C/
_ABC_

/A(?:B\K(?C1)D|(?C2)B)(?C3)C/
_ABC_

/A\K(?(?C1)(?=B)B|D)C/
_ABC_\=no_jit

/(?(DEFINE)(?<x>A\K(?C1)B))(?&x)(?C2)C/
_ABC_

/A\K(?C1)B/
_AC_AB_

/(?C1)A\K(?C2)B/no_start_optimize
_AC_AB_

/(?C1)A(?C2)B(?C3)C/
_ABC_

/A\KBC/auto_callout
_ABC_

# End of testinput2
88 changes: 88 additions & 0 deletions testdata/testoutput2
Original file line number Diff line number Diff line change
Expand Up @@ -23955,6 +23955,94 @@ Failed: error -76 at offset 3 in replacement: replacement $' or $_ not supported
Failed: error -76 at offset 3 in replacement: replacement $' or $_ not supported with partial match
here: >$' |<--| <

# Callout start offsets after resetting the start of a match.

/(?C1)A\K(?C2)B(?C3)C/
_ABC_
--->_ABC_
1 ^ A
2 ^ B
3 ^^ C
0: BC
_ABC_ABC_\=offset=4
--->_ABC_ABC_
1 ^ A
2 ^ B
3 ^^ C
0: BC

/A\K(?C"after")BC/
_ABC_
Callout (7): "after"
--->_ABC_
^ B
0: BC

/A\K(?C1)B\K(?C2)C/
_ABC_
--->_ABC_
1 ^ B
2 ^ C
0: C

/A(?:B\K(?C1)D|(?C2)B)(?C3)C/
_ABC_
--->_ABC_
1 ^ D
2 ^^ B
3 ^ ^ C
0: ABC

/A\K(?(?C1)(?=B)B|D)C/
_ABC_\=no_jit
--->_ABC_
1 ^ (?=
0: BC

/(?(DEFINE)(?<x>A\K(?C1)B))(?&x)(?C2)C/
_ABC_
--->_ABC_
1 ^ B
2 ^^ C
0: BC

/A\K(?C1)B/
_AC_AB_
--->_AC_AB_
1 ^ B
1 ^ B
0: B

/(?C1)A\K(?C2)B/no_start_optimize
_AC_AB_
--->_AC_AB_
1 ^ A
1 ^ A
2 ^ B
1 ^ A
1 ^ A
1 ^ A
2 ^ B
0: B

/(?C1)A(?C2)B(?C3)C/
_ABC_
--->_ABC_
1 ^ A
2 ^^ B
3 ^ ^ C
0: ABC

/A\KBC/auto_callout
_ABC_
--->_ABC_
+0 ^ A
+1 ^^ \K
+3 ^ B
+4 ^^ C
+5 ^ ^ End of pattern
0: BC

# End of testinput2
Error -80: PCRE2_ERROR_BADDATA (unknown error number)
Error -62: bad serialized data
Expand Down
Loading