1
0
Fork 0
mirror of git://git.code.sf.net/p/cdesktopenv/code synced 2025-02-13 19:52:20 +00:00
Commit graph

1112 commits

Author SHA1 Message Date
Martijn Dekker
143ff27a91 emacs: fix keys w/ repeat parameters repeating extra (re: 29b11bba)
@JohnoKing writes:
> In emacs mode, using Alt+D or Alt+H with a repeat parameter
> results in the deletion of extra characters. Reproducer:
>
> $ set -o emacs
> $ foo bar delete add   # <Ctrl+A> <ESC+3+Alt+D>
> $ d  # Should be ' add'
>
> $ foo bar delete add   # <ESC+3+Alt+H>
> $ f  # Should be 'foo '
>
> [...] this bug also affects the Delete and Arrow keys [...].
> Reproducer:
>
> $ test_string <Ctrl+A> <ESC+3+Delete>
>	# This will delete all of 'test', which is four characters
> $ test_string <Ctrl+A> <ESC+4+Right Arrow>
>	# This should move the cursor to '_', not 's'

src/cmd/ksh93/edit/emacs.c: ed_emacsread():
- Revert part of 29b11bba: once again set 'count' to
  'vt220_save_repeat' instead of adding the value.
- do_escape: If the escape() function (which handles both ESC
  repeat counts and commands like ESC d and ESC h) returns a repeat
  count, do not use the saved repeat count for v220 sequences.

src/cmd/ksh93/tests/pty.sh:
- Test the four reproducers above.

