DEBUG trap is not reset when running a script without a shebang
petrpavlu opened this issue · 0 comments
Description of problem:
When a DEBUG trap is registered in a parent shell and then a child shell is invoked to run a script without a shebang, the DEBUG trap is not reset in the forked shell.
My understanding is that when a subshell is entered, traps should be set to the default actions (POSIX 2004 reference).
Ksh version:
- sh (AT&T Research) 2020.0.0
- Current Git revision: 031d73a.
How reproducible:
Always.
Steps to reproduce:
$ echo "echo test" > test.sh
$ chmod +x test.sh
$ function log_debug { echo "DEBUG ${.sh.command}"; }
$ trap log_debug DEBUG
$ ./test.sh
DEBUG ./test.sh
./test.sh: line 1: log_debug: not found
test
Note: When invoking a script with a proper shebang, the DEBUG trap is reset:
$ cat <<EOF > test2.sh
> #!/bin/ksh
> echo test
> EOF
$ chmod +x test2.sh
$ function log_debug { echo "DEBUG ${.sh.command}"; }
$ trap log_debug DEBUG
$ ./test2.sh
DEBUG ./test2.sh
test
Actual results:
DEBUG trap remains set in a child shell.
Expected results:
DEBUG trap is not set in a child shell.
Additional info:
My understanding is that the following happens when running the above mentioned example test.sh
:
-
Function
path_spawn()
(src/cmd/ksh93/sh/path.c
) is executed to spawn./test.sh
. -
It ends up running the
execve("./test.sh", ...)
syscall which returnsENOEXEC
because of the missing shebang. -
Function
path_spawn()
recognizes this failure and instead forks the running ksh process to execute the script:path_spawn()
->exscript()
. -
Function
exscript()
ends up passing control via a series of long jumps tosh_main()
(src/cmd/ksh93/sh/main.c
) which callssh_reinit()
(src/cmd/ksh93/sh/init.c
). -
Function
sh_reinit()
re-initializes the shell to a clean state. It removes the user-defined functionlog_debug()
and clears also some knowledge of trap handlers, in particular it callssh_sigreset()
. -
Function
sh_sigreset()
contains the following code:for(sig=SH_DEBUGTRAP-1;sig>=0;sig--) { if(trap=sh.st.trap[sig]) { if(mode) free(trap); sh.st.trap[sig] = 0; } }
The loop starts from
SH_DEBUGTRAP-1
and so the DEBUG trap is not reset. -
The script invokes command
echo test
which triggers the debug handler and ksh reports thatlog_debug()
is not available.
Naively, my initial impression was that the above loop should start from SH_DEBUGTRAP
and not SH_DEBUGTRAP-1
because the trap array is declared in src/cmd/ksh93/include/defs.h
as char *trap[SH_DEBUGTRAP+1]
. However, a colleague pointed out to me that this might not be a simple off-by-one error because the code was consciously changed from SH_DEBUGTRAP
to SH_DEBUGTRAP-1
in ksh93t. Unfortunately, it is not clear to me from its changelog why this was done.