Skip to content

guard end-before-start match length in pcre2grep -o and --output - #954

Merged
NWilson merged 4 commits into
PCRE2Project:mainfrom
sage-mode-hunter:grep-om-output-length-underflow
Aug 22, 2026
Merged

guard end-before-start match length in pcre2grep -o and --output#954
NWilson merged 4 commits into
PCRE2Project:mainfrom
sage-mode-hunter:grep-om-output-length-underflow

Conversation

@sage-mode-hunter

Copy link
Copy Markdown
Contributor

Length underflow on an end-before-start match in pcre2grep

With --allow-lookaround-bsk, a \K inside a lookaround can leave a match whose end offset is before its start ((?=foo\K) on XfooY gives ovector 4..1). The -o and --output paths take the printed length as an unsigned end - start, which wraps near SIZE_MAX and runs print_match/fwrite off the end of the line buffer. The colour and multiline paths already swap for this exact case; these two did not. Guarded both so a reversed match counts as empty, which is what the existing plen > 0 / capturesize > 0 tests were already after.

Repro under ASAN (small --buffer-size to land on the redzone):

printf 'XfooY\n' | pcre2grep --buffer-size=24 --allow-lookaround-bsk -o '(?=foo\K)' -
printf 'XfooY\n' | pcre2grep --buffer-size=24 --allow-lookaround-bsk --output '$0' '(?=foo\K)' -

Both fault in the length-based write (pcre2grep.c:2889 for -o, :2216 for --output) before the patch and run clean after. Added test 161 to RunGrepTest.

@NWilson NWilson left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is great, thank you!

However... we do have a convention already in a couple of other places in pcre2grep, where these pathological "reversed matches" are just printed as [min(start,end) ... max(start,end)].

Would it be OK to swap these two you found to behave the same, just for consistency?

I also asked GPT to check for others, and it found some. It should be quick & easy (hopefully!) to make the same change in each place.

Comment thread src/pcre2grep.c Outdated
Comment on lines 2856 to 2857

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here's one needing the same treatment.

Create local variables, swap if not ordered.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, start/end locals with a swap, shared by both offset options.

Comment thread src/pcre2grep.c Outdated
Comment on lines 2862 to 2864

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This usage too.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Covered by the same block as --line-offsets now.

Comment thread src/pcre2grep.c Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be testing which is larger, and doing the reversed subtraction if they are not ordered.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, reversed subtraction when end < start so it agrees with the memcpy pass below.

Comment thread src/pcre2grep.c Outdated
Comment on lines 2427 to 2428

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another one here to swap/flip.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Swapped here too.

…oing

Follow the existing convention used by the colour and multiline code:
when \K leaves the end offset before the start, print the range
[min, max] rather than treating it as empty. Apply the same swap to
--line-offsets, --file-offsets, and the callout argument length and
copy, which had the same unsigned subtraction.
@sage-mode-hunter

Copy link
Copy Markdown
Contributor Author

Makes sense, switched both to the swap convention and did the same in the four spots you marked (--line-offsets, --file-offsets, and the callout argslen/memcpy pair). For the argslen one I kept it as a conditional subtraction since it's only a length, the rest use start/end locals with the same swap block as the colour path. Test 161 now expects "foo" and covers --line-offsets / --file-offsets too. RunGrepTest is green with and without ASAN.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Prevents unsigned length underflow when \K produces reversed match offsets in pcre2grep.

Changes:

  • Normalizes reversed capture and match offsets before output.
  • Covers -o, --output, callouts, and offset-reporting modes.
  • Adds regression test 161 and expected output.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

File Description
src/pcre2grep.c Safely handles end-before-start offsets.
RunGrepTest Adds regression commands for affected modes.
testdata/grepoutput Records expected regression output.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@NWilson NWilson left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Amazing, thank you very much!

@NWilson NWilson added this to the 10.48 milestone Aug 21, 2026
@NWilson

NWilson commented Aug 22, 2026

Copy link
Copy Markdown
Member

I pushed a small commit adding the matching update RunGrepTest.bat

@NWilson
NWilson merged commit 30697d9 into PCRE2Project:main Aug 22, 2026
37 of 39 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants