From d7cada7b2e81a63cf2003b97ff6472c07c506b33 Mon Sep 17 00:00:00 2001 From: Martijn Dekker Date: Sun, 7 Nov 2021 22:27:02 +0000 Subject: [PATCH] xtrace: fix restore of standard error stream state The sh_trace() function, which prints an xtrace line to standard error, clears the SF_SHARE and SF_PUBLIC flags from the sfstderr stream during the xtrace in order to guarantee an atomic trace write. But it only restored those flags if the passed argv pointer is non-NULL. Redirections are traced with a NULL argv parameter, so the stderr state was not restored for them. This somehow caused unpredictable behaviour, including (on some systems) a crash in sfwrite(3) when running the heredoc.sh tests with xtrace on. src/cmd/ksh93/sh/xec.c: sh_xtrace(): - Move the sfset() invocation that restores the SF_SHARE|SF_PUBLIC flags to sfstderr out of the if(argv) block. - Since we're here, don't bother wasting cycles initialising local variable values if xtrace is not on. Move that inside the if(sh_isoption(SH_XTRACE)) block. Resolves: https://github.com/ksh93/ksh/issues/306 --- src/cmd/ksh93/sh/xec.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/cmd/ksh93/sh/xec.c b/src/cmd/ksh93/sh/xec.c index 1a9898156..c61d3edcc 100644 --- a/src/cmd/ksh93/sh/xec.c +++ b/src/cmd/ksh93/sh/xec.c @@ -2795,12 +2795,12 @@ int sh_run(int argn, char *argv[]) int sh_trace(Shell_t *shp,register char *argv[], register int nl) { - register char *cp; - register int bracket = 0; - int decl = (nl&2); - nl &= ~2; if(sh_isoption(SH_XTRACE)) { + register char *cp; + register int bracket = 0; + int decl = (nl&2); + nl &= ~2; /* make this trace atomic */ sfset(sfstderr,SF_SHARE|SF_PUBLIC,0); if(!(cp=nv_getval(sh_scoped(shp,PS4NOD)))) @@ -2836,8 +2836,8 @@ int sh_trace(Shell_t *shp,register char *argv[], register int nl) } sfputr(sfstderr,cp,*argv?' ':nl); } - sfset(sfstderr,SF_SHARE|SF_PUBLIC,1); } + sfset(sfstderr,SF_SHARE|SF_PUBLIC,1); return(1); } return(0);