Skip to content

Commit ac598d2

Browse files
committed
Fix crash in get/getn disciplines; document getn (re: 2a43cbc)
Reproducer: see the test added in tests/variables.sh. Analysis: The global 'struct blocked *blist' variable in nvdisc.c, which is the starting point for all the bp pointers, gets invalidated when the arithmetic subsystem throws an error in the reproducer. Which is obvious, because the struct blocked items in the list are all local/automatic variables in the assign() and lookup() functions, which no longer exist after a longjmp. The root problem is that an error is thrown during the nv_getn() call, so that block_done() is not getting called after the longjmp, so the global blist variable is not reset, causing a probable crash on any subsequent use of a discipline function. src/cmd/ksh93/sh/nvdisc.c: lookup(): - Delay calling nv_getv or nv_getn until after restoring all state, including after calling block_done(). src/cmd/ksh93/sh.1: - Finally add documentation for the getn discipline. Resolves: #435
1 parent 6d69092 commit ac598d2

File tree

5 files changed

+44
-13
lines changed

5 files changed

+44
-13
lines changed

NEWS

+4
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@ This documents significant changes in the 1.0 branch of ksh 93u+m.
22
For full details, see the git log at: https://github.com/ksh93/ksh/tree/1.0
33
Uppercase BUG_* IDs are shell bug IDs as used by the Modernish shell library.
44

5+
2024-08-21:
6+
7+
- Fixed a corner-case crashing bug in shell discipline functions.
8+
59
2024-08-19:
610

711
- Fixed a corner-case bug: for an empty set of positional parameters,

src/cmd/ksh93/include/version.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818

1919
#define SH_RELEASE_FORK "93u+m" /* only change if you develop a new ksh93 fork */
2020
#define SH_RELEASE_SVER "1.0.11-beta" /* semantic version number: https://semver.org */
21-
#define SH_RELEASE_DATE "2024-08-19" /* must be in this format for $((.sh.version)) */
21+
#define SH_RELEASE_DATE "2024-08-21" /* must be in this format for $((.sh.version)) */
2222
#define SH_RELEASE_CPYR "(c) 2020-2024 Contributors to ksh " SH_RELEASE_FORK
2323

2424
/* Scripts sometimes field-split ${.sh.version}, so don't change amount of whitespace. */

src/cmd/ksh93/sh.1

+18-5
Original file line numberDiff line numberDiff line change
@@ -4135,18 +4135,33 @@ file.
41354135
.SS Discipline Functions.
41364136
Each variable can have zero or more discipline functions
41374137
associated with it.
4138-
The shell initially understands the discipline names \f3get\fP,
4139-
\f3set\fP, \f3append\fP, and \f3unset\fP but can be added
4140-
when defining new types. On most systems
4138+
The shell initially understands the discipline names
4139+
\f3get\fP, \f3getn\fP, \f3set\fP, \f3append\fP, and \f3unset\fP,
4140+
but new disciplines can be added
4141+
when defining new types. On most systems,
41414142
others can be added at run time via the
41424143
C programming interface extension provided by the
41434144
.B builtin
41444145
built-in utility.
4146+
.PP
41454147
If the \f3get\fP discipline is defined for a variable, it is invoked
41464148
whenever the given variable is referenced.
41474149
If the variable \f3.sh.value\fP is assigned a value inside
41484150
the discipline function, the referenced variable will evaluate
41494151
to this value instead.
4152+
If the \f3getn\fP discipline is defined for a variable, it is invoked
4153+
in preference to \f3get\fP whenever the given variable is referenced
4154+
in an arithmetic expression.
4155+
The variable \f3.sh.value\fP is assigned the
4156+
.B \-F
4157+
attribute
4158+
inside \f3getn\fP discipline functions
4159+
(see
4160+
.B typeset
4161+
under
4162+
.I "Builtin Commands"
4163+
below).
4164+
Otherwise, it works like it does for \f3get\fP disciplines.
41504165
If the \f3set\fP discipline is defined for a variable, it is invoked
41514166
whenever the given variable is assigned a value.
41524167
If the \f3append\fP discipline is defined for a variable, it is invoked
@@ -4180,7 +4195,6 @@ Finally, the expansion \f3${\fP\f2var\^\fP\f3.\fP\f2name\^\fP\f3}\fP,
41804195
when \f2name\^\fP is the name of a discipline, and there is
41814196
no variable of this name, is equivalent to the command substitution
41824197
\f3${ \fP\f2var\^\fP\f3.\fP\f2name\^\fP\f3;}\fP.
4183-
41844198
.SS Name Spaces.
41854199
Commands and functions that are executed as part of the
41864200
.I list\^
@@ -4220,7 +4234,6 @@ By default, variables starting with
42204234
\fB\s+2.\s-2sh\fP are in the
42214235
.B sh
42224236
name space.
4223-
42244237
.SS Type Variables.
42254238
Typed variables provide a way to create data structure and objects.
42264239
A type can be defined either by a shared library, by the

src/cmd/ksh93/sh/nvdisc.c

+8-7
Original file line numberDiff line numberDiff line change
@@ -434,13 +434,6 @@ static char* lookup(Namval_t *np, int type, Sfdouble_t *dp,Namfun_t *handle)
434434
}
435435
if(nv_isarray(np))
436436
np->nvalue.up = up;
437-
if(!cp)
438-
{
439-
if(type==LOOKUPS)
440-
cp = nv_getv(np,handle);
441-
else
442-
*dp = nv_getn(np,handle);
443-
}
444437
if(bp== &block)
445438
block_done(bp);
446439
if(nq && nq->nvalue.rp && nq->nvalue.rp->running==1)
@@ -451,6 +444,14 @@ static char* lookup(Namval_t *np, int type, Sfdouble_t *dp,Namfun_t *handle)
451444
if(jmpval >= SH_JMPFUN)
452445
siglongjmp(*sh.jmplist,jmpval);
453446
sh_sigcheck();
447+
/* nv_get{v,n} may throw an error and longjmp, so must come after restoring all state */
448+
if(!cp)
449+
{
450+
if(type==LOOKUPS)
451+
cp = nv_getv(np,handle);
452+
else
453+
*dp = nv_getn(np,handle);
454+
}
454455
return cp;
455456
}
456457

src/cmd/ksh93/tests/variables.sh

+13
Original file line numberDiff line numberDiff line change
@@ -1619,5 +1619,18 @@ got=$(set +x; { "$SHELL" -c '
16191619
"(expected status 0, $(printf %q "$exp");" \
16201620
"got status $e$( ((e>128)) && print -n /SIG && kill -l "$e"), $(printf %q "$got"))"
16211621
1622+
# ======
1623+
# https://github.com/ksh93/ksh/issues/435
1624+
"$SHELL" <<\EOF >/dev/null 2>&1; (((e=$?)==1)) || err_exit "getn/get discipline crash" \
1625+
"(expected status 1, got status $e$( ((e>128)) && print -n /SIG && kill -l "$e"))"
1626+
unset nonexistent_var
1627+
foo=nonexistent_var
1628+
foo.getn() { :; }
1629+
foo.get() { :; }
1630+
unset -f foo.getn
1631+
trap 'echo $((foo))' EXIT # throw the echo $((foo)) 'unset parameter' error twice
1632+
echo $((foo))
1633+
EOF
1634+
16221635
# ======
16231636
exit $((Errors<125?Errors:125))

0 commit comments

Comments
 (0)