From b56d524da406e3b0778a832aaf78fe24de9cf44e Mon Sep 17 00:00:00 2001 From: Jilles Tjoelker Date: Wed, 13 Mar 2019 21:53:10 +0000 Subject: [PATCH] MFC r342880,r343981,r344902: sh: Fix $((-9223372036854775808)) Since $((9223372036854775808)) overflows, $((-9223372036854775808)) was not parsed correctly (with x=-9223372036854775808, $((x)) already worked, since that parses the value with the minus sign in one step). Values further from zero are still clamped to 9223372036854775807. Also, allow the full 64 bits in octal and hexadecimal. --- bin/sh/arith_yacc.c | 2 +- bin/sh/arith_yacc.h | 1 + bin/sh/arith_yylex.c | 30 +++++++++++++++++++++++++++++- bin/sh/shell.h | 2 -- bin/sh/tests/expansion/Makefile | 3 +++ bin/sh/tests/expansion/arith15.0 | 20 ++++++++++++++++++++ bin/sh/tests/expansion/arith16.0 | 26 ++++++++++++++++++++++++++ bin/sh/tests/expansion/arith17.0 | 3 +++ 8 files changed, 83 insertions(+), 4 deletions(-) create mode 100644 bin/sh/tests/expansion/arith15.0 create mode 100644 bin/sh/tests/expansion/arith16.0 create mode 100644 bin/sh/tests/expansion/arith17.0 diff --git a/bin/sh/arith_yacc.c b/bin/sh/arith_yacc.c index 5000c6b0d1b..a08163bdc29 100644 --- a/bin/sh/arith_yacc.c +++ b/bin/sh/arith_yacc.c @@ -104,7 +104,7 @@ static arith_t arith_lookupvarint(char *varname) if (str == NULL || *str == '\0') str = "0"; errno = 0; - result = strtoarith_t(str, &p, 0); + result = strtoarith_t(str, &p); if (errno != 0 || *p != '\0') yyerror("variable conversion error"); return result; diff --git a/bin/sh/arith_yacc.h b/bin/sh/arith_yacc.h index ca92e6f7fa1..7fdd99b75b5 100644 --- a/bin/sh/arith_yacc.h +++ b/bin/sh/arith_yacc.h @@ -90,4 +90,5 @@ union yystype { extern union yystype yylval; +arith_t strtoarith_t(const char *restrict nptr, char **restrict endptr); int yylex(void); diff --git a/bin/sh/arith_yylex.c b/bin/sh/arith_yylex.c index f7eaf3e3fa6..9f320dbcb58 100644 --- a/bin/sh/arith_yylex.c +++ b/bin/sh/arith_yylex.c @@ -35,6 +35,8 @@ #include __FBSDID("$FreeBSD$"); +#include +#include #include #include #include @@ -50,6 +52,32 @@ __FBSDID("$FreeBSD$"); #error Arithmetic tokens are out of order. #endif +arith_t +strtoarith_t(const char *restrict nptr, char **restrict endptr) +{ + arith_t val; + + while (isspace((unsigned char)*nptr)) + nptr++; + switch (*nptr) { + case '-': + return strtoimax(nptr, endptr, 0); + case '0': + return (arith_t)strtoumax(nptr, endptr, 0); + default: + val = (arith_t)strtoumax(nptr, endptr, 0); + if (val >= 0) + return val; + else if (val == ARITH_MIN) { + errno = ERANGE; + return ARITH_MIN; + } else { + errno = ERANGE; + return ARITH_MAX; + } + } +} + int yylex(void) { @@ -78,7 +106,7 @@ yylex(void) case '7': case '8': case '9': - yylval.val = strtoarith_t(buf, &end, 0); + yylval.val = strtoarith_t(buf, &end); arith_buf = end; return ARITH_NUM; case 'A': diff --git a/bin/sh/shell.h b/bin/sh/shell.h index 0b25587c59f..c06e737e658 100644 --- a/bin/sh/shell.h +++ b/bin/sh/shell.h @@ -59,8 +59,6 @@ */ typedef intmax_t arith_t; #define ARITH_FORMAT_STR "%" PRIdMAX -#define atoarith_t(arg) strtoimax(arg, NULL, 0) -#define strtoarith_t(nptr, endptr, base) strtoimax(nptr, endptr, base) #define ARITH_MIN INTMAX_MIN #define ARITH_MAX INTMAX_MAX diff --git a/bin/sh/tests/expansion/Makefile b/bin/sh/tests/expansion/Makefile index 4f344c4a516..58df967304f 100644 --- a/bin/sh/tests/expansion/Makefile +++ b/bin/sh/tests/expansion/Makefile @@ -21,6 +21,9 @@ ${PACKAGE}FILES+= arith11.0 ${PACKAGE}FILES+= arith12.0 ${PACKAGE}FILES+= arith13.0 ${PACKAGE}FILES+= arith14.0 +${PACKAGE}FILES+= arith15.0 +${PACKAGE}FILES+= arith16.0 +${PACKAGE}FILES+= arith17.0 ${PACKAGE}FILES+= assign1.0 ${PACKAGE}FILES+= cmdsubst1.0 ${PACKAGE}FILES+= cmdsubst2.0 diff --git a/bin/sh/tests/expansion/arith15.0 b/bin/sh/tests/expansion/arith15.0 new file mode 100644 index 00000000000..32b35bb907c --- /dev/null +++ b/bin/sh/tests/expansion/arith15.0 @@ -0,0 +1,20 @@ +# $FreeBSD$ + +failures=0 + +check() { + if [ $(($1)) != $2 ]; then + failures=$((failures+1)) + echo "For $1, expected $2 actual $(($1))" + fi +} + +XXX=-9223372036854775808 +check "XXX" -9223372036854775808 +check "XXX - 1" 9223372036854775807 +check "$XXX - 1" 9223372036854775807 +check "$XXX - 2" 9223372036854775806 +check "0x8000000000000000 == 0x7fffffffffffffff" \ + 0 + +exit $((failures != 0)) diff --git a/bin/sh/tests/expansion/arith16.0 b/bin/sh/tests/expansion/arith16.0 new file mode 100644 index 00000000000..b764e3c216f --- /dev/null +++ b/bin/sh/tests/expansion/arith16.0 @@ -0,0 +1,26 @@ +# $FreeBSD$ + +failures=0 + +for x in \ + 0x10000000000000000 \ + -0x8000000000000001 \ + 0xfffffffffffffffffffffffffffffffff \ + -0xfffffffffffffffffffffffffffffffff \ + 02000000000000000000000 \ + 9223372036854775808 \ + 9223372036854775809 \ + -9223372036854775809 \ + 9999999999999999999999999 \ + -9999999999999999999999999 +do + msg=$({ + v=$((x)) || : + } 3>&1 >&2 2>&3 3>&-) + r=$? + if [ "$r" = 0 ] || [ -z "$msg" ]; then + printf 'Failed: %s\n' "$x" + : $((failures += 1)) + fi +done +exit $((failures > 0)) diff --git a/bin/sh/tests/expansion/arith17.0 b/bin/sh/tests/expansion/arith17.0 new file mode 100644 index 00000000000..0a9260886dd --- /dev/null +++ b/bin/sh/tests/expansion/arith17.0 @@ -0,0 +1,3 @@ +# $FreeBSD$ + +[ $((9223372036854775809)) -gt 0 ] -- 2.45.0