mirror of
https://github.com/tailscale/tailscale.git
synced 2024-11-25 11:05:45 +00:00
util/deephash: prevent infinite loop on map cycle
Fixes #2340 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
parent
aceaa70b16
commit
3962744450
@ -169,6 +169,28 @@ func (h *hasher) print(v reflect.Value) (acyclic bool) {
|
||||
case reflect.Interface:
|
||||
return h.print(v.Elem())
|
||||
case reflect.Map:
|
||||
// TODO(bradfitz): ideally we'd avoid these map
|
||||
// operations to detect cycles if we knew from the map
|
||||
// element type that there no way to form a cycle,
|
||||
// which is the common case. Notably, we don't care
|
||||
// about hashing the same map+contents twice in
|
||||
// different parts of the tree. In fact, we should
|
||||
// ideally. (And this prevents it) We should only stop
|
||||
// hashing when there's a cycle. What we should
|
||||
// probably do is make sure we enumerate the data
|
||||
// structure tree is a fixed order and then give each
|
||||
// pointer an increasing number, and when we hit a
|
||||
// dup, rather than emitting nothing, we should emit a
|
||||
// "value #12" reference. Which implies that all things
|
||||
// emit to the bufio.Writer should be type-tagged so
|
||||
// we can distinguish loop references without risk of
|
||||
// collisions.
|
||||
ptr := v.Pointer()
|
||||
if visited[ptr] {
|
||||
return false
|
||||
}
|
||||
visited[ptr] = true
|
||||
|
||||
if h.hashMapAcyclic(v) {
|
||||
return true
|
||||
}
|
||||
|
@ -226,3 +226,15 @@ func TestSHA256EqualHex(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// verify this doesn't loop forever, as it used to (Issue 2340)
|
||||
func TestMapCyclicFallback(t *testing.T) {
|
||||
type T struct {
|
||||
M map[string]interface{}
|
||||
}
|
||||
v := &T{
|
||||
M: map[string]interface{}{},
|
||||
}
|
||||
v.M["m"] = v.M
|
||||
Hash(v)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user