Fixes: https://github.com/ksh93/ksh/issues/292
2021-05-04 05:10:32 +01:00
Martijn Dekker
da4bf85f27 COMPATIBILITY: update to 93u+ entry re: 5ed9ffd6, 9f2066f1 2021-05-04 03:14:05 +01:00
hyenias
642a105351
Fix arithmetic assignment operations for multidimensional indexed arrays (#296)
This PR corrects #168 for indexed arrays having more than one
level. Turns out ksh was only keeping track of the subscript number
for assignment in lvalue's nosub variable. By saving the actual
subscript reference, the result can be assigned to its proper
destination instead of putting the result into the last looked
value or subscript location.

src/cmd/ksh93/include/streval.h: struct lval:
- Create a new pointer named sub to hold the reference that nosub
  describes.

src/cmd/ksh93/sh/arith.c: arith():
- Adjust LOOKUP: for lvalue ARITH_ASSIGNOP operations on indexed
  arrays to save the np of the destination subscript for later use.
- Adjust ASSIGN: to act when lvalue's nosub > 0 which happens as
  the last step in the arithmetic parsing loop for assignment
  operations. Only indexed arrays will have a nosub value > 0. All
  others have a nosub of 0 unless they are involved in a unary
  operation (++, --) which sets nosub to -1. All said in the
  context of assignment operations like (( arr[0][1] += 1 )).

src/cmd/ksh93/sh/streval.c:
- Initialize the new sub pointer to 0.

src/cmd/ksh93/tests/arrays2.sh:
- Created a few multidimensional indexed array tests for assignment
  operations like += as an example.

Resolves: https://github.com/ksh93/ksh/issues/168
2021-05-04 03:13:14 +01:00
Martijn Dekker
d309d604e7 POSIX: 'command': don't disable declaration proprts (re: b9d10c5a)
Following the resolution of Austin Group bug 1393[*] that is set to
be included in the next version of the POSIX standard, the
'command' prefix in POSIX mode (set -o posix) no longer disables
the declaration properties of declaration built-ins.
[*] https://austingroupbugs.net/view.php?id=1393

src/cmd/ksh93/sh/parse.c: lex():
- Skip the 'command' prefix even in POSIX mode so that any
  declaration commands prefixed by it are treated as such in xec.c
  (sh_exec()).

src/cmd/ksh93/sh/xec.c: sh_exec():
- The foregoing change reintroduced a variant of BUG_CMDSPEXIT: the
  shell exits on something like 'command export readonlyvar=foo'.
  This now fixes that bug for both POSIX and non-POSIX mode. When
  calling nv_setlist() to process true shell assignments, and there
  is a 'command' prefix, push a shell context and use sigsetjmp to
  intercept any errors in assignments and stop the shell exiting.

src/cmd/ksh93/tests/builtins.sh:
- Borrow the BUG_CMDSPEXIT regression test from modernish and adapt
  it for ksh. (I'm the author so yes, I can do this.) Original:
  https://github.com/modernish/modernish/blob/ae8fe9c3/lib/modernish/tst/builtin.t#L80-L109
2021-05-04 00:52:10 +01:00
Martijn Dekker
1a1e3709c2 tests/subshell.sh: replace use of unportable seq command 2021-05-03 21:51:03 +01:00
Martijn Dekker
7a2d3564b6 emacs/vi: Fix <Tab> behaviour after command substitution
Tab completion in emacs and vi wrongly parses and executes command
substitutions. Example reproducers:

  $ $(~)<Tab>		# Result:
  $ $(~)ksh[1]: /home/johno: cannot execute [Is a directory]

  $ $(~ksh)<Tab>	# Result:
  $ $(~ksh)ksh: /home/johno/GitRepos/KornShell/ksh: cannot execute [Is a directory]

  $ $(echo true)<Tab>	# Result:
  $ /usr/bin/true	# or just 'true' -- it's unpredictable

In addition, backtick command substitutions had the following bug:

  $ `echo hi`<Tab>	# Result:
  $ `echo hi`ksh: line 1: BUG_BRACQUOT_test.sh: not found

(where BUG_BRACQUOT_test.sh happens to be lexically the
first-listed file in my ksh development working directory).

There's also a crash associated with this due to an access beyond
buffer boundaries, which is only triggered on some systems (macOS
included).

src/cmd/ksh93/edit/completion.c:
- find_begin():
  * When finding the beginning of a command substitution and the
    last character is ')', do not increase the character pointer
    cp. Increasing it caused the condition 'if(c && c==endchar)' in
    the 'default:' block to be true, causing 'return(xp);' to be
    executed, which returns a pointer the beginning of the command
    substitution to ed_expand() on line 290, so that ed_expand()
    eventually executes the command substitution with the
    sh_argbuild() call on line 349. After deleting this 'else
    cp++', that statement 'if(c && c==endchar) return(xp);' is not
    executed and `find_begin()` returns the null pointer, which
    avoids anything being executed. Thanks to @JohnoKing:
    https://github.com/ksh93/ksh/issues/268#issuecomment-817249164
  * Add code for properly skipping over backtick-style command
    substitutions, based on the $( ) code.
- ed_expand(): Avoid out[-1] reading one byte to the left of
  outbuff by first checking that out>outbuff. Thanks to @JohnoKing
  for using ASan to find the location of the crash:
  https://github.com/ksh93/ksh/issues/268#issuecomment-825574885

src/cmd/ksh93/tests/pty.sh:
- Test for the bugs detailed above.

Resolves: https://github.com/ksh93/ksh/issues/268
2021-05-03 18:49:10 +01:00
Martijn Dekker
33269cae61 tests/variables.sh: fix ( echo $RANDOM & ) test (re: af6a32d1)
On slower systems it could fail with an arithmetic syntax error
because the output was verified before it had been written.

Also make another test xtrace-proof.
2021-05-03 18:14:34 +01:00
Martijn Dekker
6d54faf9f5 tests/leaks.sh: fix intermittent fails on Gentoo (re: 005d38f41)
This applies when ksh is compiled with standard malloc.

Apparently, 1024 iterations is not enough on Gentoo Linux i386, at
least not when running the full test suite. The leak tests fail
intermittently and different tests fail each time, but always with
a leak of exactly 36864 bytes for each failing test. So those
failures are clearly spurious. Doubling the number of iterations
seems to make them go away.
2021-05-03 16:55:42 +01:00
Martijn Dekker
dd5455ac5f tests/io.sh: fix spurious failure on Gentoo i386 (re: c4f980eb) 2021-05-03 16:38:37 +01:00
Johnothan King
d5b94a3ff8
Fix some bugs in the regression tests and add more regression tests (#295)
src/cmd/ksh93/tests/{basic.sh,builtins.sh,shtests}:
- Redirect error output from the ulimit builtin to silence irrelevant
  errors in the regression tests (these errors may occur when a
  command such as 'ulimit -t 4' is run before the regression tests).
- Shellquote the error messages from the getconf regression tests.

src/cmd/ksh93/tests/{arrays,io,variables}.sh:
- Backport the ksh2020 regression tests for the following bugs:
  https://github.com/att/ast/issues/23
  https://github.com/att/ast/issues/203
  https://github.com/att/ast/issues/472
  https://github.com/att/ast/issues/492
- Minor fix to POSIX mode regression tests in ksh93v-. In ksh93v-,
  [[ -o ?posix ]] doesn't return an error (because it's implemented
  in the bash mode). However, 'set -o posix' will fail in ksh93v-
  if it's not in bash compatibility mode, which causes this test
  script to exit prematurely.

src/cmd/ksh93/tests/{basic,pty}.sh:
- Add test for https://github.com/att/ast/issues/1461
- The ksh2020 fix for [ -t 1 ] in non-forking command substitutions
  caused the following bug in interactive shells:
    $ ( [ -t 1 ]; echo $? )
    1  # Always fails
  To avoid introducing this bug, this commit adds a regression
  test for it.

src/cmd/ksh93/tests/functions.sh:
- Add test for https://github.com/att/ast/issues/1160
  Put the test to the start of functions.sh (if it's at the end
  of the script, it refuses to fail under ksh2020). Output from
  this regression test when run against ksh2020:
    functions.sh[46]: eval'ing function dumps function body to
    stdout (got $' { eval "bar() { FAILURE; }"; }\n { FAILURE; }')
2021-05-03 06:52:27 +01:00
Martijn Dekker
5ed4c71fca Fix regression caused by ${var:-'{}'} fix (re: f31e3687)
The regression is:

  quoting.sh[189]: expansion of "{q:+'}" not correct when q unset

The failure was that, for unset q, "${q:+'}q${q:+'}" yielded empty
and not 'q'. This is because the single quotes within the double
quotes were erroneously parsed as meaningful.

The originally used ST_QUOTE state table (see data/lexstates.c),
where no quote character has any special meaning, was for avoiding
this problem.

The newly introduced ST_MOD1 state table is a copy of ST_QUOTE
except the ' has been given its special meaning back. We need this
to fix #290, but only for unquoted expansions.

So we need to go back to using ST_QUOTE if the string is quoted
(mp->quote) and we're not parsing a substitution that uses patterns
where quotes are significant (newops, ST_MOD2), i.e., only for
old-style ST_MOD1 operators.

src/cmd/ksh93/sh/macro.c: varsub():
- When the ${var<OP>string} expansion is quoted, and of an old
  (S_MOD1) type, then use the ST_QUOTE state table to skip over it
  instead of the new ST_MOD1 one.
2021-05-03 05:55:47 +01:00
Martijn Dekker
af6a32d14f
Fix $RANDOM to act consistently in subshells (#294)
This fixes the following:
1. Using $RANDOM in a virtual/non-forked subshell no longer
   influences the reproducible $RANDOM sequence in the parent
   environment.
2. When invoking a subshell $RANDOM is now re-seeded (as mksh and
   bash do) so that invocations in repeated subshells (including
   forked subshells) longer produce identical sequences by default.
3. Program flow corruption that occurred in scripts on executing
   ( ( simple_command & ) ).

src/cmd/ksh93/include/variables.h:
- Move 'struct rand' here as it will be needed in subshell.c. Add
  rand_seed member to save the pseudorandom generator seed. Remove
  the pointer to the shell state as it's redundant.

src/cmd/ksh93/sh/init.c:
- put_rand(): Store given seed in rand_seed while calling srand().
  No longer pointlessly limit the number of possible seeds with the
  RANDMASK bitmask (that mask is to limit the values to 0-32767,
  it should not limit the number of possible sequences to 32768).
- nget_rand(): Instead of using rand(), use rand_r() to update the
  random_seed value. This makes it possible to save/restore the
  current seed of the pseudorandom generator.
- Add sh_reseed_rand() function that reseeds the pseudorandom
  generator by calling srand() with a bitwise-xor combination of
  the current PID, the current time with a granularity of 1/10000
  seconds, and a sequence number that is increased on each
  invocation.
- nv_init(): Set the initial seed using sh_reseed_rand() here
  instead of in sh_main(), as this is where the other struct rand
  members are initialised.

src/cmd/ksh93/sh/main.c: sh_main():
- Remove the srand() call that was replaced by the sh_reseed_rand()
  call in init.c.

src/cmd/ksh93/sh/subshell.c: sh_subshell():
- Upon entering a virtual subshell, save the current $RANDOM seed
  and state, then reseed $RANDOM for the subshell.
- Upon exiting a virtual subshell, restore $RANDOM seed and state
  and reseed the generator using srand() with the restored seed.

src/cmd/ksh93/sh/xec.c: sh_exec():
- When optimizing out a subshell that is the last command, still
  act like a subshell: reseed $RANDOM and increase ${.sh.subshell}.
- Fix a separate bug discovered while implementing this. Do not
  optimize '( simple_command & )' when in a virtual subshell; doing
  this causes program flow corruption.
- When optimizing '( simple_command & )', also reseed $RANDOM and
  increment ${.sh.subshell}.

src/cmd/ksh93/tests/subshell.sh,
src/cmd/ksh93/tests/variables.sh:
- Add various tests for all of the above.

Co-authored-by: Johnothan King <johnothanking@protonmail.com>
Resolves: https://github.com/ksh93/ksh/issues/285
2021-05-03 04:03:46 +01:00
Martijn Dekker
f31e368795 Fix remaining bug in ${var:-'{}'} (re: d087b031)
The following problems remained:

$ var=x; echo ${var:-'{}'}
x}
$ var=; echo ${var:+'{}'}
}

src/cmd/ksh93/sh/macro.c: varsub():
- Use the new ST_MOD1 state table to skip over ${var-'foo'}, etc.
  instead of ST_QUOTE. In ST_MOD1 the ' is categorised as S_LIT
  which causes the single quotes to be skipped over correctly.
  See d087b031 for more info.

src/cmd/ksh93/tests/quoting2.sh:
- Add tests for this remaining bug.
- Make the new test xtrace-proof.

Resolves: https://github.com/ksh93/ksh/issues/290 (again)
2021-05-03 03:14:30 +01:00
Johnothan King
1aec9b06dd
Fix more bugs that occur when enabling ASan (#293)
src/cmd/ksh93/{bltins/typeset,sh/name,sh/nvtree,sh/nvtype}.c:
- Replace more instances of memcmp with strncmp to fix
  heap-buffer-overflow errors when running the regression tests
  with ASan enabled.

src/cmd/ksh93/edit/vi.c:
- Fix an invalid dereference of the 'p' pointer to fix a crash in
  vi mode when entering a comment in the command history. This
  bugfix was backported from ksh2020:
  https://github.com/att/ast/issues/798

src/cmd/ksh93/tests/pty.sh:
- Add a regression test for the vi mode crash.
2021-05-02 04:06:30 +01:00
Martijn Dekker
88a1f3d661 Fork before entering shared-state command substitution
The code contains various checks to see if a subshell needs to
fork, like this one in the ulimit builtin:

	if(shp->subshell && !shp->subshare)
		sh_subfork();

All checks of this form are fatally broken, as each one of them
causes shared-state command substitutions to ignore parent virtual
subshells.

Currently the only feasible way to fix this is to fork a virtual
subshell before executing a shared-state command substitution in
it. In the long term I think shared-state command substitutions
should probably be redesigned to disassociate them completely from
the virtual subshell mechanism.

src/cmd/ksh93/sh/macro.c: comsubst():
- If we're in a non-subshare virtual subshell, fork it before
  entering a type 2 (subshare) command substitution.

src/cmd/ksh93/sh/subshell.c:
- sh_assignok(): Remove subshare fix from 911d6b06 as it's
  redundant now that the parent of a subshare is never a virtual
  subshell. Go back to not doing anything if the current "subshell"
  is a subshare.
- sh_subtracktree(), sh_subfuntree(): Similarly, remove the
  now-redundant subshare fixes from 13c57e4b.

src/cmd/ksh93/sh/xec.c: sh_exec():
- Fix a separate bug: only fork a virtual subshell before running a
  background job if that "subshell" is not a subshare.

src/cmd/ksh93/tests/subshell.sh:
- Add test for bug fixed in xec.c.
- Add tests for 'ulimit', 'builtin' and 'exec' run in subshare
  within subshell -- all commands that use checks of the form
  'if(sh.subshell && !sh.subshare) sh_subfork();'.

Resolves: https://github.com/ksh93/ksh/issues/289
2021-05-01 00:47:39 +01:00
Martijn Dekker
72fe631b2f typeset: only run sh_assignok() for variables (re: a2f13c19)
src/cmd/ksh93/bltins/typeset.c:
- setall(): Only run sh_assignok() if troot points to the variable
  tree. For instance, it's pointless to run it for an alias.
- Remove vestigial SHOPT_BSH code. The ast-open-history repo shows
  that earlier SHOPT_BSH code was removed on 2008-06-02 and
  2005-05-22. This may have been experimental code for increased
  compatibility with the ancient Bourne shell. There was never any
  documentation.
2021-05-01 00:43:12 +01:00
Govind Kamat
7439e3dffe Parse quotes when extracting words from command history (#291)
This avoids splitting on quoted whitespace when extracting words
from the command history using the emacs M-. or vi _ command.

Example: if the prior command is

$ ls Stairway\ To\ Heaven.mp3

then, M-. in Emacs editing mode (and _ in vi mode) now inserts
Stairway\ To\ Heaven.mp3 instead of Heaven.mp3. The behavior is
similar for 'Stairway To Heaven.mp3' and "Stairway To Heaven.mp3".

src/cmd/ksh93/edit/history.c: hist_word():
- Skip over single-quoted and double-quoted strings and
  backslash-escaped characters.

src/cmd/ksh93/tests/pty.sh:
- Add regression test for this feature in vi mode. Since emacs and
  vi both use the same code for this, that should be good enough.

Co-authored-by: Martijn Dekker <martijn@inlv.org>
2021-04-30 20:18:07 +01:00
Martijn Dekker
d087b031f0 Fix single quotes in expansion operator string (re: 5ed9ffd6)
The referenced commit introduced the following bug:

> The closing quote does not appear to be registering during the
> parse of the following:
>
>	echo ${var:+'{}'}
>
> Within a script, this will result in:
>
>	syntax error at line 1: `'' unmatched

src/cmd/ksh93/data/lexstates.c,
src/cmd/ksh93/include/lexstates.h:
- Add new ST_MOD1 state table that is a copy of ST_QUOTE, but adds
  a special meaning (ST_LIT) for the single quote (position 39).

src/cmd/ksh93/sh/lex.c: sh_lex():
- For parameter expansion operators with old-style quoting
  (S_MOD1), use the new ST_MOD1 state table instead of ST_QUOTE.
  This causes single quotes within them to be processed properly.

src/cmd/ksh93/tests/quoting2.sh:
- Add tests.

Thanks to @gkamat for the bug report.
Resolves: https://github.com/ksh93/ksh/issues/290
2021-04-30 05:28:21 +01:00
Martijn Dekker
090b65e79b Fix fork after redirecting stdout in subshare (re: 500757d7)
Previously, command substitutions executed as virtual subshells
were always forked if any command was run within them that
redireceted standard output, even if the redirection was local to
that command.

Commit 500757d7 removed the check for a shared-state command
substitution (subshare), so introduced a bug where even that would
fork, causing it to stop sharing its state.

We can further improve on that fix by only forking if the
redirection is permanent as with `exec` or `redirect`. There should
be no need to do that if the redirection is local to a command run
within the command substitution, as the file descriptor is restored
when that command finishes, which is still within the command
substitution.

src/cmd/ksh93/sh/io.c: sh_redirect():
- Only fork upon redirecting stdout if the virtual subshell is a
  command substitution, and if the redirection is permanent
  (flag==1 or flag==2).
2021-04-26 18:22:17 +01:00
Martijn Dekker
2aad3cab06 Add ksh 93u+m contributors notice to 964 copyright headers 2021-04-26 00:19:31 +01:00
Johnothan King
1d9093e603
Add support for process substitutions to the deparser (#288)
Like tdump() and trestore() before commit 32d1abb1, sh_deparse() fails
to handle process substitutions correctly. This limitation of the shell
deparser is rather minor since it's unused. However, seeing as the
deparser was left in the code base intentionally it should at least
function properly.

src/cmd/ksh93/sh/deparse.c:
- Add a PROCSUBST flag for handling process substitutions in
  sh_deparse().
- If we're handling a process substitution, add an ending ')'
  without an extra newline.
- Avoid adding an extra ' &' to commands inside of a process
  substitution. An extra ' &' is only added if the FAMP and FINT
  flags are set, which indicates the command was spawned as a separate
  job with '&'.
- Add process substitution handling to 'p_redirect' by calling p_tree()
  when encountering a process substitution.
2021-04-26 00:12:29 +01:00
Martijn Dekker
295cce2c6d Improve fix for 'unset -f' in sub-subshell (re: 07faf384, 13c57e4b)
src/cmd/ksh93/bltins/typeset.c:
- Removing the nv_search() call altogether was actually not
  neccessary, I was just searching the wrong tree: instead of
  sh.fun_base, simply search the current sh.fun_tree which has a
  view to all the layered parent subshell copes. It is not going to
  find it in the current subshell tree but will find it in one of
  the parent trees if it exists. The cost of an unnecessary dummy
  is negligible, but so is the cost of this search, and doing it is
  more correct.
2021-04-24 21:26:17 +01:00
Johnothan King
24b7fcb771
Don't detect unset functions with whence (re: 13c57e4b) (#287)
src/cmd/ksh93/bltins/whence.c:
- The previous commit that fixed 'unset -f' in virtual subshells left
  one bug. The type builtin (or 'whence -v') could still find the unset
  function in virtual subshells:
    $ foo() { echo foo; }
    $ (unset -f foo; type foo)
    foo is an undefined function
  To fix this bug, avoid detecting functions in the whence builtin
  unless they have the NV_FUNCTION flag.

src/cmd/ksh93/tests/subshell.sh:
- Add a regression test for using 'type' on a function unset inside of
  a virtual subshell.
2021-04-24 21:25:45 +01:00
Martijn Dekker
07faf38425 Fix 'unset -f' in sub-subshell (re: 13c57e4b)
A bug introduced in the previous commit caused 'unset -f' in a
subshell of a subshell to fail to unset a function created in a
parent subshell. Reproducer:

$ ( f2() { echo WRONG; }; ( unset -f f2; f2 ) )
WRONG

src/cmd/ksh93/bltins/typeset.c: unall():
- Do not nv_search() in sh.fun_base before setting the dummy node
  that marks the function as unset in this subshell. That search
  only reaches the base tree and not any of its subtrees. Setting
  the dummy unconditionally is not harmful; the cost is negligible.

src/cmd/ksh93/tests/subshell.sh:
- Add test for the bug.
2021-04-24 12:41:40 +01:00
Martijn Dekker
13c57e4b58 Fix 'unset -f' to work in subshells without forking (re: 047cb330)
This commit implements unsetting functions in virtual subshells,
removing the need for the forking workaround. This is done by
either invalidating the function found in the current subshell
function tree by unsetting its NV_FUNCTION attribute bits (which
will cause sh_exec() to skip it) or, if the function exists in a
parent shell, by creating an empty dummy subshell node in the
current function tree without that attribute.

As a beneficial side effect, it seems that bug 228 (unset -f fails
in forked subshells if a function is defined before forking) is now
also fixed.

src/cmd/ksh93/include/defs.h,
src/cmd/ksh93/sh/init.c:
- Add sh.fun_base for a saved pointer to the main shell's function
  tree for checking when in a subshell, analogous to sh.var_base.

src/cmd/ksh93/bltins/typeset.c: unall():
- Remove the fork workaround.
- When unsetting a function found in the current function tree
  (troot) and that tree is not sh.var_base (which checks if we're
  in a virtual subshell in a way that handles shared-state command
  substitutions correctly), then do not delete the function but
  invalidate it by unsetting its NV_FUNCTION attribute bits.
- When unsetting a function not found in the current function tree,
  search for it in sh.fun_base and if found, add an empty dummy
  node to mask the parent shell environment's function. The dummy
  node will not have NV_FUNCTION set, so sh_exec() will skip it.

src/cmd/ksh93/sh/subshell.c:
- sh_subfuntree(): For 'unset -f' to work correctly with
  shared-state command substitutions (subshares), this function
  needs a fix similar to the one applied to sh_assignok() for
  variables in commit 911d6b06. Walk up on the subshells tree until
  we find a non-subshare.
- sh_subtracktree(): Apply the same fix for the hash table.
- Remove table_unset() and incorporate an updated version of its
  code in sh_subshell(). As of ec888867, this function was only
  used to clean up the subshell function table as the alias table
  no longer exists.
- sh_subshell():
  * Simplify the loop to free the subshell hash table.
  * Add table_unset() code, slightly refactored for readability.
    Treat dummy nodes now created by unall() separately to avoid a
    memory leak; they must be nv_delete()d without passing the
    NV_FUNCTION bits. For non-dummy nodes, turn on the NV_FUNCTION
    attribute in case they were invalidated by unall(); this is
    needed for _nv_unset() to free the function definition.

src/cmd/ksh93/tests/subshell.sh:
- Update the test for multiple levels of subshell functions to test
  a subshare as well. While we're add it, add a very similar test
  for multiple levels of subshell variables that was missing.
- Add @JohnoKing's reproducer from #228.

src/cmd/ksh93/tests/leaks.sh:
- Add leak tests for unsetting functions in a virtual subshell.
  Test both the simple unset case (unall() creates a dummy node)
  and the define/unset case (unall() invalidates existing node).

Resolves: https://github.com/ksh93/ksh/issues/228
2021-04-24 06:57:49 +01:00
Johnothan King
086d504393
Lots of man page fixes and some other minor fixes (#284)
Noteworthy changes:
- The man pages have been updated to fix a ton of instances of
  runaway underlining (this was done with `sed -i 's/\\f5/\\f3/g'`
  commands). This commit dramatically increased in size because
  of this change.
- The documentation for spawnveg(3) has been extended with
  information about its usage of posix_spawn(3) and vfork(2).
- The documentation for tmfmt(3) has been updated with the changes
  previously made to the man pages for the printf and date builtins
  (though the latter builtin is disabled by default).
- The shell's tracked alias tree (hash table) is now documented in
  the shell(3) man page.
- Removed the commented out regression test for an ERRNO variable
  as the COMPATIBILITY file states it was removed in ksh93.
2021-04-23 22:02:30 +01:00
Johnothan King
2c22ace1e6
Fix LINENO after unsetting it a virtual subshell (#283)
There is a TODO note in variables.sh that notes the value of LINENO
is wrong after a virtual subshell. The following script should
print '6', but the bug causes it to print '1' instead:
  $ cat /tmp/lineno
  #!/bin/ksh
  (
      unset LINENO
      :
  )
  echo $LINENO

This bug started to occur after the bugfix applied in 7b994b6a.
However, that commit is not where the cause of bug was (when that
bugfix is applied to ksh versions 2008-07-25 through 2012-01-01,
$LINENO works fine). Rather, the cause of this bug was introduced
in 93u+ 2012-02-29. In that version, the mp->nvfun pointer was only
copied from np->nvfun if the variable can be freed from memory.
This is what caused 7b994b6a to break $LINENO in subshells, so to
fix this bug the mp->nvfun and np->nvfun must point to the same
object, even when the variable isn't freed from memory.

src/cmd/ksh93/sh/subshell.c: nv_restore():
- Always copy the np->nvfun pointer to mp->nvfun. To prevent
  crashes, the value of np->nvfun->nofree is set to the value given
  by the nofree variable, which is set before _nv_unset. See also
  commit 7e7f1372, which fixed a crash that happened because
  _nv_unset discards the NV_NOFREE flag.

src/cmd/ksh93/tests/variables.sh:
- Remove the workaround for LINENO after a virtual subshell.
- Add a regression test for the value of LINENO when unset in a
  virtual subshell, then used after the subshell. Note that before
  commit 997ad43b LINENO's value was corrupted after being unset in
  a subshell, so the test checks for corruption of the LINENO
  variable (in prior commits LINENO was set to '49' because of the
  previous bug).
2021-04-22 19:16:25 +01:00
Johnothan King
01c01fe8f6
Fix buffer overflows and memory leaks caught by ASAN (#282)
The changes in this commit allow ksh to be built and run with
ASan[*], although for now it only works under vmalloc. Example
command to build ksh with ASan:
$ bin/package make CCFLAGS='-O0 -g -fsanitize=address'

[*] https://en.wikipedia.org/wiki/AddressSanitizer

src/cmd/INIT/mamake.c:
- Fix a few memory leaks in mamake. This doesn't fix all of the
  memory leaks ASan complains about (there is one remaining in the
  view() function), but it's enough to get ksh to build under ASan.

src/lib/libast/features/map.c,
src/lib/libast/misc/glob.c:
- Rename the ast globbing functions to _ast_glob() and
  _ast_globfree(). Without this change the globbing tests fail
  under ASan. See: https://github.com/att/ast/commit/2c49eb6e

src/cmd/ksh93/sh/{init,io,nvtree,subshell}.c:
- Fix buffer overflows by using strncmp(3) instead of memcmp(3).

src/cmd/ksh93/sh/name.c:
- Fix another invalid usage of memcmp by using strncmp instead.
  This change is also in one of Red Hat's patches:
  https://git.centos.org/rpms/ksh/blob/c8s/f/SOURCES/ksh-20120801-nv_open-memcmp.patch

Resolves: https://github.com/ksh93/ksh/issues/230
2021-04-22 18:13:12 +01:00
Martijn Dekker
9530f09b08 Disable SHOPT_EDPREDICT compile-time option by default
It's experimental, undocumented, at least somewhat broken, and gets
in the way if you type a comment. Should not be enabled by default,
at least not until someone steps up to fix it properly.

This commit also updates the descriptions of the option to clarify
that this provides a pattern-based history search menu. "Predictive
editing" is a misnomer as this does not predict anything.

Note that Solaris already disables it by default:
https://github.com/oracle/solaris-userland/blob/master/components/ksh93/patches/165-CR7186440_ksh93_disable_predictive_editing.patch

Discussion: https://github.com/ksh93/ksh/issues/233
2021-04-22 17:37:12 +01:00
Martijn Dekker
32d1abb1ba shcomp: fix redirection with process substitution
The commands within a process substitution used as an argument to a
redirection (e.g. < <(...) or > >(...)) are simply not included in
parse trees dumped by shcomp. This can be verified with a command
like hexdump -C. As a result, these process substitutions do not
work when running a bytecode-compiled shell script.

The fix is surprisingly simple. A process substitution is encoded
as a complete parse tree. When used with a redirection, that parse
tree is used as the file name for the redirection. All we need to
do is treat the "file name" as a parse tree instead of a string if
flags indicate a process substitution.

A process substitution is detected by the struct ionod field
'iofile'. Checking the IOPROCSUB bit flag is not enough. We also
need to exclude the IOLSEEK flag as that form of redirection may
use the IOARITH flag which has the same bit value as IOPROCSUB (see
include/shnodes.h).

src/cmd/ksh93/sh/tdump.c: p_redirect():
- Call p_tree() instead of p_string() for a process substitution.

src/cmd/ksh93/sh/trestore.c: r_redirect():
- Call r_tree() instead of r_string() for a process substitution.

src/cmd/ksh93/include/version.h:
- Bump the shcomp binary header version as this change is not
  backwards compatible; previous trestore.c versions don't know how
  to read the newly compiled process substitutions and would crash.

src/cmd/ksh93/tests/io.sh:
- Add test.

src/cmd/ksh93/tests/builtins.sh,
src/cmd/ksh93/tests/options.sh:
- Revert shcomp workarounds. (re: 6701bb30)

Resolves: https://github.com/ksh93/ksh/issues/165
2021-04-22 03:25:24 +01:00
Martijn Dekker
b7dde4e747 Fix ksh exit on syntax error in profile (re: cb67a01b, ceb77b13)
Johnothan King writes:
> There are two regressions related to how ksh handles syntax
> errors in the .kshrc file. If ~/.kshrc or the file pointed to by
> $ENV have a syntax error, ksh exits during startup. Additionally,
> the error message printed is incorrect:
>
> $ cat /tmp/synerror
> ((
> echo foo
>
> # ksh93u+m
> $ ENV=/tmp/synerror arch/*/bin/ksh -ic 'echo ${.sh.version}'
> /tmp/synerror: syntax error: `/t/tmp/synerror' unmatched
>
> # ksh93u+
> $ ENV=/tmp/synerror ksh93u -ic 'echo ${.sh.version}'
> /tmp/synerror: syntax error: `(' unmatched
> Version AJM 93u+ 2012-08-01
>
> The regression that causes the incorrect error message was
> introduced by commit cb67a01. The other bug that causes ksh to
> exit on startup was introduced by commit ceb77b1.

src/cmd/ksh93/sh/lex.c: fmttoken():
- Call stakfreeze(0) to terminate a possible unterminated previous
  stack item before writing the token string onto the stack. This
  fixes the bug with garbage in a syntax error message.

src/cmd/ksh93/sh/main.c: exfile():
- Revert Red Hat's ksh-20140801-diskfull.patch applied in ceb77b13.
  This fixes the bug with interactive ksh exiting on syntax error
  in a profile script. Testing by @JohnoKing showed the patch is no
  longer necessary to fix a login crash on disk full, as commit
  970069a6 (which applied Red Hat patches ksh-20120801-macro.patch
  and ksh-20120801-fd2lost.patch) also fixes that crash.

src/cmd/ksh93/README:
- Fix typos. (re: fdc08b23)

Co-authored-by: Johnothan King <johnothanking@protonmail.com>
Resolves: https://github.com/ksh93/ksh/issues/281
2021-04-21 19:42:24 +01:00
Martijn Dekker
fdc08b239b ksh93/README updates
src/cmd/ksh93/README:
- Update compile-time options docuemntation.
- Update build instructions.
- Remove obsolete stuff.

src/cmd/ksh93/SHOPT.sh:
- Remove unused SHOPT_SEVENBIT option. A search in ast-open-history
  shows it was removed from include/edit.h on 2001-10-31. You can
  still get its effect by changing STRIP from 0377 to 0177 there.
2021-04-21 04:30:30 +01:00
Martijn Dekker
7954855f21 Don't import/export readonly attribute via magic A__z env var
While automagically importing/exporting ksh variable attributes via
the environment is probably a misfeature in general (now disabled
for POSIX standard mode), doing so with the readonly attribute is
particularly problematic. Scripts can take into account the
possibility of importing unwanted attributes by unsetting or
typesetting variables before using them. But there is no way for a
script to get rid of an unwanted imported readonly variable. This
is a possible attack vector with no possible mitigation.

This commit blocks both the import and the export of the readonly
attribute through the environment. I consider it a security fix.

src/cmd/ksh93/sh/init.c: env_import_attributes():
- Clear NV_RDONLY from imported attributes before applying them.

src/cmd/ksh93/sh/name.c: sh_envgen():
- Remove NV_RDONLY from bitmask defining attributes to export.
2021-04-21 04:11:55 +01:00
Johnothan King
f28bce61a7
Fix multiple problems with the getconf builtin (#280)
This commit fixes three problems with getconf pathbound builtin:
1. The -l/--lowercase option did not change all variable names to
   lower case.
2. The -q/--quote option now quotes all string values. Previously,
   it only quoted string values that had a space or other
   non-shellsafe character.
3. The -c/--call, -n/--name and -s/--standard options matched all
   variable names provided by 'getconf -a', even if none were
   actual matches.

Additionally, references to the confstr and sysconf functions have
been updated to reference section 3 of the man pages instead of
section 2.

src/lib/libast/port/astconf.c:
- Previously, only values that had spaces in them were quoted. Change
  that behavior to quote all string values by using the FMT_ALWAYS
  flag. Bug report: https://github.com/att/ast/issues/1173
- Not all variable names were printed in lowercase by 'getconf -l'.
  Fix it by adding a few missing instances of fmtlower.
  Bug report: https://github.com/att/ast/issues/1171
- Add the missing code to the '#if _pth_getconf_a' block to handle
  -c/-n/-s while parsing the OS's native 'getconf -a' output. This
  approach reuses code for name matching from other parts of
  astconflist(). Resolves: https://github.com/ksh93/ksh/issues/279

src/lib/libcmd/getconf.c:
- Update the documentation to note the -q flag only quotes strings.

src/cmd/ksh93/tests/bulitins.sh:
- Add regression tests for the getconf bugs fixed in this commit.

Co-authored-by: Martijn Dekker <martijn@inlv.org>
2021-04-21 03:34:54 +01:00
Martijn Dekker
61e0f90460 Yet more fixes for subshell directory handling (re: feaf718f)
There were still problems left after the previous commit. On at
least one system (QNX i386), the following regression test crashed:

src/cmd/ksh93/test/subshell.c
900     got=$( { "$SHELL" -c '(cd /; (cd /)); print -r -- "PWD=$PWD"'; } 2>&1 )

A backtrace done on the core dunp pointed to the free() call here:

src/cmd/ksh93/bltins/cd_pwd.c
90      if(oldpwd && oldpwd!=shp->pwd && oldpwd!=e_dot)
91              free(oldpwd);

Analysis: The interaction between $PWD, sh.pwd aka shp->pwd, and
the path_pwd() function is a mess. path_pwd() usually returns a
freeable value, but not always. sh.pwd is sometimes a pointer to
the value of $PWD, but not always (e.g. when you unset PWD or
assign to it). Instead of debugging the exact cause of the crash, I
think it is better to make this work in a more consistent way.

As of this commit:
1. sh.pwd keeps its own copy of the PWD, independently of the PWD
   variable. The old value must always be freed immediately before
   assigning a new one. This is simple and consistent, reducing the
   chance of bugs at negligible cost.
2. The PWD variable is no longer given the NV_NOFREE attribute
   because its value no longer points to sh.pwd. It is now a
   variable like any other.

src/cmd/ksh93/sh/path.c: path_pwd():
- Do not give PWDNOD the NV_NOFREE attribute.
- Give sh.pwd its own copy of the PWD by strdup'ing PWDNOD's value.

src/cmd/ksh93/bltins/cd_pwd.c: b_cd():
- Since sh.pwd is now consistently freed before giving it a new
  value and at no other time, oldpwd must not be freed any longer
  and can become a regular non-static variable.
- If the PWD needs reinitialising, call path_pwd() to do it.

src/cmd/ksh93/sh/subshell.c: sh_subshell():
- Systems with fchdir(2): Always restore the PWD upon exiting a
  non-subshare subshell. The check to decide whether or not to
  restore it was unsafe: it was not restored if the current PWD
  pointer and value was identical to the saved one, but a directory
  can be deleted and recreated under the same name.
- Systems without fchdir(2) (if any exist):
  . Entry: Fork if the PWD is nonexistent or has no x permission.
  . Restore: Only chdir back if the subshell PWD was changed.
  That's probably the best we can do. It remains inherently unsafe.
  We should probably just require fchdir(2) at some point.
2021-04-20 05:39:10 +01:00
Martijn Dekker
feaf718f16 More fixes for subshell directory handling (re: 7bab9508, 5ee290c7)
This commit fixes what are hopefully the two final aspects of #153:

1. If the present working directory does not exist (was moved or
   deleted) upon entering a virtual subshell, no PWD directory path
   is saved. Since restoring the state after exiting a virtual
   subshell is contingent on a previous PWD path existing, this
   resulted in entire aspects of the virtual subshell, such as the
   subshell function tree, not being cleaned up.
2. A separate problem is that 'cd ..' does not update PWD or OLDPWD
   when run from a nonexistent directory.

A reproducer exposing both problems is:

$ mkdir test
$ cd test
$ ksh -c '(subfn() { BAD; }; cd ..; echo subPWD==$PWD);
			typeset -f subfn; echo mainPWD==$PWD'
subPWD==/usr/local/src/ksh93/ksh/test
subfn() { BAD; };mainPWD==/usr/local/src/ksh93/ksh/test

Expected output:
subPWD==/usr/local/src/ksh93/ksh
mainPWD==/usr/local/src/ksh93/ksh/test

src/cmd/ksh93/bltins/cd_pwd.c:
- If path_pwd() fails to get the PWD (usually it no longer exists),
  don't set $OLDPWD to '.' as that is pointless; use $PWD instead.
  After cd'ing from a nonexistent directory, 'cd -' *should* fail
  and should not be equivalent to 'cd .'.
- Remove a redundant check for (!oldpwd) where it is always set.
- Do not prematurely return without setting PWD or OLDPWD if
  pathcanon() fails to canonicalise a nonexistent directory.
  Instead, fall back to setting PWD to the result of getcwd(3).

src/cmd/ksh93/sh/subshell.c:
- Minor stylistic adjustment. Some NULL macros sneaked in. This
  historic code base does not use them (yet); change to NIL(type*).
- sh_subshell(): Fix logic for determining whether to save/restore
  subshell state.
  1. When saving, 'if(!comsub || !shp->subshare)' is redundant;
     'if(!shp->subshare)' should be enough. If we're not in a
     subshare, state should be saved.
  2. When restoring, 'if(sp->shpwd)' is just nonsense as there is
     no guarantee that the PWD exists upon entering a subshell.
     Simply use the same 'if(!shp->subshare)'. Add an extra check
     for sp->pwd to avoid a possible segfault. Always restore the
     PWD on subshell exit and not only if shp->pwd is set.
- sh_subshell(): Issue fatal errors in libast's "panic" format.

src/cmd/ksh93/tests/builtins.sh:
- Adjust a relevant test to run err_exit() outside of the subshell
  so that any error is counted in the main shell.
- Add test for problem 2 described at the top.

src/cmd/ksh93/tests/subshell.sh:
- Add test for problems 1 and 2 based on reproducer above.

Resolves: https://github.com/ksh93/ksh/issues/153
2021-04-19 00:06:43 +01:00
Martijn Dekker
b0a6c1bde5 Further fix '<>;' and fix crash on 32-bit systems (re: 6701bb30)
Accessing t->tre.treio for every sh_exec() run is invalid because
't' is of type Shnode_t, which is a union that can contain many
different kinds of structs. As all members of a union occupy the
same address space, only one can be used at a time. Which member is
valid to access depends on the node type sh_exec() was called with.
The invalid access triggered a crash on 32-bit systems when
executing an arithmetic command like ((x=1)).

The t->tre.treio union member should be accessed for a simple
command (case TCOM in sh_exec()). The fix is also needed for
redirections attached to blocks (case TSETIO) in which case the
union member to use is t->fork.forkio.

src/cmd/ksh93/sh/xec.c:
- Add check_exec_optimization() function that checks for all the
  conditions where the exec optimisation should not be done. For
  redirections we need to loop through the whole list to check for
  an IOREWRITE (<>;) one.
- sh_exec(): case TCOM (simple command): Only bother to call
  check_exec_optimization() if there are either command arguments
  or redirections (IOW: don't bother for bare variable
  assignments), so move it to within the if(io||argn) block.
- sh_exec(): case TSETIO: This needs a similar fix. To avoid the
  optimization breaking again if the last command is a subshell
  with a <>; redirection attached, we need to not only set execflg
  to 0 but also clear the SH_NOFORK state bit from the 'flags'
  variable which is passed on to the recursive sh_exec() call.

src/cmd/ksh93/tests/io.sh:
- Update and expand tests. Add tests for redirections attached to
  simple commands (TCOM) and various kinds of code block (TSETIO).

Co-authored-by: Johnothan King <johnothanking@protonmail.com>
Resolves: https://github.com/ksh93/ksh/issues/278
2021-04-17 21:56:39 +01:00
Martijn Dekker
ba43436f10 emacs: Fix digits input after completion (re: 16e4824c, e8b3274a)
Immediately after tab-completing the name of a directory, it is
not possible to type digits after the slash; ksh eats them as it
parses them as a menu selection for a nonexistent menu.

Reproducer:
$ mkdir -p emacstest/123abc
$ cd emacste[tab]123abc

Actual results:
$ cd emacstest/abc

Expected results:
$ cd emacstest/123abc

Workarounds are to press a non-numeric key followed by backspace,
or hit [tab] again to get a list of options.

Originally reported by Arnon Weinberg, 2012-12-23 07:15:19 UTC, at:
https://bugzilla.redhat.com/889745

The fix had been partially backported from ksh 93v- by AT&T
(16e4824c), which made things worse, so it was reverted (e8b3274a).
This commit backports a slightly edited version of the complete
fix. Thanks to @JohnoKing for finding the correct code. Discussion:
https://github.com/ksh93/ksh/issues/198#issuecomment-820178514

src/cmd/ksh93/edit/emacs.c: escape():
- Backport the fix for this bug that was implemented in ksh 93v-
  alpha 2013-10-10. Immediately after a slash, do not stay in "\"
  mode (file name completion) and reset the tab count.

src/cmd/ksh93/tests/pty.sh:
- Test the fix.

Resolves: https://github.com/ksh93/ksh/issues/198
2021-04-16 14:46:07 +01:00
Martijn Dekker
5fc9e64208 tests: cd /dev, not /home which not all systems have (re: ca2443b5) 2021-04-16 03:04:59 +01:00
Johnothan King
6701bb30de
Fix <>; redirection for final command exec optimization (#277)
The <>; operator doesn't work correctly if it's used as the last
command of a -c script. Reproducer:
  $ echo test > a; ksh -c 'echo x 1<>; a'; cat a
  x
  st
This bug is caused by ksh running the last command of -c scripts
with execve(2) instead of posix_spawn(3) or fork(2). The <>;
operator is noted by the man page as being incompatible with the
exec builtin (see also the ksh93u+ man page), so it's not
surprising this bug occurs when ksh runs a command using execve:

> <>;word cannot be used with the exec and redirect built-ins.

The ksh2020 fix simply removed the code required for ksh to use
this optimization at all. It's not a performance friendly fix and
only papers over the bug, so this commit provides a better fix.

This bug was first reported at:
https://github.com/att/ast/issues/9

In addition, this commit re-enables the execve(2) optimization for
the last command for scripts loaded from a file. It was enabled in
in older ksh versions, and was only disabled in interactive shells:
https://github.com/ksh93/ast-open-history/blob/2011-06-30/src/cmd/ksh93/sh/main.c#L593-L599
It was changed on 2011-12-24 to only be used for -c scripts:
https://github.com/ksh93/ast-open-history/blob/2011-12-24/src/cmd/ksh93/sh/main.c#L593-L599

We think there is no good reason why scripts loaded from a file
should be optimised less than scripts loaded from a -c argument.
They're both scripts; there's no essential difference between them.
So this commit reverts that change. If there is a bug left in the
optimization after this fix, this revert increases the chance of
exposing it so that it can be fixed.

src/cmd/ksh93/sh/xec.c:
- The IOREWRITE flag is set when handling the <>; operator, so to
  fix this bug, avoid exec'ing the last command if it uses <>;. See
  also commit 17ebfbf6, which fixed another issue related to the
  execve optimization.

src/cmd/ksh93/tests/io.sh:
- Enable a regression test that was failing because of this bug.
- Add the reproducer from https://github.com/att/ast/issues/9 as a
  regression test.

src/cmd/ksh93/sh/main.c:
- Only avoid the non-forking optimization in interactive shells.

src/cmd/ksh93/tests/signal.sh:
- Add an extra comment to avoid the non-forking optimization in the
  regression test for rhbz#1469624.
- If the regression test for rhbz#1469624 fails, show the incorrect
  exit status in the error message.

src/cmd/ksh93/tests/builtins.sh,
src/cmd/ksh93/tests/options.sh:
- This bugfix was causing the options regression test to segfault
  when run under shcomp. The cause is the same as
  <https://github.com/ksh93/ksh/issues/165>, so as a workaround,
  avoid parsing process substitutions with shcomp until that is
  fixed. This workaround should also avoid the other problem
  detailed in <https://github.com/ksh93/ksh/issues/274>.

Resolves: https://github.com/ksh93/ksh/issues/274
2021-04-15 18:29:50 +01:00
Andy Fiddaman
2fdf394b99
nv_disc(NV_LAST) loses trailing shell context from discipline stack (#276)
This is the underlying cause for the issue worked around in
3654ee73.

The following explanation refers to the current illumos version of
ksh93 and shows output from illumos' modular debugger:
https://illumos.org/books/dev/debugging.html

Each environment variable (name/value pair) has a linked list of
disciplines attached to it, and at the end of that list there is
optionally a shell context pointer. For example, for the EDITOR
variable:

        > ::bp libshell.so.1`put_ed
        > ::run
        $
        $ EDITOR=vim
        > ::stack ! head -1
        libshell.so.1`put_ed+0x14(e06208, e01c58, 0, dced90)
        > e06208::print Namval_t
        {
            nvname = 0xfffffbffeec40a0e "EDITOR"
            nvfun = 0xdced90
            nvalue = 0
        }
        > e06208::print Namval_t nvfun | ::print Namfun_t
        {
            disc = libshell.so.1`EDITOR_disc
            next = libshell.so.1`sh+0x710
        }

Here, the EDITOR Namval_t has a discipline stack containing
EDITOR_disc and &Shell_t.nvfun.

The problem arises when a new discipline is pushed onto the stack,
such as when using typeset -u to add an upper-case translation
discipline.

    $ typeset -u EDITOR
    > e06208::print Namval_t
    {
        nvname = 0xfffffbffeec40a0e "EDITOR"
        nvfun = 0xdced90
        nvalue = 0xe0fdb0 "vim"
    }
    > e06208::print Namval_t nvfun | ::print Namfun_t
    {
        disc = libshell.so.1`EDITOR_disc
        next = 0xdc27a0
    }
    > e06208::print Namval_t nvfun | ::print Namfun_t next | ::print Namfun_t
    {
        disc = libshell.so.1`TRANS_disc
        next = 0
    }

TRANS_disc has been pushed onto the end of the discipline stack,
but the shell handle has been lost.

With this change, the attributes and variables tests pass (this is
on illumos where this change originates).
2021-04-15 14:41:32 +01:00
Martijn Dekker
519bb08265
Allow invoking path-bound built-in commands by direct path or preceding PATH assignment (#275)
Path-bound builtins on ksh (such as /opt/ast/bin/cat) break some
basic assumptions about paths in the shell that should hold true,
e.g., that a path output by whence -p or command -v should actually
point to an executable command. This commit should fix the
following:

1. Path-bound built-ins (such as /opt/ast/bin/cat) can now be
   executed by invoking the canonical path (independently of the
   value of $PATH), so the following will now work as expected:

        $ /opt/ast/bin/cat --version
          version         cat (AT&T Research) 2012-05-31
        $ (PATH=/opt/ast/bin:$PATH; "$(whence -p cat)" --version)
          version         cat (AT&T Research) 2012-05-31

   In the event an external command by that path exists, the
   path-bound builtin will now override it when invoked using the
   canonical path. To invoke a possible external command at that
   path, you can still use a non-canonical path, e.g.:
   /opt//ast/bin/cat or /opt/ast/./bin/cat

2. Path-bound built-ins will now also be found on a PATH set
   locally using an assignment preceding the command, so something
   like the following will now work as expected:

        $ PATH=/opt/ast/bin cat --version
          version         cat (AT&T Research) 2012-05-31

   The builtin is not found by sh_exec() because the search for
   builtins happens long before invocation-local preceding
   assignments are processsed. This only happens in sh_ntfork(),
   before forking, or in sh_fork(), after forking. Both sh_ntfork()
   and sh_fork() call path_spawn() to do the actual path search, so
   a check there will cover both cases.

   This does mean the builtin will be run in the forked child if
   sh_fork() is used (which is the case on interactive shells with
   job.jobcontrol set, or always after compiling with SHOPT_SPAWN
   disabled). Searching for it before forking would mean
   fundamentally redesigning that function to be basically like
   sh_ntfork(), so this is hard to avoid.

src/cmd/ksh93/sh/path.c: path_spawn():
- Before doing anything else, check if the passed path appears in
  the builtins tree as a pathbound builtin. If so, run it. Since a
  builtin will only be found if a preceding PATH assignment
  temporarily changed the PATH, and that assignment is currently in
  effect, we can just sh_run() the builtin so a nested sh_exec()
  invocation will find and run it.
- If 'spawn' is not set (i.e. we must return), set errno to 0 and
  return -2. See the change to sh_ntfork() below.

src/cmd/ksh93/sh/xec.c:
- sh_exec(): When searching for built-ins and the restricted option
  isn't active, also search bltin_tree for names beginning with a
  slash.
- sh_ntfork(): Only throw an error if the PID value returned is
  exactly -1. This allows path_spawn() to return -2 after running a
  built-in to tell sh_ntfork() to do the right things to restore
  state.

src/cmd/ksh93/sh/parse.c: simple():
- When searching for built-ins at parse time, only exclude names
  containing a slash if the restricted option is active. This
  allows finding pointers to built-ins invoked by literal path like
  /opt/ast/bin/cat, as long as that does not result from an
  expansion. This is not actually necessary as sh_exec() will also
  cover this case, but it is an optimisation.

src/lib/libcmd/getconf.c:
- Replace convoluted deferral to external command by a simple
  invocation of the path to the native getconf command determined
  at compile time (by src/lib/libast/comp/conf.sh). Based on:
  https://github.com/ksh93/ksh/issues/138#issuecomment-816384871
  If there is ever a system that has /opt/ast/bin/getconf as its
  default native external 'getconf', then there would still be an
  infinite recursion crash, but this seems extremely unlikely.

Resolves: https://github.com/ksh93/ksh/issues/138
2021-04-15 04:08:12 +01:00
Johnothan King
2c38fb93fd
Fix the exit status returned when a command isn't executable (#273)
Previous discussion: https://github.com/att/ast/issues/485

If ksh attempts to execute a non-executable command found in the
PATH, in some instances the error message and return status are
incorrect. In the example below, ksh returns with exit status 126
when using the -c execve(2) optimization or when using fork(2) in
an interactive shell. However, using posix_spawn(3) causes the exit
status to change:
  $ echo 'print cannot execute' > /tmp/x
  # Runs command with spawnveg (i.e., posix_spawn or vfork)
  $ ksh -c 'PATH=/tmp; x; echo $?'
  ksh: x: not found
  127
  # Runs command with execve
  $ ksh -c 'PATH=/tmp; x'; echo $?
  ksh: x: cannot execute [Permission denied]
  126
  # Runs command with fork
  $ ksh -ic 'PATH=/tmp; x; echo $?'
  ksh: x: cannot execute [Permission denied]
  126

Since 'x' is in the PATH but can't be executed, the correct exit
status is 126, not 127. It's worth noting this bug doesn't cause
the regression tests to fail with ksh93u+m, but it does cause one
test to fail when run under dtksh:

    path.sh[706]: Long nonexistent command name: got status 126, ''

This commit backports various fixes for this bug from ksh2020, with
additional fixes applied (since there were still some additional
issues the ksh2020 patch didn't fix). The lacking regression test
for exit status 126 in path.sh has been rewritten to test for more
scenarios where ksh failed to return the correct error message
and/or exit status. I can also confirm with this patch applied the
path.sh regression tests now pass when run under dtksh.

src/cmd/ksh93/sh/path.c:
- Add a comment to path_absolute() describing 'oldpp' is the
  current pointer in the while loop and 'pp' is the next pointer.
  Backported from:
  https://github.com/att/ast/commit/a6cad450

- The patch from ksh2020 didn't fix this bug in the SHOPT_SPAWN
  code (because ksh2020 prefers fork(2)), so issues with the exit
  status could still occur when using spawnveg. To fix this, always
  set 'noexec' to the value of errno if can_execute fails. Before
  this fix, errno was discarded if 'pp' was a null pointer and
  can_execute failed.

- If a command couldn't be executed and the error wasn't ENOENT,
  save errno in a 'not_executable' variable. If an executable
  command couldn't be found in the PATH, exit with status 126 and
  set errno to the saved value. This was based on a ksh2020 bugfix,
  but it has been reworked a little bit to fix a bug that caused a
  mismatch between the error message shown and errno. Example with
  a non-executable file in PATH:
  $ nonexec
  ksh2020: nonexec: cannot execute [No such file or directory]
  The ksh2020 patch: <https://github.com/att/ast/pull/493>

- Backport a ksh2020 bugfix for directories in the PATH when
  running one of the added regression tests on OpenBSD:
  https://github.com/att/ast/pull/767

src/cmd/ksh93/data/msg.c,
src/cmd/ksh93/include/shell.h,
src/cmd/ksh93/sh/{path,xec}.c:
- If a command name is too long (ENAMETOOLONG), then it wasn't
  found in the PATH. For that case return exit status 127, like
  for ENOENT.

src/cmd/ksh93/tests/path.sh:
- Replace the old test with a new set of more extensive tests.
  These tests check the error message and exit status when ksh
  attempts to run a command using any of the following:
   - execve(2), used with the last command run with -c       (*A tests).
   - posix_spawn(3)/vfork(2), used in noninteractive scripts (*B tests).
   - fork(2), used in interactive shells with job control    (*C tests).
   - command -x                                              (*D tests).
   - exec(1)                                                 (*E tests).
- Add a regression test from ksh2020 for attempting to execute a
  directory:
  https://github.com/att/ast/pull/758

src/lib/libast/include/ast.h,
src/lib/libast/include/wait.h:
- Avoid bitshifts in macros for static error codes. The return
  values of command not found and exec related errors are static
  values and should not require any macro magic for calculation.
  Backported from: https://github.com/att/ast/commit/c073b102
- Simplify EXIT_* and W* macros to use 8 bits.
2021-04-15 03:37:57 +01:00
Johnothan King
df47731d7d
tests/builtins.sh: Fix dtksh regression test failures (re: ef4fe41) (#272)
The usage options test wasn't properly excluding all dtksh builtins,
which was causing the regression tests to fail under dtksh. This commit
adds exclusions for the builtins missed in commit ef4fe41.
2021-04-15 00:10:12 +01:00
hyenias
d6ddd89053
Correct memory fault when removing default nameref KSH_VERSION (#271)
This commit fixes a segmentation fault when an attempt was made to
unset the default KSH_VERSION variable prior any other nameref
activity such as creating another nameref or even reassigning the
nameref KSH_VERSION to something else.

(new shell without prior nameref activity)
$ nameref
KSH_VERSION=.sh.version
$ unset -n KSH_VERSION
Memory fault

src/cmd/ksh93/sh/name.c: _nv_unset():
- Add a 'Refdict' check before attempting to remove a value from it
  as apparently one does not exist until some sort of nameref
  activity occurs after shell startup as the default nameref of
  'KSH_VERSION=.sh.version' does not create one.
2021-04-13 03:15:34 +01:00
Johnothan King
75796a9c75
Fix += operator regressions (re: fae8862c) (#270)
The bugfix for BUG_CMDSPASGN backported in commit fae8862c caused
two regressions with the += operator:

1. The += operator did not append to variables. Reproducer:
     $ integer foo=3
     $ foo+=2 command eval 'echo $foo'
     2

2. The += operator ignored the readonly attribute, modifying readonly
   variables in the same manner as above. Reproducer
     $ readonly bar=str
     $ bar+=ing command eval 'echo $bar'
     ing

Both of the regressions above were caused by nv_putval() failing to
clone the variable from the previous scope into the invocation-local
scope. As a result, 'foo+=2' was effectively 0 + 2 (since ksh didn't
clone 3). The first regression was noticed during the development of
ksh93v-, so to fix both bugs I've backported the bugfix for the
regression from the ksh93v- 2013-10-10 alpha version:
https://www.mail-archive.com/ast-users@lists.research.att.com/msg00369.html

src/cmd/ksh93/sh/name.c:
- To fix both of the bugs above, find the variable to modify with
  nv_search(), then clone it into the invocation local scope. To
  fix the readonly bug as well, this is done before the NV_RDONLY
  check (otherwise np will be missing that attribute and be
  incorrectly modified in the invocation-local scope).
- Update a nearby comment describing what sh_assignok() does (per this
  comment: https://github.com/ksh93/ksh/pull/249#issuecomment-811381759)

src/cmd/ksh93/tests/builtins.sh:
- Add regression tests for both of the now fixed regressions,
  loosely based on the regression tests in ksh93v-.
2021-04-12 01:24:33 +01:00
hyenias
6629c22308
Adjust readonly regression tests for freezes (#267)
src/cmd/ksh93/tests/readonly.sh:
- Use a 'ulimit --cpu' as a workaround to close down hung processes
  that might be caused due to a couple of known bugs (recursion and
  type variable function)
  Discussion: https://github.com/ksh93/ksh/issues/264
- Adjust tests so xtrace can be used
- Use integer n within for loop
2021-04-11 19:57:40 +01:00
Martijn Dekker
d50d3d7c4c Reset arithmetic recursion level on all errors (re: 264ba48b)
The recursion level for arithmetic expressions is kept track of in
a static 'level' variable in streval.c. It is reset when arithmetic
expressions throw an error.

But an error for an arithmetic expression may also occur elsewhere
-- at least in one case: when an arithmetic expression attempts to
change a read-only variable. In that case, the recursion level is
never reset because that code does not have access to the static
'level' variable.

If many such conditions occur (as in the new readonly.sh regression
tests), an arithmetic command like 'i++' may eventually fail with a
'recursion too deep' error.

To mitigate the problem, MAXLEVEL in streval.c was changed from 9
to 1024 in 264ba48b (as in the ksh 93v- beta). This commit leaves
that increase, but adds a proper fix.

src/cmd/ksh93/include/defs.h:
- Add global sh.arithrecursion (a.k.a. shp->arithrecursion)
  variable to keep track of the arithmetic recursion level,
  replacing the static 'level' variable in streval.c.

src/cmd/ksh93/sh/xec.c: sh_exec():
- Reset sh.arithrecursion before starting a new simple command
  (TCOM), a new subshell with parentheses (TPAR), a new pipe
  (TFIL), or a new [[ ... ]] command (TTST). These are the same
  places where 'echeck' is set to 1 for --errexit and ERR trap
  checks, so it should cover everything.

src/cmd/ksh93/sh/streval.c:
- Change all uses of 'level' to sh.arithrecursion.
- _seterror, aritherror(): No longer bother to reset the level
  to zero here; xec.c should have this covered for all cases now.

src/cmd/ksh93/tests/arith.sh:
- Add tests for main shell and subshell.
2021-04-11 01:25:19 +01:00
Martijn Dekker
f6bc5c03ca nv_setlist(): add check for readonly (re: 264ba48b)
One area where readonly is still ineffective is the local
environment list for a command (preceding assignments) if that
command is not executed using exec(3) after fork(2). Builtin
commands are one example. The following succeeds but should fail:

	(readonly v=1; v=2 true)  # succeeds, but should fail

If the shell is compiled with SHOPT_SPAWN (the default) then this
also applies to external commands invoked with sh_ntfork():

	(readonly v=1; v=2 env)	  # succeeds if SHOPT_SPAWN

This presents to the user as inconsitent behaviour because external
commands may be fork()ed under certain circumstances but not
others, depending on complex optimisations. One example is:

	$ ksh -c 'readonly v=1; v=2 env'
	ksh: v: is read only
	$ ksh -c 'readonly v=1; v=2 env; :'
	(bad: environment list is output, including 'v=2')

In the first command above, where 'v2=env' is the last command in
the -c script, the optimisation skips creating a scope and assigns
the environment list in the current scope.

src/cmd/ksh93/sh/name.c: nv_setlist():
- Add check for readonly. This requires searching for the variable
  in the main tree using nv_search() before a locally scoped one is
  added using nv_open(). Since nv_search() only works with plain
  variable names, temporarily end the string at '='.

src/cmd/ksh93/tests/readonly.sh:
- Add version check and fork the test command substitution subshell
  on older versions that would otherwise abort the tests due to the
  combination of an excessively low arithmetic recursion tolerance
  and a bug that sometimes fails to restore the shell's arithmetic
  recursion level.
2021-04-10 23:12:18 +01:00
Martijn Dekker
66c37202fd SHOPT_SPAWN: rm unused job control code (re: f207cd57, 41ebb55a)
Since f207cd57, sh_ntfork() is never called if job.jobcontrol is
set (i.e. if job control is active on an interactive shell), so the
code that is only run if job.jobcontrol is set should be removed.

src/cmd/ksh93/sh/xec.c:
- Remove spawnveg() define that is unused as of 7b0e0776.
- sh_exec(): Simplify SHOPT_SPAWN preprocessor logic. As sh_fork()
  never returns a negative value, only run the parent<0 check after
  running sh_ntfork() -- that check already didn't happen when
  compiling ksh with SHOPT_SPAWN disabled.
- sh_ntfork(): Remove signal and terminal handling (with race
  condition) that was only run with job.jobcontrol set.
2021-04-10 18:10:27 +01:00