Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions deephash.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,19 @@ func deepHash(src reflect.Value, visited map[uintptr]*visit, depth int) []byte {
}
// Remember, remember...
visited[h] = &visit{addr, typ, seen}
defer func() {
// If we get here, we've either added a new entry in visited or
// a new type to the end of a list in visited
if seen != nil {
// If we just added a type to the end, remove it when
// returning from this level of recursion
visited[h] = seen
} else {
// If this is the first time we've seen this memory address,
// pop it off when returning from this level of recursion
delete(visited, h)
}
}()
}

hash := fnv.New64a()
Expand Down
27 changes: 27 additions & 0 deletions deephash_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -259,3 +259,30 @@ func TestBooleans(t *testing.T) {
t.Fatal("Expecting true to hash differently than false")
}
}

type parent struct {
c1, c2 *child
}

type child struct {
val string
}

func TestStackCycle(t *testing.T) {
c1 := child{val: "child"}
c2 := child{val: "child"}

ch1 := Hash(&c1)
ch2 := Hash(&c2)
if !bytes.Equal(ch1, ch2) {
t.Fatalf("got %d != %d, want equal", ch1, ch2)
}

p1 := parent{c1: &c1, c2: &c1}
p2 := parent{c1: &c1, c2: &c2}
ph1 := Hash(p1)
ph2 := Hash(p2)
if !bytes.Equal(ph1, ph2) {
t.Errorf("got %d != %d, want equal", ph1, ph2)
}
}