Empty `!!null` node fails encoding and causes panic
TristanSpeakEasy opened this issue · comments
Consider this reproducible:
package main
import (
"fmt"
"gopkg.in/yaml.v3"
)
func createIntNode(str string) *yaml.Node {
n := &yaml.Node{
Kind: yaml.ScalarNode,
Tag: "!!int",
Value: str,
}
return n
}
func createEmptyNullNode() *yaml.Node {
n := &yaml.Node{
Kind: yaml.ScalarNode,
Tag: "!!null",
Value: "",
}
return n
}
func encodeNode(node *yaml.Node) error {
var rawNode yaml.Node
if err := rawNode.Encode(node); err != nil {
return err
}
var v interface{}
if err := rawNode.Decode(&v); err != nil {
return err
}
fmt.Println(v)
return nil
}
func main() {
err := encodeNode(createIntNode("1"))
if err != nil {
panic(err)
}
yamlDoc := `key:`
var node yaml.Node
if err := yaml.Unmarshal([]byte(yamlDoc), &node); err != nil {
panic(err)
}
err = encodeNode(node.Content[0].Content[1])
if err != nil {
panic(err)
}
err = encodeNode(createEmptyNullNode())
if err != nil {
panic(err)
}
fmt.Println("done")
}
this causes this panic:
go run main.go
1
panic: runtime error: invalid memory address or nil pointer dereference [recovered]
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x48 pc=0x4ea2f3]
goroutine 1 [running]:
gopkg.in/yaml%2ev3.handleErr(0xc00015dbc8)
/home/trist/go/pkg/mod/gopkg.in/yaml.v3@v3.0.1/yaml.go:294 +0x6d
panic({0x4fda80?, 0x5ea890?})
/home/linuxbrew/.linuxbrew/opt/go/libexec/src/runtime/panic.go:914 +0x21f
gopkg.in/yaml%2ev3.(*Node).Encode(0xc000144820, {0x5071a0, 0xc000144780})
/home/trist/go/pkg/mod/gopkg.in/yaml.v3@v3.0.1/yaml.go:269 +0x593
main.encodeNode(0xc000136598?)
/home/trist/workspace/scratch/main.go:29 +0x3b
main.main()
/home/trist/workspace/scratch/main.go:56 +0xdb
as far as I can see a key in a yaml document can have no value and it is meant to be interpreted as a null value. https://stackoverflow.com/a/64462925
Which is fine when unmarshalling the document but I have code that is then also trying to marshal yaml again (and I'm working with yaml.Node instead of go models of the document to control ordering etc of maps)
And it blows up when Encoding this particular type of node.
The reason is pretty clear here: https://github.com/go-yaml/yaml/blob/v3/yaml.go#L269
func (n *Node) Encode(v interface{}) (err error) {
defer handleErr(&err)
e := newEncoder()
defer e.destroy()
e.marshalDoc("", reflect.ValueOf(v))
e.finish()
p := newParser(e.out)
p.textless = true
defer p.destroy()
doc := p.parse()
*n = *doc.Content[0]
return nil
}
The value returned from p.parse()
is nil
and then this is dereferenced without any nil
check