1
0
Fork 0
mirror of git://git.code.sf.net/p/cdesktopenv/code synced 2025-02-13 11:42:21 +00:00

Fix octal number arguments in printf integer arithmetic

Bug 1: POSIX requires numbers used as arguments for all the %d,
%u... in printf to be interpreted as in the C language, so
	printf '%d\n' 010
should output 8 when the posix option is on. However, it outputs 10.

This bug was introduced as a side effect of a change introduced in
the 2012-02-07 version of ksh 93u+m, which caused the recognition
of leading-zero numbers as octal in arithmetic expressions to be
disabled outside ((...)) and $((...)). However, POSIX requires
leading-zero octal numbers to be recognised for printf, too.

The change in question introduced a sh.arith flag that is set while
we're processing a POSIX arithmetic expression, i.e., one that
recognises leading-zero octal numbers.
Bug 2: Said flag is not reset in a command substitution used within
an arithmetic expression. A command substitution should be a
completely new context, so the following should both output 10:

$ ksh -c 'integer x; x=010; echo $x'
10            # ok; it's outside ((…)) so octals are not recognised
$ ksh -c 'echo $(( $(integer x; x=010; echo $x) ))'
8             # bad; $(comsub) should create new non-((…)) context

src/cmd/ksh93/bltins/print.c: extend():
- For the u, d, i, o, x, and X conversion modifiers, set the POSIX
  arithmetic context flag before calling sh_strnum() to convert the
  argument. This fixes bug 1.

src/cmd/ksh93/sh/subshell.c: sh_subshell():
- When invoking a command substitution, save and unset the POSIX
  arithmetic context flag. Restore it at the end. This fixes bug 2.

Reported-by: @stephane-chazelas
Resolves: https://github.com/ksh93/ksh/issues/326
This commit is contained in:
Martijn Dekker 2021-09-13 04:23:50 +02:00
parent 44bdb3fbfc
commit 7b5b0a5d54
8 changed files with 50 additions and 3 deletions

12
NEWS
View file

@ -3,6 +3,18 @@ For full details, see the git log at: https://github.com/ksh93/ksh
Any uppercase BUG_* names are modernish shell bug IDs. Any uppercase BUG_* names are modernish shell bug IDs.
2021-09-13:
- Fixed a bug introduced in 93u+ 2012-02-07 that caused the 'printf' builtin
(and its 'print -f' equivalent) to fail to recognise integer arguments with a
leading zero as octal numbers. For example, 'printf "%d\n" 010' now once
again outputs '8' instead of '10'.
- Disable the POSIX arithmetic context while running a command substitution
invoked from within an arithmetic expression. This fixes a bug that caused
integer arguments with a leading zero to be incorrectly interpreted as octal
numbers in non-POSIX arithmetic contexts within such command substitutions.
2021-09-12: 2021-09-12:
- When invoking a script without an interpreter/hashbang path on Linux and - When invoking a script without an interpreter/hashbang path on Linux and

View file

@ -151,6 +151,11 @@ For more details, see the NEWS file and for complete details, see the git log.
correctly negates another '!', e.g., [[ ! ! 1 -eq 1 ]] now returns correctly negates another '!', e.g., [[ ! ! 1 -eq 1 ]] now returns
0/true. Note that this has always been the case for 'test'/'['. 0/true. Note that this has always been the case for 'test'/'['.
28. In the 'printf' builtin (and the 'print -f' equivalent), numeric
arguments with a leading zero are now once again recognized as octal
numbers as in ksh93 versions before 2012-02-07, and as POSIX requires.
For example, 'printf "%d\n" 010' now once again outputs '8'.
____________________________________________________________________________ ____________________________________________________________________________
KSH-93 VS. KSH-88 KSH-93 VS. KSH-88

View file

