Fix null pointer dereference printing an expression.
Parser.parseVariable method should always set the value of the variable it creates. Failure to do so may end up in the following: ``` $ androidmk <(printf "FOO:=(X)\nFOO:=bar\n") parse error: <input>:3:1: variable already set, previous assignment: FOO@<input>:1:5 = %!s(PANIC=String method: runtime error: invalid memory address or nil pointer dereference) (%!s(PANIC=String method: runtime error: invalid memory address or nil pointer dereference)) false ``` The cause is that calling Parser.Parse to parse `FOO=abc` created a Variable instance with nil value, causing panic on print attempt. Test: m androidmk && androidmk <(printf "FOO:=(X)\nFOO:=bar\n") (should print: ERROR: parse error: <input>:3:1: variable already set, previous assignment: FOO@<input>:1:5 = X = Not Evaluated (X = Not Evaluated) false) Change-Id: I296d7984df6d8796e0075f9eb692b234f8c94f08
This commit is contained in:
parent
0c4d1db0a0
commit
77418b70b4
3 changed files with 49 additions and 0 deletions
|
@ -164,6 +164,7 @@ const (
|
||||||
Int64Type
|
Int64Type
|
||||||
ListType
|
ListType
|
||||||
MapType
|
MapType
|
||||||
|
NotEvaluatedType
|
||||||
)
|
)
|
||||||
|
|
||||||
func (t Type) String() string {
|
func (t Type) String() string {
|
||||||
|
@ -178,6 +179,8 @@ func (t Type) String() string {
|
||||||
return "list"
|
return "list"
|
||||||
case MapType:
|
case MapType:
|
||||||
return "map"
|
return "map"
|
||||||
|
case NotEvaluatedType:
|
||||||
|
return "notevaluated"
|
||||||
default:
|
default:
|
||||||
panic(fmt.Errorf("Unknown type %d", t))
|
panic(fmt.Errorf("Unknown type %d", t))
|
||||||
}
|
}
|
||||||
|
@ -476,6 +479,29 @@ func (c Comment) Text() string {
|
||||||
return string(buf)
|
return string(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type NotEvaluated struct {
|
||||||
|
Position scanner.Position
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n NotEvaluated) Copy() Expression {
|
||||||
|
return NotEvaluated{Position: n.Position}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n NotEvaluated) String() string {
|
||||||
|
return "Not Evaluated"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n NotEvaluated) Type() Type {
|
||||||
|
return NotEvaluatedType
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n NotEvaluated) Eval() Expression {
|
||||||
|
return NotEvaluated{Position: n.Position}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n NotEvaluated) Pos() scanner.Position { return n.Position }
|
||||||
|
func (n NotEvaluated) End() scanner.Position { return n.Position }
|
||||||
|
|
||||||
func endPos(pos scanner.Position, n int) scanner.Position {
|
func endPos(pos scanner.Position, n int) scanner.Position {
|
||||||
pos.Offset += n
|
pos.Offset += n
|
||||||
pos.Column += n
|
pos.Column += n
|
||||||
|
|
|
@ -484,6 +484,8 @@ func (p *parser) parseVariable() Expression {
|
||||||
}
|
}
|
||||||
value = assignment.Value
|
value = assignment.Value
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
value = &NotEvaluated{}
|
||||||
}
|
}
|
||||||
value = &Variable{
|
value = &Variable{
|
||||||
Name: text,
|
Name: text,
|
||||||
|
|
|
@ -1122,3 +1122,24 @@ func TestParserEndPos(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestParserNotEvaluated(t *testing.T) {
|
||||||
|
// When parsing without evaluation, create variables correctly
|
||||||
|
scope := NewScope(nil)
|
||||||
|
input := "FOO=abc\n"
|
||||||
|
_, errs := Parse("", bytes.NewBufferString(input), scope)
|
||||||
|
if errs != nil {
|
||||||
|
t.Errorf("unexpected errors:")
|
||||||
|
for _, err := range errs {
|
||||||
|
t.Errorf(" %s", err)
|
||||||
|
}
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
assignment, found := scope.Get("FOO")
|
||||||
|
if !found {
|
||||||
|
t.Fatalf("Expected to find FOO after parsing %s", input)
|
||||||
|
}
|
||||||
|
if s := assignment.String(); strings.Contains(s, "PANIC") {
|
||||||
|
t.Errorf("Attempt to print FOO returned %s", s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue