From 410461cf21961f2455d51780548517d1b71dce45 Mon Sep 17 00:00:00 2001 From: CAOShurong <170531907+CAOShurong@users.noreply.github.com> Date: Fri, 16 Oct 2026 05:14:41 +0800 Subject: [PATCH] Fix interpreter callout start_match after \K --- ChangeLog | 3 ++ src/pcre2_match.c | 6 ++-- testdata/testinput2 | 30 +++++++++++++++++ testdata/testoutput2 | 76 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 112 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index 8ddf1b2d7..c1ce9abbc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -15,6 +15,9 @@ Version 10.50 xx-xxx-2026 the configured header installation directory and handle absolute header and library installation directories. +2. (#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 ------------------------------- diff --git a/src/pcre2_match.c b/src/pcre2_match.c index e4f8f551c..51c82739e 100644 --- a/src/pcre2_match.c +++ b/src/pcre2_match.c @@ -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); diff --git a/testdata/testinput2 b/testdata/testinput2 index 812d0b8e6..4627bea5b 100644 --- a/testdata/testinput2 +++ b/testdata/testinput2 @@ -8417,4 +8417,34 @@ 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)(?A\K(?C1)B))(?&x)(?C2)C/ + _ABC_ + +/A\K(?C1)B/ + _AC_AB_ + +/(?C1)A(?C2)B(?C3)C/ + _ABC_ + +/A\KBC/auto_callout + _ABC_ + # End of testinput2 diff --git a/testdata/testoutput2 b/testdata/testoutput2 index 6ffa12c6c..0dc31d814 100644 --- a/testdata/testoutput2 +++ b/testdata/testoutput2 @@ -23843,6 +23843,82 @@ 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)(?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(?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