From 2c0c68d621415f0c2dffb71b20fdc0fdbbcfb5fe Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Tue, 6 Mar 2018 14:36:49 -0800 Subject: cmd/compile: fix miscompilation of "defer delete(m, k)" Previously, for slow map key types (i.e., any type other than a 32-bit or 64-bit plain memory type), we would rewrite defer delete(m, k) into ktmp := k defer delete(m, &ktmp) However, if the defer statement was inside a loop, we would end up reusing the same ktmp value for all of the deferred deletes. We already rewrite defer print(x, y, z) into defer func(a1, a2, a3) { print(a1, a2, a3) }(x, y, z) This CL generalizes this rewrite to also apply for slow map deletes. This could be extended to apply even more generally to other builtins, but as discussed on #24259, there are cases where we must *not* do this (e.g., "defer recover()"). However, if we elect to do this more generally, this CL should still make that easier. Lastly, while here, fix a few isues in wrapCall (nee walkprintfunc): 1) lookupN appends the generation number to the symbol anyway, so "%d" was being literally included in the generated function names. 2) walkstmt will be called when the function is compiled later anyway, so no need to do it now. Fixes #24259. Change-Id: I70286867c64c69c18e9552f69e3f4154a0fc8b04 Reviewed-on: https://go-review.googlesource.com/99017 Run-TryBot: Matthew Dempsky TryBot-Result: Gobot Gobot Reviewed-by: Brad Fitzpatrick --- src/runtime/map_test.go | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'src/runtime') diff --git a/src/runtime/map_test.go b/src/runtime/map_test.go index b12b09eeb6..d1b268bda4 100644 --- a/src/runtime/map_test.go +++ b/src/runtime/map_test.go @@ -875,3 +875,24 @@ func BenchmarkMapDelete(b *testing.B) { b.Run("Int64", runWith(benchmarkMapDeleteInt64, 100, 1000, 10000)) b.Run("Str", runWith(benchmarkMapDeleteStr, 100, 1000, 10000)) } + +func TestDeferDeleteSlow(t *testing.T) { + ks := []complex128{0, 1, 2, 3} + + m := make(map[interface{}]int) + for i, k := range ks { + m[k] = i + } + if len(m) != len(ks) { + t.Errorf("want %d elements, got %d", len(ks), len(m)) + } + + func() { + for _, k := range ks { + defer delete(m, k) + } + }() + if len(m) != 0 { + t.Errorf("want 0 elements, got %d", len(m)) + } +} -- cgit v1.3