ww source: reject raw NUL characters
This commit is contained in:
@@ -18,11 +18,11 @@ toklit(Arena *a, Tok t)
|
||||
}
|
||||
|
||||
static int
|
||||
runrow(const char *src, const char *expect)
|
||||
runrown(const char *src, size_t len, const char *expect, int expecterrs)
|
||||
{
|
||||
Arena *a = newarena();
|
||||
Lex l;
|
||||
lexinit(&l, a, "<test>", src, strlen(src));
|
||||
lexinit(&l, a, "<test>", src, len);
|
||||
|
||||
char *got = amalloc(a, 1);
|
||||
got[0] = '\0';
|
||||
@@ -48,15 +48,23 @@ runrow(const char *src, const char *expect)
|
||||
got[n] = '\0';
|
||||
}
|
||||
|
||||
int ok = strcmp(got, expect) == 0;
|
||||
int ok = strcmp(got, expect) == 0
|
||||
&& (expecterrs < 0 || l.errs == expecterrs);
|
||||
if (!ok) {
|
||||
fprintf(stderr, "lex mismatch:\n src: %s\n"
|
||||
" want: %s\n got: %s\n", src, expect, got);
|
||||
fprintf(stderr, "lex mismatch:\n want: %s (%d errors)\n"
|
||||
" got: %s (%d errors)\n", expect, expecterrs, got,
|
||||
l.errs);
|
||||
}
|
||||
freearena(a);
|
||||
return ok;
|
||||
}
|
||||
|
||||
static int
|
||||
runrow(const char *src, const char *expect)
|
||||
{
|
||||
return runrown(src, strlen(src), expect, -1);
|
||||
}
|
||||
|
||||
struct row { const char *src, *expect; };
|
||||
|
||||
static const struct row rows[] = {
|
||||
@@ -133,11 +141,11 @@ static const struct row rows[] = {
|
||||
* not the token stream. The verbatim Hare messages live at lexunicode
|
||||
* in cmd/wcc/lex.c. */
|
||||
static int
|
||||
runerr(const char *src)
|
||||
runerrn(const char *src, size_t len)
|
||||
{
|
||||
Arena *a = newarena();
|
||||
Lex l;
|
||||
lexinit(&l, a, "<test>", src, strlen(src));
|
||||
lexinit(&l, a, "<test>", src, len);
|
||||
for (;;) {
|
||||
Tok t = lexnext(&l);
|
||||
if (t.kind == TK_EOF)
|
||||
@@ -151,6 +159,12 @@ runerr(const char *src)
|
||||
return ok;
|
||||
}
|
||||
|
||||
static int
|
||||
runerr(const char *src)
|
||||
{
|
||||
return runerrn(src, strlen(src));
|
||||
}
|
||||
|
||||
static int
|
||||
runrewind(void)
|
||||
{
|
||||
@@ -205,6 +219,93 @@ static const char *const errrows[] = {
|
||||
"'\\uDFFF'", /* top of the UTF-16 surrogate range */
|
||||
};
|
||||
|
||||
static const struct {
|
||||
const char *src;
|
||||
size_t len;
|
||||
const char *expect;
|
||||
int errs;
|
||||
} nulrows[] = {
|
||||
{ "\0package main;", sizeof "\0package main;" - 1,
|
||||
"package IDENT(main) ;", 1 },
|
||||
{ "pack\0age main;", sizeof "pack\0age main;" - 1,
|
||||
"package IDENT(main) ;", 1 },
|
||||
{ "1\0_0", sizeof "1\0_0" - 1, "INT(10)", 1 },
|
||||
{ "1f\0oo", sizeof "1f\0oo" - 1, "INT(1) IDENT(foo)", 1 },
|
||||
{ "=\0=", sizeof "=\0=" - 1, "==", 1 },
|
||||
{ "/\0/ comment\nfn", sizeof "/\0/ comment\nfn" - 1, "fn", 1 },
|
||||
{ "/* end *\0/ fn", sizeof "/* end *\0/ fn" - 1, "fn", 1 },
|
||||
{ "\"a\0b\"", sizeof "\"a\0b\"" - 1, "STR(ab)", 1 },
|
||||
{ "'\0A'", sizeof "'\0A'" - 1, "RUNE(65)", 1 },
|
||||
{ "fn\0", sizeof "fn\0" - 1, "fn", 1 },
|
||||
{ "f\0\0n", sizeof "f\0\0n" - 1, "fn", 2 },
|
||||
};
|
||||
|
||||
static int
|
||||
runescapenul(void)
|
||||
{
|
||||
static const char line[] = "\"\\\0n\"";
|
||||
static const char hex[] = "\"\\x0" "\0" "0\"";
|
||||
Arena *a = newarena();
|
||||
Lex l;
|
||||
lexinit(&l, a, "<test>", line, sizeof line - 1);
|
||||
Tok t = lexnext(&l);
|
||||
int ok = t.kind == TK_STR && t.tlen == 1 && t.text[0] == '\n'
|
||||
&& l.errs == 1 && lexnext(&l).kind == TK_EOF;
|
||||
lexinit(&l, a, "<test>", hex, sizeof hex - 1);
|
||||
t = lexnext(&l);
|
||||
ok = ok && t.kind == TK_STR && t.tlen == 1 && t.text[0] == '\0'
|
||||
&& l.errs == 1 && lexnext(&l).kind == TK_EOF;
|
||||
if (!ok)
|
||||
fprintf(stderr, "NUL escape recovery failed\n");
|
||||
freearena(a);
|
||||
return ok;
|
||||
}
|
||||
|
||||
static int
|
||||
runsuffixnul(void)
|
||||
{
|
||||
static const char src[] = "1i" "\0" "8";
|
||||
Arena *a = newarena();
|
||||
Lex l;
|
||||
lexinit(&l, a, "<test>", src, sizeof src - 1);
|
||||
Tok t = lexnext(&l);
|
||||
int ok = t.kind == TK_INT && t.v.uval == 1 && t.tsuffix != NULL
|
||||
&& strcmp(t.tsuffix, "i8") == 0 && l.errs == 1
|
||||
&& lexnext(&l).kind == TK_EOF;
|
||||
if (!ok)
|
||||
fprintf(stderr, "NUL typed-suffix recovery failed\n");
|
||||
freearena(a);
|
||||
return ok;
|
||||
}
|
||||
|
||||
static int
|
||||
runlongdirective(void)
|
||||
{
|
||||
static const char pre[] = "//ww:module ";
|
||||
static const char tail[] = "\nfn";
|
||||
const size_t pathlen = 16384;
|
||||
const size_t len = sizeof pre - 1 + pathlen + sizeof tail - 1;
|
||||
char *src = malloc(len);
|
||||
if (!src)
|
||||
return 0;
|
||||
memcpy(src, pre, sizeof pre - 1);
|
||||
memset(src + sizeof pre - 1, 'a', pathlen);
|
||||
memcpy(src + sizeof pre - 1 + pathlen, tail, sizeof tail - 1);
|
||||
Arena *a = newarena();
|
||||
Lex l;
|
||||
lexinit(&l, a, "<test>", src, len);
|
||||
Tok m = lexnext(&l);
|
||||
Tok f = lexnext(&l);
|
||||
int ok = m.kind == TK_MODPATH && m.tlen == pathlen
|
||||
&& m.text[0] == 'a' && m.text[pathlen - 1] == 'a'
|
||||
&& f.kind == TK_FN && l.errs == 0;
|
||||
if (!ok)
|
||||
fprintf(stderr, "long module directive failed\n");
|
||||
freearena(a);
|
||||
free(src);
|
||||
return ok;
|
||||
}
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
@@ -225,6 +326,19 @@ main(void)
|
||||
fail++;
|
||||
}
|
||||
}
|
||||
for (size_t i = 0; i < sizeof nulrows / sizeof nulrows[0]; i++) {
|
||||
if (!runrown(nulrows[i].src, nulrows[i].len,
|
||||
nulrows[i].expect, nulrows[i].errs)) {
|
||||
fprintf(stderr, "NUL row %zu failed\n", i);
|
||||
fail++;
|
||||
}
|
||||
}
|
||||
if (!runescapenul())
|
||||
fail++;
|
||||
if (!runsuffixnul())
|
||||
fail++;
|
||||
if (!runlongdirective())
|
||||
fail++;
|
||||
if (fail) {
|
||||
fprintf(stderr, "%d/%zu lex tests failed\n", fail,
|
||||
sizeof rows / sizeof rows[0]);
|
||||
|
||||
Reference in New Issue
Block a user