tech-userlevel archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Coming /bin/sh changes (fixes)



I am (soon -- perhaps it will have happened before you
read this for some of you) going to commit changes to /bin/sh
to (finally!) get rid of internal uses of atoi() - completely.

Mostly this will have no visible effect, but there may be a few
places where sh will now report a "number out of range" instead
of silently truncating it to 32 bits, eg: "shift 4294967297" will
now be an error, instead of the same as "shift 1" (and the
same for several other builtin commands that take a
numeric argument).   (We already fixed a bug a while ago
where ${4294967297} used to treated the same as ${1},
nothing is altering there, that will remain valid, and most
likely produce an (unset) null string as its value, unless
you can work out a way to actually set that many args.

Note that none of this affects shell arithmetic $(( )) which
continues to operate on intmax_t integral types, and is
not affected at all (it has not used atoi() in a very long time,
if it ever did.)

Most likely the one place where a script might fall over
because of this change is if it happens to have

	break NNNNNNNNNNNNN

where N...N is a > 31 bit number, where the intent was
to simply break out of every possible enclosing loop, but
the programmer (script writer) was too lazy to work out
how many there might be, so simply wrote something huge.
(Same for "continue" of course.)

That will no longer work if "huge" is too big, keep it under
2^31 and all should still function just the same.

One other thing that was affected, just as
	shift 4294967297
is no longer an alias for "shift 1", the same is true for
OPTIND=4294967297 which used to be treated the same
as OPTIND=1 and do a reset on the argument list for getopts().

But as well as no longer silently truncating this way, another bug
in the handling of OPTIND is being fixed (a side effect needed
because of the other changes) - it will no longer be an error to
assign a non-number to OPTIND.   Doing so won't accomplish
anything useful, but in sh, OPTIND is just a variable like any other,
and it should be possible to assign anything you like to it.   That
will now work as it should (ie: no "number out of range" here).

What is undefined (in POSIX) in this area, is calling getopts after
setting OPTIND to anything other than 1.

For our /bin/sh the posix undefined behaviour will be implemented
to be to simply ignore the invalid setting of OPTIND.   Set it to 1
and the arg list is reset, set it to anything else, and it gets set, but
has no other effect.   getopts will continue to set OPTIND as it is
defined to do, whatever the script (or you) set it to before calling getopts.
(Note "1" here is implmented as any unsigned decimal integer which
has the same value as 1, so 001 etc will work as well, +1 will not.)

Also, in this area, the shell is supposed to initialize OPTIND to 1
when it starts.   /bin/sh did that, but allowed an OPTIND in the
environment to override that.   That will no longer happen, whatever
the environment contains when sh starts, OPTIND will start at 1.

If anyone notices any untoward effects from these changes, after they
have been committed, please let me know, or file a PR.

kre

ps: this was inspired by seeing bug reports about another shell which
could actually be made to core dump by giving it large enough integer
parameters in "appropriate" commands - I am not aware of any /bin/sh
bugs that drastic, but I thought it time to fix the integer parsing code
once and for all.



Home | Main Index | Thread Index | Old Index