Commit 5e89acb5 authored by Rob Pike's avatar Rob Pike

cmd/asm: fix some fuzz bugs

One (12466) was an actual logic error, backing up when there was
nothing there. The others were due to continuing to process an
instruction when it cannot work.

Methodically stop assembling an instruction when it's not going to
succeed.

Fixes #12466.
Fixes #12467.
Fixes #12468.

Change-Id: I88c568f2b9c1a8408043b2ac5a78f5e2ffd62abd
Reviewed-on: https://go-review.googlesource.com/14498Reviewed-by: default avatarAndrew Gerrand <adg@golang.org>
parent 2b50e6b4
...@@ -27,15 +27,18 @@ func (p *Parser) append(prog *obj.Prog, cond string, doLabel bool) { ...@@ -27,15 +27,18 @@ func (p *Parser) append(prog *obj.Prog, cond string, doLabel bool) {
case '5': case '5':
if !arch.ARMConditionCodes(prog, cond) { if !arch.ARMConditionCodes(prog, cond) {
p.errorf("unrecognized condition code .%q", cond) p.errorf("unrecognized condition code .%q", cond)
return
} }
case '7': case '7':
if !arch.ARM64Suffix(prog, cond) { if !arch.ARM64Suffix(prog, cond) {
p.errorf("unrecognized suffix .%q", cond) p.errorf("unrecognized suffix .%q", cond)
return
} }
default: default:
p.errorf("unrecognized suffix .%q", cond) p.errorf("unrecognized suffix .%q", cond)
return
} }
} }
if p.firstProg == nil { if p.firstProg == nil {
...@@ -49,6 +52,7 @@ func (p *Parser) append(prog *obj.Prog, cond string, doLabel bool) { ...@@ -49,6 +52,7 @@ func (p *Parser) append(prog *obj.Prog, cond string, doLabel bool) {
for _, label := range p.pendingLabels { for _, label := range p.pendingLabels {
if p.labels[label] != nil { if p.labels[label] != nil {
p.errorf("label %q multiply defined", label) p.errorf("label %q multiply defined", label)
return
} }
p.labels[label] = prog p.labels[label] = prog
} }
...@@ -67,8 +71,7 @@ func (p *Parser) append(prog *obj.Prog, cond string, doLabel bool) { ...@@ -67,8 +71,7 @@ func (p *Parser) append(prog *obj.Prog, cond string, doLabel bool) {
func (p *Parser) validateSymbol(pseudo string, addr *obj.Addr, offsetOk bool) { func (p *Parser) validateSymbol(pseudo string, addr *obj.Addr, offsetOk bool) {
if addr.Name != obj.NAME_EXTERN && addr.Name != obj.NAME_STATIC || addr.Scale != 0 || addr.Reg != 0 { if addr.Name != obj.NAME_EXTERN && addr.Name != obj.NAME_STATIC || addr.Scale != 0 || addr.Reg != 0 {
p.errorf("%s symbol %q must be a symbol(SB)", pseudo, symbolName(addr)) p.errorf("%s symbol %q must be a symbol(SB)", pseudo, symbolName(addr))
} } else if !offsetOk && addr.Offset != 0 {
if !offsetOk && addr.Offset != 0 {
p.errorf("%s symbol %q must not be offset from SB", pseudo, symbolName(addr)) p.errorf("%s symbol %q must not be offset from SB", pseudo, symbolName(addr))
} }
} }
...@@ -144,6 +147,7 @@ func (p *Parser) asmText(word string, operands [][]lex.Token) { ...@@ -144,6 +147,7 @@ func (p *Parser) asmText(word string, operands [][]lex.Token) {
// There is an argument size. It must be a minus sign followed by a non-negative integer literal. // There is an argument size. It must be a minus sign followed by a non-negative integer literal.
if len(op) != 2 || op[0].ScanToken != '-' || op[1].ScanToken != scanner.Int { if len(op) != 2 || op[0].ScanToken != '-' || op[1].ScanToken != scanner.Int {
p.errorf("TEXT %s: argument size must be of form -integer", name) p.errorf("TEXT %s: argument size must be of form -integer", name)
return
} }
argSize = p.positiveAtoi(op[1].String()) argSize = p.positiveAtoi(op[1].String())
} }
...@@ -195,11 +199,13 @@ func (p *Parser) asmData(word string, operands [][]lex.Token) { ...@@ -195,11 +199,13 @@ func (p *Parser) asmData(word string, operands [][]lex.Token) {
// OK // OK
default: default:
p.errorf("DATA value must be an immediate constant or address") p.errorf("DATA value must be an immediate constant or address")
return
} }
// The addresses must not overlap. Easiest test: require monotonicity. // The addresses must not overlap. Easiest test: require monotonicity.
if lastAddr, ok := p.dataAddr[name]; ok && nameAddr.Offset < lastAddr { if lastAddr, ok := p.dataAddr[name]; ok && nameAddr.Offset < lastAddr {
p.errorf("overlapping DATA entry for %s", name) p.errorf("overlapping DATA entry for %s", name)
return
} }
p.dataAddr[name] = nameAddr.Offset + int64(scale) p.dataAddr[name] = nameAddr.Offset + int64(scale)
...@@ -340,6 +346,7 @@ func (p *Parser) asmJump(op int, cond string, a []obj.Addr) { ...@@ -340,6 +346,7 @@ func (p *Parser) asmJump(op int, cond string, a []obj.Addr) {
reg, ok := p.arch.RegisterNumber("R", int16(reg)) reg, ok := p.arch.RegisterNumber("R", int16(reg))
if !ok { if !ok {
p.errorf("bad register number %d", reg) p.errorf("bad register number %d", reg)
return
} }
prog.Reg = reg prog.Reg = reg
break break
...@@ -390,6 +397,7 @@ func (p *Parser) asmJump(op int, cond string, a []obj.Addr) { ...@@ -390,6 +397,7 @@ func (p *Parser) asmJump(op int, cond string, a []obj.Addr) {
prog.To = a[0] prog.To = a[0]
default: default:
p.errorf("cannot assemble jump %+v", target) p.errorf("cannot assemble jump %+v", target)
return
} }
p.append(prog, cond, true) p.append(prog, cond, true)
...@@ -400,9 +408,9 @@ func (p *Parser) patch() { ...@@ -400,9 +408,9 @@ func (p *Parser) patch() {
targetProg := p.labels[patch.label] targetProg := p.labels[patch.label]
if targetProg == nil { if targetProg == nil {
p.errorf("undefined label %s", patch.label) p.errorf("undefined label %s", patch.label)
} else { return
p.branch(patch.prog, targetProg)
} }
p.branch(patch.prog, targetProg)
} }
p.toPatch = p.toPatch[:0] p.toPatch = p.toPatch[:0]
} }
...@@ -468,6 +476,7 @@ func (p *Parser) asmInstruction(op int, cond string, a []obj.Addr) { ...@@ -468,6 +476,7 @@ func (p *Parser) asmInstruction(op int, cond string, a []obj.Addr) {
break break
} }
p.errorf("unrecognized addressing for %s", obj.Aconv(op)) p.errorf("unrecognized addressing for %s", obj.Aconv(op))
return
} }
if arch.IsARMFloatCmp(op) { if arch.IsARMFloatCmp(op) {
prog.From = a[0] prog.From = a[0]
...@@ -506,6 +515,7 @@ func (p *Parser) asmInstruction(op int, cond string, a []obj.Addr) { ...@@ -506,6 +515,7 @@ func (p *Parser) asmInstruction(op int, cond string, a []obj.Addr) {
prog.To = a[1] prog.To = a[1]
if a[2].Type != obj.TYPE_REG { if a[2].Type != obj.TYPE_REG {
p.errorf("invalid addressing modes for third operand to %s instruction, must be register", obj.Aconv(op)) p.errorf("invalid addressing modes for third operand to %s instruction, must be register", obj.Aconv(op))
return
} }
prog.RegTo2 = a[2].Reg prog.RegTo2 = a[2].Reg
break break
...@@ -541,9 +551,11 @@ func (p *Parser) asmInstruction(op int, cond string, a []obj.Addr) { ...@@ -541,9 +551,11 @@ func (p *Parser) asmInstruction(op int, cond string, a []obj.Addr) {
prog.To = a[2] prog.To = a[2]
default: default:
p.errorf("invalid addressing modes for %s instruction", obj.Aconv(op)) p.errorf("invalid addressing modes for %s instruction", obj.Aconv(op))
return
} }
default: default:
p.errorf("TODO: implement three-operand instructions for this architecture") p.errorf("TODO: implement three-operand instructions for this architecture")
return
} }
case 4: case 4:
if p.arch.Thechar == '5' && arch.IsARMMULA(op) { if p.arch.Thechar == '5' && arch.IsARMMULA(op) {
...@@ -577,6 +589,7 @@ func (p *Parser) asmInstruction(op int, cond string, a []obj.Addr) { ...@@ -577,6 +589,7 @@ func (p *Parser) asmInstruction(op int, cond string, a []obj.Addr) {
break break
} }
p.errorf("can't handle %s instruction with 4 operands", obj.Aconv(op)) p.errorf("can't handle %s instruction with 4 operands", obj.Aconv(op))
return
case 5: case 5:
if p.arch.Thechar == '9' && arch.IsPPC64RLD(op) { if p.arch.Thechar == '9' && arch.IsPPC64RLD(op) {
// Always reg, reg, con, con, reg. (con, con is a 'mask'). // Always reg, reg, con, con, reg. (con, con is a 'mask').
...@@ -598,6 +611,7 @@ func (p *Parser) asmInstruction(op int, cond string, a []obj.Addr) { ...@@ -598,6 +611,7 @@ func (p *Parser) asmInstruction(op int, cond string, a []obj.Addr) {
break break
} }
p.errorf("can't handle %s instruction with 5 operands", obj.Aconv(op)) p.errorf("can't handle %s instruction with 5 operands", obj.Aconv(op))
return
case 6: case 6:
if p.arch.Thechar == '5' && arch.IsARMMRC(op) { if p.arch.Thechar == '5' && arch.IsARMMRC(op) {
// Strange special case: MCR, MRC. // Strange special case: MCR, MRC.
...@@ -621,6 +635,7 @@ func (p *Parser) asmInstruction(op int, cond string, a []obj.Addr) { ...@@ -621,6 +635,7 @@ func (p *Parser) asmInstruction(op int, cond string, a []obj.Addr) {
fallthrough fallthrough
default: default:
p.errorf("can't handle %s instruction with %d operands", obj.Aconv(op), len(a)) p.errorf("can't handle %s instruction with %d operands", obj.Aconv(op), len(a))
return
} }
p.append(prog, cond, true) p.append(prog, cond, true)
......
...@@ -293,6 +293,7 @@ var armOperandTests = []operandTest{ ...@@ -293,6 +293,7 @@ var armOperandTests = []operandTest{
{"[R0,R1,g,R15", ""}, // Issue 11764 - asm hung parsing ']' missing register lists. {"[R0,R1,g,R15", ""}, // Issue 11764 - asm hung parsing ']' missing register lists.
{"[):[o-FP", ""}, // Issue 12469 - there was no infinite loop for ARM; these are just sanity checks. {"[):[o-FP", ""}, // Issue 12469 - there was no infinite loop for ARM; these are just sanity checks.
{"[):[R0-FP", ""}, {"[):[R0-FP", ""},
{"(", ""}, // Issue 12466 - backed up before beginning of line.
} }
var ppc64OperandTests = []operandTest{ var ppc64OperandTests = []operandTest{
......
...@@ -155,6 +155,7 @@ func (p *Parser) line() bool { ...@@ -155,6 +155,7 @@ func (p *Parser) line() bool {
// Remember this location so we can swap the operands below. // Remember this location so we can swap the operands below.
if colon >= 0 { if colon >= 0 {
p.errorf("invalid ':' in operand") p.errorf("invalid ':' in operand")
return true
} }
colon = len(operands) colon = len(operands)
} }
...@@ -338,8 +339,13 @@ func (p *Parser) operand(a *obj.Addr) bool { ...@@ -338,8 +339,13 @@ func (p *Parser) operand(a *obj.Addr) bool {
case scanner.Int, scanner.Float, scanner.String, scanner.Char, '+', '-', '~': case scanner.Int, scanner.Float, scanner.String, scanner.Char, '+', '-', '~':
haveConstant = true haveConstant = true
case '(': case '(':
// Could be parenthesized expression or (R). // Could be parenthesized expression or (R). Must be something, though.
rname := p.next().String() tok := p.next()
if tok.ScanToken == scanner.EOF {
p.errorf("missing right parenthesis")
return false
}
rname := tok.String()
p.back() p.back()
haveConstant = !p.atStartOfRegister(rname) haveConstant = !p.atStartOfRegister(rname)
if !haveConstant { if !haveConstant {
...@@ -361,6 +367,7 @@ func (p *Parser) operand(a *obj.Addr) bool { ...@@ -361,6 +367,7 @@ func (p *Parser) operand(a *obj.Addr) bool {
if p.have(scanner.String) { if p.have(scanner.String) {
if prefix != '$' { if prefix != '$' {
p.errorf("string constant must be an immediate") p.errorf("string constant must be an immediate")
return false
} }
str, err := strconv.Unquote(p.get(scanner.String).String()) str, err := strconv.Unquote(p.get(scanner.String).String())
if err != nil { if err != nil {
...@@ -952,7 +959,11 @@ func (p *Parser) next() lex.Token { ...@@ -952,7 +959,11 @@ func (p *Parser) next() lex.Token {
} }
func (p *Parser) back() { func (p *Parser) back() {
if p.inputPos == 0 {
p.errorf("internal error: backing up before BOL")
} else {
p.inputPos-- p.inputPos--
}
} }
func (p *Parser) peek() lex.ScanToken { func (p *Parser) peek() lex.ScanToken {
......
...@@ -35,6 +35,8 @@ func TestErroneous(t *testing.T) { ...@@ -35,6 +35,8 @@ func TestErroneous(t *testing.T) {
{"TEXT", "%", "expect two or three operands for TEXT"}, {"TEXT", "%", "expect two or three operands for TEXT"},
{"TEXT", "1, 1", "TEXT symbol \"<erroneous symbol>\" must be a symbol(SB)"}, {"TEXT", "1, 1", "TEXT symbol \"<erroneous symbol>\" must be a symbol(SB)"},
{"TEXT", "$\"foo\", 0, $1", "TEXT symbol \"<erroneous symbol>\" must be a symbol(SB)"}, {"TEXT", "$\"foo\", 0, $1", "TEXT symbol \"<erroneous symbol>\" must be a symbol(SB)"},
{"TEXT", "$0É:0, 0, $1", "expected EOF, found É"}, // Issue #12467.
{"TEXT", "$:0:(SB, 0, $1", "expected '(', found 0"}, // Issue 12468.
{"FUNCDATA", "", "expect two operands for FUNCDATA"}, {"FUNCDATA", "", "expect two operands for FUNCDATA"},
{"FUNCDATA", "(SB ", "expect two operands for FUNCDATA"}, {"FUNCDATA", "(SB ", "expect two operands for FUNCDATA"},
{"DATA", "", "expect two operands for DATA"}, {"DATA", "", "expect two operands for DATA"},
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment