Skip to content

Commit 8a6ac6d

Browse files
authored
Set errno when out of range in strtoimax (#111)
1 parent f5da4ef commit 8a6ac6d

File tree

5 files changed

+29
-5
lines changed

5 files changed

+29
-5
lines changed

libc/fmt/strtoimax.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
│ PERFORMANCE OF THIS SOFTWARE. │
1818
╚─────────────────────────────────────────────────────────────────────────────*/
1919
#include "libc/fmt/conv.h"
20+
#include "libc/errno.h"
2021
#include "libc/limits.h"
2122
#include "libc/nexgen32e/bsr.h"
2223
#include "libc/str/str.h"
@@ -85,7 +86,7 @@ intmax_t strtoimax(const char *s, char **endptr, int base) {
8586
diglet = kBase36[*s & 0xff];
8687
if (!diglet || diglet > base) break;
8788
diglet -= 1;
88-
if (!diglet || !x || (bits = bsr(diglet) + bsrmax(x)) < 127) {
89+
if (!x || (bits = (diglet ? bsr(diglet) : 0) + bsrmax(x * base)) < 127) {
8990
s++;
9091
x *= base;
9192
x += diglet;
@@ -96,9 +97,11 @@ intmax_t strtoimax(const char *s, char **endptr, int base) {
9697
if (x == INTMAX_MIN) s++;
9798
}
9899
x = INTMAX_MIN;
100+
errno = ERANGE;
99101
break;
100102
} else {
101103
x = INTMAX_MAX;
104+
errno = ERANGE;
102105
break;
103106
}
104107
}

test/libc/fmt/strtoimax_test.c

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,17 @@ TEST(strtoimax, testLimits) {
5353
strtoimax("0x7fffffffffffffffffffffffffffffff", NULL, 0));
5454
}
5555

56-
TEST(strtoimax, testTwosBane) {
57-
EXPECT_EQ(((uintmax_t)0x8000000000000000) << 64 | 0x0000000000000000,
58-
strtoimax("0x80000000000000000000000000000000", NULL, 0));
56+
TEST(strtoimax, testOutsideLimit) {
57+
errno = 0;
58+
EXPECT_EQ(
59+
((uintmax_t)0x7fffffffffffffff) << 64 | (uintmax_t)0xffffffffffffffff,
60+
strtoimax("0x80000000000000000000000000000000", NULL, 0));
61+
EXPECT_EQ(ERANGE, errno);
62+
errno = 0;
63+
EXPECT_EQ(
64+
((uintmax_t)0x8000000000000000) << 64 | 0x0000000000000000,
65+
strtoimax("-0x80000000000000000000000000000001", NULL, 0));
66+
EXPECT_EQ(ERANGE, errno);
5967
}
6068

6169
TEST(strtoul, neghex) {

test/libc/fmt/strtoumax_test.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,3 +46,8 @@ TEST(strtoumax, testMaximum) {
4646
EXPECT_EQ(UINTMAX_MAX,
4747
strtoumax("0xffffffffffffffffffffffffffffffff", NULL, 0));
4848
}
49+
50+
TEST(strtoumax, testTwosBane) {
51+
EXPECT_EQ(((uintmax_t)0x8000000000000000) << 64 | 0x0000000000000000,
52+
strtoumax("0x80000000000000000000000000000000", NULL, 0));
53+
}

tool/build/calculator.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -443,7 +443,7 @@ bool ConsumeLiteral(const char *literal) {
443443
char *e;
444444
struct Value x;
445445
x.t = kInt;
446-
x.i = strtoimax(literal, &e, 0);
446+
x.i = *literal == '-' ? strtoimax(literal, &e, 0) : strtoumax(literal, &e, 0);
447447
if (!e || *e) {
448448
x.t = kFloat;
449449
x.f = strtod(literal, &e);

tool/build/calculator.ctest

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,3 +81,11 @@ false false || ! assert
8181
1 -1 min -1 = assert
8282
1 2 min 1 = assert
8383
rand64 rand64 rand64 rand64 != != && assert
84+
85+
# HEX SIGN
86+
-0x80000000 -2147483648 = assert
87+
0x80000000 2147483648 = assert
88+
0x80000001 2147483649 = assert
89+
0xffffffff 4294967295 = assert
90+
0x100000000 4294967296 = assert
91+
-0x100000000 -4294967296 = assert

0 commit comments

Comments
 (0)