Skip to content

Commit

Permalink
Fix $LINENO corruption when autoloading functions
Browse files Browse the repository at this point in the history
Autoloading a function caused the calling script's $LINENO to be
off by the number of lines in the function definition file. In
addition, while running autoloaded functions, errors/warnings were
reported with wrong line numbers.

src/cmd/ksh93/sh/path.c:
- Save $LINENO (shp->inlineno) before autoloading a function, reset
  it to 1 so that the correct line number offset is remembered for
  the function definition, and restore it after.

src/cmd/ksh93/tests/variables.sh:
- Add regression test for $LINENO, directly and in error messages,
  within and outside a non-autoloaded and an autoloaded function.

Fixes: #116
  • Loading branch information
McDutchie committed Oct 1, 2020
1 parent be22f37 commit d89ef0f
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 1 deletion.
4 changes: 4 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ Any uppercase BUG_* names are modernish shell bug IDs.
nonzero exit status. Similarly, if both the 'errexit' and 'pipefail' options
are active, ksh now correctly exits if any pipeline element returns nonzero.

- Autoloading a function no longer causes the calling script's $LINENO to be
off by the number of lines in the function definition file that was loaded.
This also corrects line numbers in warnings and error messages.

2020-09-28:

- While executing a ksh-style function, ksh 93u+ ignored all signals for which
Expand Down
4 changes: 3 additions & 1 deletion src/cmd/ksh93/sh/path.c
Original file line number Diff line number Diff line change
Expand Up @@ -582,7 +582,7 @@ static void funload(Shell_t *shp,int fno, const char *name)
char *pname,*oldname=shp->st.filename, buff[IOBSIZE+1];
Namval_t *np;
struct Ufunction *rp,*rpfirst;
int savestates = sh_getstate(), oldload=shp->funload;
int savestates = sh_getstate(), oldload=shp->funload, savelineno = shp->inlineno;
pname = path_fullname(shp,stakptr(PATH_OFFSET));
if(shp->fpathdict && (rp = dtmatch(shp->fpathdict,(void*)pname)))
{
Expand Down Expand Up @@ -615,6 +615,7 @@ static void funload(Shell_t *shp,int fno, const char *name)
shp->readscript = (char*)name;
shp->st.filename = pname;
shp->funload = 1;
shp->inlineno = 1;
error_info.line = 0;
sh_eval(sfnew(NIL(Sfio_t*),buff,IOBSIZE,fno,SF_READ),SH_FUNEVAL);
sh_close(fno);
Expand All @@ -631,6 +632,7 @@ static void funload(Shell_t *shp,int fno, const char *name)
pname = 0;
free((void*)shp->st.filename);
shp->funload = oldload;
shp->inlineno = savelineno;
shp->st.filename = oldname;
sh_setstate(savestates);
if(pname)
Expand Down
47 changes: 47 additions & 0 deletions src/cmd/ksh93/tests/variables.sh
Original file line number Diff line number Diff line change
Expand Up @@ -1130,5 +1130,52 @@ case $'\n'$(env 'BASH_FUNC_a%%=() { echo test; }' "$SHELL" -c set) in
err_exit 'ksh imports environment variables with invalid names' ;;
esac

# ======
# Autoloading a function caused $LINENO to be off by the # of lines in the function definition file.
# https://github.com/ksh93/ksh/issues/116

cd "$tmp" || exit 128

cat >lineno_autoload <<'EOF'
echo "begin: main script \$LINENO == $LINENO"
function main_script_fn
{
lineno_autoload_fn
(: ${bad\subst\in\main_script_fn\on\line\5})
}
main_script_fn
(eval 'syntax error(')
(: ${bad\subst\in\main\script\on\line\9})
echo "end: main script \$LINENO == $LINENO"
EOF

cat >lineno_autoload_fn <<'EOF'
function lineno_autoload_fn
{
echo "Hi, I'm a function! On line 3, my \$LINENO is $LINENO"
(: ${bad\subst\in\function\on\line\4})
(eval 'syntax error(')
echo "Hi, I'm still a function! On line 6, my \$LINENO is $LINENO"
}
echo "In definition file, outside function: \$LINENO on line 8 is $LINENO"
: ${bad\subst\in\def\file\on\line\9}
EOF

exp="begin: main script \$LINENO == 1
In definition file, outside function: \$LINENO on line 8 is 8
./lineno_autoload[7]: main_script_fn: line 9: \${bad\subst\in\def\file\on\line\9}: bad substitution
Hi, I'm a function! On line 3, my \$LINENO is 3
./lineno_autoload[7]: main_script_fn[4]: lineno_autoload_fn: line 4: \${bad\subst\in\function\on\line\4}: bad substitution
./lineno_autoload[7]: main_script_fn[4]: lineno_autoload_fn[5]: eval: syntax error at line 1: \`(' unexpected
Hi, I'm still a function! On line 6, my \$LINENO is 6
./lineno_autoload[7]: main_script_fn: line 5: \${bad\subst\in\main_script_fn\on\line\5}: bad substitution
./lineno_autoload[8]: eval: syntax error at line 1: \`(' unexpected
./lineno_autoload: line 9: \${bad\subst\in\main\script\on\line\9}: bad substitution
end: main script \$LINENO == 10"

got=$(FPATH=$tmp "$SHELL" ./lineno_autoload 2>&1)
[[ $got == "$exp" ]] || err_exit 'Regression in \$LINENO and/or error messages.' \
$'Diff follows:\n'"$(diff -u <(print -r -- "$exp") <(print -r -- "$got") | sed $'s/^/\t| /')"

# ======
exit $((Errors<125?Errors:125))

0 comments on commit d89ef0f

Please sign in to comment.