Description
Code sample:
package main
import (
"encoding/json"
"fmt"
)
func main() {
var outMap map[string]any
if err := json.Unmarshal([]byte("{}"), &outMap); err != nil {
println(fmt.Sprint("err: ", err))
return
}
outMap["hello"] = "Hello"
}
Nilaway Output:
~/niltest/main.go:14:2: error: Potential nil panic detected. Observed nil flow from source to dereference point:
- niltest/main.go:14:2: unassigned variable `outMap` written to at an index
Contract for unmarshal is specified here:
To unmarshal a JSON object into a map, Unmarshal first establishes a map to use. If the map is nil, Unmarshal allocates a new map. Otherwise Unmarshal reuses the existing map, keeping existing entries.
Detection can be avoided by preallocating an empty map in the code, but (I think) using the nil map here is common. Implementation code of unmarshal is reflection heavy for dealing with a nil map, so there may be limits on how clever the code can be to detect non-nillness of the field.
Overall, I was not sure if Nilaway has similar capabilities to Nullaway that allow you to specify the contract of a standard lib methods, but I was wondering if it would make sense to allowlist this method in some meaningful way (i.e. specifying that the output value will be non-nil when the error is nil)