Zsh Mailing List Archive
Messages sorted by:
Reverse Date,
Date,
Thread,
Author
[PATCH 2/5] patmatch(): give traps run mid-match their own pattern buffer
- X-seq: zsh-workers 55172
- From: Imre Péntek <imre@xxxxxxxxxx>
- To: zsh-workers@xxxxxxx
- Cc: Imre Péntek <imre@xxxxxxxxxx>, "Claude Opus 5.5" <noreply@xxxxxxxxxxxxx>
- Subject: [PATCH 2/5] patmatch(): give traps run mid-match their own pattern buffer
- Date: Wed, 23 Sep 2026 19:08:22 +0200
- Archived-at: <https://zsh.org/workers/55172>
- In-reply-to: <20260923170825.501947-1-imre@pentek.dev>
- List-id: <zsh-workers.zsh.org>
- References: <20260923170825.501947-1-imre@pentek.dev>
patmatch() runs queued signal handlers while matching
(check_for_signals()). If the pattern being matched was compiled with
PAT_STATIC (as compgetmatch() does for ${x#pat}, ${x:#pat} etc.), the
program lives in the shared patout buffer. A trap that compiles
another PAT_STATIC pattern, e.g. via a "case" statement, reallocates
patout and the interrupted match continues on freed memory, typically
crashing at "next = PATNEXT(scan)".
Save patout/patalloc around the handlers and let them allocate a
buffer of their own, freed afterwards.
This is the crash seen when holding Ctrl-C at a powerlevel10k prompt:
SIGSEGV in patmatch() from pattryrefs(), during prompt expansion.
Co-Authored-By: Claude Opus 5.5 <noreply@xxxxxxxxxxxxx>
---
Notes:
Reproducer: start "zsh -f", paste the lines below, then hold down
Ctrl-C for a few seconds. Without this patch (preceding ones applied),
zsh 5.9.2 segfaults in patmatch(); AddressSanitizer reports heap-use-after-free.
setopt interactivecomments
# 2: a trap run from inside patmatch() compiles a PAT_STATIC pattern
# (case), reallocating the buffer the interrupted match still uses.
# (Signals stay queued while a function runs; patmatch() runs them.
# The zle -F handler on /dev/zero keeps the match running.)
p="(${(j:|:)${(s: :)${:-$(print -- {1..100}c)}}})"
a=( {1..2000}x )
exec {z}</dev/zero
h() { local c x; read -r -u $1 -k 1 c; for x in ${a:#*${~p}}; do done }
zle -F $z h
trap 'case $RANDOM in (${~p}q|${~p}r) ;; esac; return 130' INT
Src/pattern.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/Src/pattern.c b/Src/pattern.c
index 017c20a1e..7d8bef960 100644
--- a/Src/pattern.c
+++ b/Src/pattern.c
@@ -2714,8 +2714,17 @@ patmatch(Upat prog)
int savpatflags = patflags, savpatglobflags = patglobflags; \
char *savexactpos = exactpos, *savexactend = exactend; \
struct rpat savpattrystate = pattrystate; \
+ char *savpatout = patout; \
+ long savpatalloc = patalloc; \
+ /* prog may live in patout (PAT_STATIC): traps get their own */ \
+ patout = NULL; \
+ patalloc = 0; \
dont_queue_signals(); \
restore_queue_signals(q); \
+ if (patout) \
+ zfree(patout, patalloc); \
+ patout = savpatout; \
+ patalloc = savpatalloc; \
exactpos = savexactpos; \
exactend = savexactend; \
patflags = savpatflags; \
--
2.55.0
Messages sorted by:
Reverse Date,
Date,
Thread,
Author