Skip to content

Commit b18be74

Browse files
committed
Fix crash on redefining array in subshell (re: 1731f66)
The referenced commit left one test unexecuted because it crashes. Minimal reproducer: typeset -a arr=((a b c) 1) got=$( typeset -a arr=( ( ((a b c)1))) ) The crash occurs when the array is redefined in a subshell. Here are abridged ASan stack traces for the crash, for the use after free, and for when it was freed: ================================================================= ==73147==ERROR: AddressSanitizer: heap-use-after-free [snippage] READ of size 8 at 0x000107403eb0 thread T0 #0 0x104fded40 in nv_search nvdisc.c:1007 #1 0x104fbeb1c in nv_create name.c:860 #2 0x104fb8b9c in nv_open name.c:1440 #3 0x104fb1edc in nv_setlist name.c:309 #4 0x104fb4a30 in nv_setlist name.c:475 #5 0x105055b58 in sh_exec xec.c:1079 #6 0x105045cd4 in sh_subshell subshell.c:654 #7 0x104f92c1c in comsubst macro.c:2266 [snippage] 0x000107403eb0 is located 0 bytes inside of 80-byte region [snippage] freed by thread T0 here: #0 0x105c5ade4 in wrap_free+0x98 (libclang_rt.asan_osx_dynamic.dylib:arm64e+0x3ede4) #1 0x105261da0 in dtclose dtclose.c:52 #2 0x104f178cc in array_putval array.c:671 #3 0x104fd7f4c in nv_putv nvdisc.c:144 #4 0x104fbc5f0 in _nv_unset name.c:2435 #5 0x104fb3250 in nv_setlist name.c:364 #6 0x105055b58 in sh_exec xec.c:1079 #7 0x105045cd4 in sh_subshell subshell.c:654 #8 0x104f92c1c in comsubst macro.c:2266 [snippage] So the crash is caused because array_putval (array.c:671) calls dtclose, freeing ap->table, which is then reused after a recursive nv_setlist call via nv_open() -> nv_create() -> nv_search(). This only happens whwn we're in a virtual subshell. src/cmd/ksh93/sh/array.c: - array_putval(): When redefining an array in a virtual subshell, do not free the old ap->table; it will be needed by the parent shell environment.
1 parent 0460290 commit b18be74

File tree

3 files changed

+8
-9
lines changed

3 files changed

+8
-9
lines changed

NEWS

+3
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ Uppercase BUG_* IDs are shell bug IDs as used by the Modernish shell library.
77
- Fixed a longstanding bug where the default terminal width for typeset -L, -R,
88
or -Z, if not given, was miscalculated for multibyte or control characters.
99

10+
- Fixed a crash on redefining an array inherited from the parent environment
11+
in a subshell.
12+
1013
2024-03-07:
1114

1215
- Fixed a bug that caused some systems to corrupt the display of multibyte

src/cmd/ksh93/sh/array.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -665,7 +665,7 @@ static void array_putval(Namval_t *np, const char *string, int flags, Namfun_t *
665665
{
666666
if(is_associative(ap))
667667
(*ap->fun)(np, NULL, NV_AFREE);
668-
else if(ap->table)
668+
else if(ap->table && (!sh.subshell || sh.subshare))
669669
{
670670
dtclose(ap->table);
671671
ap->table = 0;

src/cmd/ksh93/tests/basic.sh

+4-8
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# #
33
# This software is part of the ast package #
44
# Copyright (c) 1982-2012 AT&T Intellectual Property #
5-
# Copyright (c) 2020-2023 Contributors to ksh 93u+m #
5+
# Copyright (c) 2020-2024 Contributors to ksh 93u+m #
66
# and is licensed under the #
77
# Eclipse Public License, Version 2.0 #
88
# #
@@ -993,7 +993,6 @@ done
993993
# ======
994994
# Nested compound assignment misparsed in $(...) or ${ ...; } command substitution
995995
# https://github.com/ksh93/ksh/issues/269
996-
# TODO: one of the tests below crashes when actually executed; test lexing only by using noexec.
997996
for testcode in \
998997
': $( typeset -a arr=((a b c) 1) )' \
999998
': ${ typeset -a arr=((a b c) 1); }' \
@@ -1008,14 +1007,11 @@ for testcode in \
10081007
'typeset -Ca arr=((a=ah b=beh c=si))' \
10091008
': $( typeset -Ca arr=((a=ah b=beh c=si)) )' \
10101009
'r=${ typeset -Ca arr=((a=ah b=beh c=si)); }' \
1011-
'set --noexec; : $( typeset -a arr=((a $(( $( typeset -a barr=((a $(( 1 << 2 )) c) 1); echo 1 ) << $( typeset -a bazz=((a $(( 1 << 2 )) c) 1); echo 2 ) )) c) 1) )' \
1010+
': $( typeset -a arr=((a $(( $( typeset -a barr=((a $(( 1 << 2 )) c) 1); echo 1 ) << $( typeset -a bazz=((a $(( 1 << 2 )) c) 1); echo 2 ) )) c) 1) )' \
10121011
'r=$(typeset -C arr=( (a=ah b=beh c=si) 1 (e f g)));'
10131012
do
1014-
# fork comsub with 'ulimit' on old ksh to avoid a fixed lexer bug crashing the entire test script
1015-
got=$(let ".sh.version >= 20211209" || ulimit -c 0
1016-
eval "set +x; $testcode" 2>&1) \
1017-
|| err_exit "comsub/arithexp lexing test $(printf %q "$testcode"):" \
1018-
"got status $? and $(printf %q "$got")"
1013+
got=$(export testcode; "$SHELL" -c 'v=$(eval "$testcode" 2>&1); e=$?; print -r -- "$v"; exit $e' 2>&1) \
1014+
|| { e=$?; err_exit "comsub/arithexp lexing test $(printf %q "$testcode"): got status $e and $(printf %q "$got")"; }
10191015
done
10201016
unset testcode
10211017

0 commit comments

Comments
 (0)