Set errno when out of range in strtoimax (#111)

This commit is contained in:
Alison Winters 2021-03-07 14:38:56 -08:00 committed by GitHub
parent f5da4efcaf
commit 8a6ac6dd63
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 29 additions and 5 deletions

View file

@ -17,6 +17,7 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/fmt/conv.h" #include "libc/fmt/conv.h"
#include "libc/errno.h"
#include "libc/limits.h" #include "libc/limits.h"
#include "libc/nexgen32e/bsr.h" #include "libc/nexgen32e/bsr.h"
#include "libc/str/str.h" #include "libc/str/str.h"
@ -85,7 +86,7 @@ intmax_t strtoimax(const char *s, char **endptr, int base) {
diglet = kBase36[*s & 0xff]; diglet = kBase36[*s & 0xff];
if (!diglet || diglet > base) break; if (!diglet || diglet > base) break;
diglet -= 1; diglet -= 1;
if (!diglet || !x || (bits = bsr(diglet) + bsrmax(x)) < 127) { if (!x || (bits = (diglet ? bsr(diglet) : 0) + bsrmax(x * base)) < 127) {
s++; s++;
x *= base; x *= base;
x += diglet; x += diglet;
@ -96,9 +97,11 @@ intmax_t strtoimax(const char *s, char **endptr, int base) {
if (x == INTMAX_MIN) s++; if (x == INTMAX_MIN) s++;
} }
x = INTMAX_MIN; x = INTMAX_MIN;
errno = ERANGE;
break; break;
} else { } else {
x = INTMAX_MAX; x = INTMAX_MAX;
errno = ERANGE;
break; break;
} }
} }

View file

@ -53,9 +53,17 @@ TEST(strtoimax, testLimits) {
strtoimax("0x7fffffffffffffffffffffffffffffff", NULL, 0)); strtoimax("0x7fffffffffffffffffffffffffffffff", NULL, 0));
} }
TEST(strtoimax, testTwosBane) { TEST(strtoimax, testOutsideLimit) {
EXPECT_EQ(((uintmax_t)0x8000000000000000) << 64 | 0x0000000000000000, errno = 0;
strtoimax("0x80000000000000000000000000000000", NULL, 0)); EXPECT_EQ(
((uintmax_t)0x7fffffffffffffff) << 64 | (uintmax_t)0xffffffffffffffff,
strtoimax("0x80000000000000000000000000000000", NULL, 0));
EXPECT_EQ(ERANGE, errno);
errno = 0;
EXPECT_EQ(
((uintmax_t)0x8000000000000000) << 64 | 0x0000000000000000,
strtoimax("-0x80000000000000000000000000000001", NULL, 0));
EXPECT_EQ(ERANGE, errno);
} }
TEST(strtoul, neghex) { TEST(strtoul, neghex) {

View file

@ -46,3 +46,8 @@ TEST(strtoumax, testMaximum) {
EXPECT_EQ(UINTMAX_MAX, EXPECT_EQ(UINTMAX_MAX,
strtoumax("0xffffffffffffffffffffffffffffffff", NULL, 0)); strtoumax("0xffffffffffffffffffffffffffffffff", NULL, 0));
} }
TEST(strtoumax, testTwosBane) {
EXPECT_EQ(((uintmax_t)0x8000000000000000) << 64 | 0x0000000000000000,
strtoumax("0x80000000000000000000000000000000", NULL, 0));
}

View file

@ -443,7 +443,7 @@ bool ConsumeLiteral(const char *literal) {
char *e; char *e;
struct Value x; struct Value x;
x.t = kInt; x.t = kInt;
x.i = strtoimax(literal, &e, 0); x.i = *literal == '-' ? strtoimax(literal, &e, 0) : strtoumax(literal, &e, 0);
if (!e || *e) { if (!e || *e) {
x.t = kFloat; x.t = kFloat;
x.f = strtod(literal, &e); x.f = strtod(literal, &e);

View file

@ -81,3 +81,11 @@ false false || ! assert
1 -1 min -1 = assert 1 -1 min -1 = assert
1 2 min 1 = assert 1 2 min 1 = assert
rand64 rand64 rand64 rand64 != != && assert rand64 rand64 rand64 rand64 != != && assert
# HEX SIGN
-0x80000000 -2147483648 = assert
0x80000000 2147483648 = assert
0x80000001 2147483649 = assert
0xffffffff 4294967295 = assert
0x100000000 4294967296 = assert
-0x100000000 -4294967296 = assert