Zsh Mailing List Archive
Messages sorted by:
Reverse Date,
Date,
Thread,
Author
[PATCH 4/5] installemulation(): restore static state after the option scan
- X-seq: zsh-workers 55174
- From: Imre Péntek <imre@xxxxxxxxxx>
- To: zsh-workers@xxxxxxx
- Cc: Imre Péntek <imre@xxxxxxxxxx>, "Claude Opus 5.5" <noreply@xxxxxxxxxxxxx>
- Subject: [PATCH 4/5] installemulation(): restore static state after the option scan
- Date: Wed, 23 Sep 2026 19:08:24 +0200
- Archived-at: <https://zsh.org/workers/55174>
- In-reply-to: <20260923170825.501947-1-imre@pentek.dev>
- List-id: <zsh-workers.zsh.org>
- References: <20260923170825.501947-1-imre@pentek.dev>
installemulation() passes its target to setemulate() through the
static variables setemulate_emulation and setemulate_opts. A trap run
during scanhashtable() that itself uses "emulate" (every powerlevel10k
function starts with "emulate -L zsh") overwrites them with a pointer
into its own, soon dead, stack frame; the outer scan then writes the
option settings there (AddressSanitizer: stack-use-after-return in
setemulate()).
Save the previous values and restore them after the scan.
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),
AddressSanitizer reports stack-use-after-return in setemulate().
setopt interactivecomments
# 4: a trap's "emulate" run during another emulate's option scan leaves
# the outer scan writing to the finished call's stack frame.
# (Builtins run with signals unqueued: the trap runs mid-scan.
# The zle -F handler on /dev/zero keeps emulate running.)
exec {z}</dev/zero
h() { local c; read -r -u $1 -k 1 c; repeat 20 emulate -L zsh }
zle -F $z h
t() { emulate -L zsh -o extendedglob }
trap 't; return 130' INT
Src/options.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/Src/options.c b/Src/options.c
index 9bf56cf81..b7213ff54 100644
--- a/Src/options.c
+++ b/Src/options.c
@@ -522,10 +522,16 @@ setemulate(HashNode hn, int fully)
void
installemulation(int new_emulation, char *new_opts)
{
+ /* a trap run during the scan may emulate too: restore for our caller */
+ int sav_emulation = setemulate_emulation;
+ char *sav_opts = setemulate_opts;
+
setemulate_emulation = new_emulation;
setemulate_opts = new_opts;
scanhashtable(optiontab, 0, 0, 0, setemulate,
!!(new_emulation & EMULATE_FULLY));
+ setemulate_emulation = sav_emulation;
+ setemulate_opts = sav_opts;
}
/**/
--
2.55.0
Messages sorted by:
Reverse Date,
Date,
Thread,
Author