@ -882,7 +882,9 @@ static int extend(Sfio_t* sp, void* v, Sffmt_t* fe)
} }
break; break;
default: default:
shp->inarith = 1; /* POSIX compliance: recognize octal constants, e.g. printf '%d\n' 010 */
d = sh_strnum(argp,&lastchar,0); d = sh_strnum(argp,&lastchar,0);
shp->inarith = 0;
if(d<longmin) if(d<longmin)
{ {
errormsg(SH_DICT,ERROR_warn(0),e_overflow,argp); errormsg(SH_DICT,ERROR_warn(0),e_overflow,argp);

View file

@ -1193,7 +1193,7 @@ const char sh_optprint[] =
; ;
const char sh_optprintf[] = const char sh_optprintf[] =
"[-1c?\n@(#)$Id: printf (ksh 93u+m) 2020-08-10 $\n]" "[-1c?\n@(#)$Id: printf (ksh 93u+m) 2021-09-13 $\n]"
"[--catalog?" SH_DICT "]" "[--catalog?" SH_DICT "]"
"[+NAME?printf - write formatted output]" "[+NAME?printf - write formatted output]"
"[+DESCRIPTION?\bprintf\b writes each \astring\a operand to " "[+DESCRIPTION?\bprintf\b writes each \astring\a operand to "

View file

@ -204,7 +204,7 @@ struct shared
char used_pos; /* used positional parameter */\ char used_pos; /* used positional parameter */\
char universe; \ char universe; \
char winch; \ char winch; \
char inarith; /* set when in ((...)) */ \ char inarith; /* set when in POSIX arith context, i.e. leading zero = octal, e.g. in ((...)) */ \
short arithrecursion; /* current arithmetic recursion level */ \ short arithrecursion; /* current arithmetic recursion level */ \
char indebug; /* set when in debug trap */ \ char indebug; /* set when in debug trap */ \
unsigned char ignsig; /* ignored signal in subshell */ \ unsigned char ignsig; /* ignored signal in subshell */ \

View file

@ -21,7 +21,7 @@
#define SH_RELEASE_FORK "93u+m" /* only change if you develop a new ksh93 fork */ #define SH_RELEASE_FORK "93u+m" /* only change if you develop a new ksh93 fork */
#define SH_RELEASE_SVER "1.0.0-beta.2" /* semantic version number: https://semver.org */ #define SH_RELEASE_SVER "1.0.0-beta.2" /* semantic version number: https://semver.org */
#define SH_RELEASE_DATE "2021-09-12" /* must be in this format for $((.sh.version)) */ #define SH_RELEASE_DATE "2021-09-13" /* must be in this format for $((.sh.version)) */
#define SH_RELEASE_CPYR "(c) 2020-2021 Contributors to ksh " SH_RELEASE_FORK #define SH_RELEASE_CPYR "(c) 2020-2021 Contributors to ksh " SH_RELEASE_FORK
/* Scripts sometimes field-split ${.sh.version}, so don't change amount of whitespace. */ /* Scripts sometimes field-split ${.sh.version}, so don't change amount of whitespace. */

View file

@ -470,6 +470,7 @@ Sfio_t *sh_subshell(Shell_t *shp,Shnode_t *t, volatile int flags, int comsub)
struct rand *rp; /* current $RANDOM discipline function data */ struct rand *rp; /* current $RANDOM discipline function data */
unsigned int save_rand_seed; /* parent shell $RANDOM seed */ unsigned int save_rand_seed; /* parent shell $RANDOM seed */
int save_rand_last; /* last random number from $RANDOM in parent shell */ int save_rand_last; /* last random number from $RANDOM in parent shell */
char save_inarith; /* flag indicating POSIX arithmetic context */
memset((char*)sp, 0, sizeof(*sp)); memset((char*)sp, 0, sizeof(*sp));
sfsync(shp->outpool); sfsync(shp->outpool);
sh_sigcheck(shp); sh_sigcheck(shp);
@ -591,6 +592,9 @@ Sfio_t *sh_subshell(Shell_t *shp,Shnode_t *t, volatile int flags, int comsub)
{ {
if(comsub) if(comsub)
{ {
/* a comsub within an arithmetic expression must not itself be in an arithmetic context */
save_inarith = shp->inarith;
shp->inarith = 0;
/* disable job control */ /* disable job control */
shp->spid = 0; shp->spid = 0;
sp->jobcontrol = job.jobcontrol; sp->jobcontrol = job.jobcontrol;
@ -734,6 +738,8 @@ Sfio_t *sh_subshell(Shell_t *shp,Shnode_t *t, volatile int flags, int comsub)
sh_close(sp->tmpfd); sh_close(sp->tmpfd);
} }
shp->fdstatus[1] = sp->fdstatus; shp->fdstatus[1] = sp->fdstatus;
/* restore POSIX arithmetic context flag */
shp->inarith = save_inarith;
} }
if(!shp->subshare) if(!shp->subshare)
{ {

View file

@ -876,5 +876,27 @@ then
fi fi
unset got unset got
# ======
# https://github.com/ksh93/ksh/issues/326
for m in u d i o x X
do
case $m in
o) exp="10;21;32;" ;;
x) exp="8;11;1a;" ;;
X) exp="8;11;1A;" ;;
*) exp="8;17;26;" ;;
esac
got=${ printf "%$m;" 010 021 032; }
[[ $got == "$exp" ]] || err_exit "printf %$m does not recognize octal arguments" \
"(expected $(printf %q "$exp"), got $(printf %q "$got"))"
done
# https://github.com/ksh93/ksh/issues/326#issuecomment-917707463
exp=18
got=$(( $(integer x; x=010; echo $x) + 010 ))
# ^^^ decimal ^^^ octal
[[ $got == "$exp" ]] || err_exit 'Integer with leading zero incorrectly interpreted as octal in non-POSIX arith context' \
"(expected $(printf %q "$exp"), got $(printf %q "$got"))"
# ====== # ======
exit $((Errors<125?Errors:125)) exit $((Errors<125?Errors:125))