fix(parser): diagnose GLOBL and DATA without a symbol name
A bare GLOBL or DATA parsed without a single diagnostic while leaving a nil Name in the tree, a pointer every downstream tool dereferences; TEXT keeps a placeholder beside its error for exactly that reason, and GLOBL and DATA now do the same. The crashing input enters the corpus. Assisted-by: GLM 5.3
This commit is contained in:
1 parent
05de774c0a
commit
bbe14dd1ab
3 files changed
+49
No files matched your search
@@ -0,0 +1,2 @@
|
|||||||
|
go test fuzz v1
|
||||||
|
string("DATA")
|
||||||
@@ -299,6 +299,13 @@ func (p *state) parseGlobl(line []token.Token) *ast.Globl {
|
|||||||
g := &ast.Globl{Keyword: line[0]}
|
g := &ast.Globl{Keyword: line[0]}
|
||||||
rest := skipComma(line[1:])
|
rest := skipComma(line[1:])
|
||||||
sym, n := parseSymbolPrefix(rest)
|
sym, n := parseSymbolPrefix(rest)
|
||||||
|
if sym == nil {
|
||||||
|
// A usable tree without a name cannot be had, and the linter and LSP
|
||||||
|
// dereference Name on every parsed GLOBL, so the decl keeps a
|
||||||
|
// placeholder beside its error, exactly as TEXT does.
|
||||||
|
p.errorf(line[0].Pos, "GLOBL missing a symbol name")
|
||||||
|
sym = &ast.Symbol{Pos: line[0].Pos, Raw: "?", Name: "?"}
|
||||||
|
}
|
||||||
g.Name = sym
|
g.Name = sym
|
||||||
rest = skipComma(rest[n:])
|
rest = skipComma(rest[n:])
|
||||||
// Flags are identifiers (RODATA, DUPOK) or legacy numeric constants
|
// Flags are identifiers (RODATA, DUPOK) or legacy numeric constants
|
||||||
@@ -324,6 +331,12 @@ func (p *state) parseData(line []token.Token) *ast.Data {
|
|||||||
nameGroup, valuePart := splitFirstComma(rest)
|
nameGroup, valuePart := splitFirstComma(rest)
|
||||||
nameGroup, width := splitTrailingWidth(nameGroup)
|
nameGroup, width := splitTrailingWidth(nameGroup)
|
||||||
sym, _ := parseSymbolPrefix(nameGroup)
|
sym, _ := parseSymbolPrefix(nameGroup)
|
||||||
|
if sym == nil {
|
||||||
|
// Same contract as TEXT and GLOBL: the tree stays usable beside its
|
||||||
|
// error, because downstream tools dereference Name unconditionally.
|
||||||
|
p.errorf(line[0].Pos, "DATA missing a symbol name")
|
||||||
|
sym = &ast.Symbol{Pos: line[0].Pos, Raw: "?", Name: "?"}
|
||||||
|
}
|
||||||
d.Name = sym
|
d.Name = sym
|
||||||
d.Width = width
|
d.Width = width
|
||||||
if len(valuePart) > 0 {
|
if len(valuePart) > 0 {
|
||||||
|
|||||||
@@ -383,6 +383,40 @@ func TestTextMissingSymbolKeepsDecl(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestGloblDataMissingSymbolKeepsDecl holds GLOBL and DATA to TEXT's
|
||||||
|
// contract: a directive with no symbol name is a diagnostic, and the decl
|
||||||
|
// stays in the tree with a non-nil placeholder, because downstream tools
|
||||||
|
// dereference Name unconditionally. A bare "DATA" used to parse without a
|
||||||
|
// single error while leaving Name nil behind, a landmine every consumer
|
||||||
|
// stepped on.
|
||||||
|
func TestGloblDataMissingSymbolKeepsDecl(t *testing.T) {
|
||||||
|
for _, tc := range []struct {
|
||||||
|
src string
|
||||||
|
kind string
|
||||||
|
}{
|
||||||
|
{"GLOBL , $8\n", "GLOBL"},
|
||||||
|
{"DATA\n", "DATA"},
|
||||||
|
{"DATA /4, $1\n", "DATA"},
|
||||||
|
} {
|
||||||
|
file, errs := Parse("t.s", tc.src)
|
||||||
|
if len(errs) == 0 {
|
||||||
|
t.Errorf("%s with no symbol: want a diagnostic", tc.kind)
|
||||||
|
}
|
||||||
|
var name *ast.Symbol
|
||||||
|
switch d := file.Decls[0].(type) {
|
||||||
|
case *ast.Globl:
|
||||||
|
name = d.Name
|
||||||
|
case *ast.Data:
|
||||||
|
name = d.Name
|
||||||
|
default:
|
||||||
|
t.Fatalf("%s: decl is %T", tc.kind, d)
|
||||||
|
}
|
||||||
|
if name == nil {
|
||||||
|
t.Errorf("%s: Name must never be nil: downstream tools dereference it", tc.kind)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TestInt64MinimumImmediate covers $-0x8000000000000000: the digits overflow
|
// TestInt64MinimumImmediate covers $-0x8000000000000000: the digits overflow
|
||||||
// int64 when parsed directly, but the negated magnitude is exactly the int64
|
// int64 when parsed directly, but the negated magnitude is exactly the int64
|
||||||
// minimum and must land in Val rather than the float fallback.
|
// minimum and must land in Val rather than the float fallback.
|
||||||
|
|||||||
Reference in new issue
Block a user