1
0
Fork 0
mirror of git://git.code.sf.net/p/cdesktopenv/code synced 2025-03-09 15:50:02 +00:00

More 'command -x' robustification (re: 6f6b2201, 6a0e9a1a, 66e1d446)

The xargs-like functionality of 'command -x' was still failing with
E2BIG in cases or on systems where the environment variables list
is very large. For instance, on a default NixOS installation it's
about 50k by default (absurd; *each* process carries this weight).

This commit tweaks the feature test and introduces a runtime
fallback if it still fails.

POSIX: "The number of bytes available for the new process' combined
argument and environment lists is {ARG_MAX}. It is implementation-
defined whether null terminators, pointers, and/or any alignment
bytes are included in this total."
https://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html

More recommended reading:
https://mina86.com/2021/the-real-arg-max-part-1/
https://mina86.com/2021/the-real-arg-max-part-2/

So, operating systems are free to consume ARG_MAX space in whatever
bizarre way they want, and may even come up with more innovative
ways to waste buffer space in future. <sigh>

command_xargs() allows for the possibility of adding a certain
number of extra bytes per argument to account for pointers and
whatnot. As of this commit, we still start off from the value that
was determined by the _arg_extrabytes test in features/externs, but
path_spawn() will now increase that number at runtime and retry if
E2BIG still occurs. Hopefully this makes it future-proof.

src/cmd/ksh93/features/externs:
- Rename generated ARG_EXTRA_BYTES macro to _arg_extrabytes for
  better naming consistency with other iffe feature tests.
- Tweaks to avoid detecting 9 extra bytes instead of 8 on some
  versions of 64-bit Linux (it needs the size of a 64 bit pointer).
- Show the result in the iffe output.

src/cmd/ksh93/include/shell.h,
src/cmd/ksh93/sh/init.c:
- Do not store getconf(CONF_ARG_MAX) at init time; on Linux, this
  value may be changed dynamically (via ulimit -s), so it must be
  re-obtained on every use.

src/cmd/ksh93/sh/path.c:
- command_xargs():
  - Use a static global variable for the number of extra bytes per
    argument. Initialise it with the results of the feature test.
    This allows increasing it at runtime if an OS does something
    weird causing an E2BIG failure.
  - Abort instead of return if command_xargs() is called with
    sh.xargmin < 0; this should never happen.
  - To allow retrying without crashing, restore saved args before
    returning -1.
  - Leave more generous space for the environment -- half the size
    of the existing environment. This was experimentally determined
    to be needed to keep Linux and macOS happy.
  - Instead of crashing, return with E2BIG if there is too little
    space to run.
  - Get rid of unnecessary (void*) typecasts; we no longer pretend
    to be compatible with C++ (re: a34e8319).
  - Remove a couple of dead 'if(saveargs) free(saveargs);'
    statements; at those points, saveargs is known to be NULL.
  - Return -2 instead of -1 when retrying would be pointless.
- path_spawn():
  - When command_xargs() returns -1 and the error is E2BIG,
    increase the number of extra bytes by the size of a char*
    pointer and try again. Give up if adding bytes the size of 8
    char* pointers fails.

src/cmd/ksh93/sh/xec.c: check_exec_optimization():
- Do not use this optimization if we are running 'command -x';
  I noticed some instances of the PATH search yielding incorrect
  results if we do. TODO: work this out at some point.
This commit is contained in:
Martijn Dekker 2022-06-20 19:50:35 +01:00
parent 225323f138
commit 05fc199c95
5 changed files with 85 additions and 41 deletions

View file

@ -217,7 +217,6 @@ struct sh_scoped
struct limits
{
long arg_max; /* max arg+env exec() size */
int open_max; /* maximum number of file descriptors */
int clk_tck; /* number of ticks per second */
int child_max; /* maximum number of children */