wcc: reject final-band integer overflow; restore rewind columns
This commit is contained in:
@@ -181,6 +181,9 @@ static u64
|
||||
parseint(const char *s, u64 n, int base, int *ok)
|
||||
{
|
||||
u64 v = 0;
|
||||
u64 b = (u64)base;
|
||||
u64 cutoff = (u64)~0ULL / b;
|
||||
u64 cutlim = (u64)~0ULL % b;
|
||||
int got = 0;
|
||||
for (u64 i = 0; i < n; i++) {
|
||||
int c = (unsigned char)s[i];
|
||||
@@ -192,9 +195,11 @@ parseint(const char *s, u64 n, int base, int *ok)
|
||||
else if (c >= 'A' && c <= 'F') d = c - 'A' + 10;
|
||||
else { *ok = 0; return 0; }
|
||||
if (d >= base) { *ok = 0; return 0; }
|
||||
/* overflow? cheap check */
|
||||
if (v > (u64)~0ULL / (u64)base) { *ok = 0; return 0; }
|
||||
v = v * (u64)base + (u64)d;
|
||||
if (v > cutoff || (v == cutoff && (u64)d > cutlim)) {
|
||||
*ok = 0;
|
||||
return 0;
|
||||
}
|
||||
v = v * b + (u64)d;
|
||||
got = 1;
|
||||
}
|
||||
*ok = got;
|
||||
@@ -369,6 +374,7 @@ lexnum(Lex *l, Pos start)
|
||||
/* A typed suffix must be glued (no whitespace) to the digits. */
|
||||
if (isidstart(lpeek(l, 0))) {
|
||||
u64 sb = l->pos;
|
||||
i32 sc = l->col;
|
||||
while (isidcont(lpeek(l, 0))) lget(l);
|
||||
u64 sl = l->pos - sb;
|
||||
const char *names[] = {
|
||||
@@ -387,9 +393,8 @@ lexnum(Lex *l, Pos start)
|
||||
if (match) {
|
||||
t.tsuffix = astrndup(l->a, l->src + sb, sl);
|
||||
} else {
|
||||
/* not a known suffix — rewind so the run becomes a
|
||||
* separate token. */
|
||||
l->pos = sb;
|
||||
l->col = sc;
|
||||
}
|
||||
}
|
||||
return t;
|
||||
|
||||
@@ -269,6 +269,9 @@ fn skipws(l: *lex) bool = {
|
||||
|
||||
fn parseint(p: *u8, n: u64, base: i32, ok: *bool) u64 = {
|
||||
let v: u64 = 0u64;
|
||||
let b: u64 = base: u64;
|
||||
let cutoff: u64 = ~0u64 / b;
|
||||
let cutlim: u64 = ~0u64 % b;
|
||||
let got: bool = false;
|
||||
let i: u64 = 0u64;
|
||||
for (i < n) {
|
||||
@@ -294,8 +297,11 @@ fn parseint(p: *u8, n: u64, base: i32, ok: *bool) u64 = {
|
||||
};
|
||||
if (d < 0) { *ok = false; return 0u64; };
|
||||
if (d >= base) { *ok = false; return 0u64; };
|
||||
if (v > ~0u64 / (base: u64)) { *ok = false; return 0u64; };
|
||||
v = v * (base: u64) + (d: u64);
|
||||
if (v > cutoff || (v == cutoff && (d: u64) > cutlim)) {
|
||||
*ok = false;
|
||||
return 0u64;
|
||||
};
|
||||
v = v * b + (d: u64);
|
||||
got = true;
|
||||
i += 1u64;
|
||||
};
|
||||
@@ -551,6 +557,7 @@ fn lexnum(l: *lex, start: *pos, out: *tok) void = {
|
||||
if (pc >= 0) {
|
||||
if (isidstart(pc: rune)) {
|
||||
let sb: u64 = l.lpos;
|
||||
let sc: i32 = l.col;
|
||||
for (true) {
|
||||
let cc: i32 = lpeek(l, 0u64);
|
||||
if (cc < 0) { break; };
|
||||
@@ -591,6 +598,7 @@ fn lexnum(l: *lex, start: *pos, out: *tok) void = {
|
||||
out.tsuffix = strings.dup(view);
|
||||
} else {
|
||||
l.lpos = sb;
|
||||
l.col = sc;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -309,3 +309,32 @@ fn checkfloat(src: str, want: u64) void = {
|
||||
checkfloat("1.0e308", 0x7FE1CCF385EBC8A0u64);
|
||||
checkfloat("2.225073858507202e-308", 0x0010000000000001u64);
|
||||
};
|
||||
|
||||
@test fn intfinalband() void = {
|
||||
let src: str = "18446744073709551616";
|
||||
let l: lex;
|
||||
lexinit(&l, "t", src.ptr, src.len: u64);
|
||||
let t: tok;
|
||||
lexnext(&l, &t);
|
||||
assert(!(t.kind != tkind.TK_ERR));
|
||||
assert(!(l.errs != 1));
|
||||
};
|
||||
|
||||
@test fn suffixrewindcols() void = {
|
||||
let src: str = "1foo bar";
|
||||
let l: lex;
|
||||
lexinit(&l, "t", src.ptr, src.len: u64);
|
||||
let t: tok;
|
||||
lexnext(&l, &t);
|
||||
assert(!(t.kind != tkind.TK_INT));
|
||||
assert(!(t.col != 1));
|
||||
assert(!(t.uval != 1u64));
|
||||
lexnext(&l, &t);
|
||||
assert(!(t.kind != tkind.TK_IDENT));
|
||||
assert(!(t.col != 2));
|
||||
assert(!(t.text != "foo"));
|
||||
lexnext(&l, &t);
|
||||
assert(!(t.kind != tkind.TK_IDENT));
|
||||
assert(!(t.col != 6));
|
||||
assert(!(t.text != "bar"));
|
||||
};
|
||||
|
||||
@@ -80,6 +80,7 @@ static const struct row rows[] = {
|
||||
{ "0xDE_AD_BE_EF", "INT(3735928559)" },
|
||||
{ "0b1010", "INT(10)" },
|
||||
{ "0o777", "INT(511)" },
|
||||
{ "18446744073709551616", "ERR(18446744073709551616)" },
|
||||
{ "3.14", "FLOAT(3.14)" },
|
||||
{ "1.5e3", "FLOAT(1500)" },
|
||||
|
||||
@@ -149,6 +150,28 @@ runerr(const char *src)
|
||||
return ok;
|
||||
}
|
||||
|
||||
static int
|
||||
runrewind(void)
|
||||
{
|
||||
const char *src = "1foo bar";
|
||||
Arena *a = newarena();
|
||||
Lex l;
|
||||
lexinit(&l, a, "<test>", src, strlen(src));
|
||||
Tok n = lexnext(&l);
|
||||
Tok f = lexnext(&l);
|
||||
Tok b = lexnext(&l);
|
||||
int ok = n.kind == TK_INT && n.pos.col == 1 && n.v.uval == 1
|
||||
&& f.kind == TK_IDENT && f.pos.col == 2
|
||||
&& strcmp(f.text, "foo") == 0
|
||||
&& b.kind == TK_IDENT && b.pos.col == 6
|
||||
&& strcmp(b.text, "bar") == 0;
|
||||
if (!ok)
|
||||
fprintf(stderr, "suffix rewind columns: want 1,2,6 got %d,%d,%d\n",
|
||||
n.pos.col, f.pos.col, b.pos.col);
|
||||
freearena(a);
|
||||
return ok;
|
||||
}
|
||||
|
||||
static const char *const errrows[] = {
|
||||
"'\\uZ'", /* unexpected rune scanning for escape */
|
||||
"\"\\u00g0\"", /* non-hex digit inside a string escape */
|
||||
@@ -169,6 +192,8 @@ main(void)
|
||||
fail++;
|
||||
}
|
||||
}
|
||||
if (!runrewind())
|
||||
fail++;
|
||||
for (size_t i = 0; i < sizeof errrows / sizeof errrows[0]; i++) {
|
||||
if (!runerr(errrows[i])) {
|
||||
fprintf(stderr, "errrow %zu failed\n", i);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//ww:error "bad integer literal"
|
||||
// 989_intoverflow_reject dec_overflow: a 21-digit decimal exceeds u64.
|
||||
// Exact final-digit band: MAX/10 with 6 greater than MAX%10.
|
||||
package main;
|
||||
export fn main() i32 = {
|
||||
let x: u64 = 99999999999999999999u64;
|
||||
let x: u64 = 18446744073709551616u64;
|
||||
return x: i32;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user