Commit f4ef6977 authored by Dmitriy Vyukov's avatar Dmitriy Vyukov

runtime: ignore pointers to global objects in SetFinalizer

Update #7656

LGTM=rsc
R=rsc, iant
CC=golang-codereviews
https://golang.org/cl/82560043
parent 383963b5
...@@ -885,11 +885,20 @@ func SetFinalizer(obj Eface, finalizer Eface) { ...@@ -885,11 +885,20 @@ func SetFinalizer(obj Eface, finalizer Eface) {
// because we use &runtime·zerobase for all such allocations. // because we use &runtime·zerobase for all such allocations.
if(ot->elem != nil && ot->elem->size == 0) if(ot->elem != nil && ot->elem->size == 0)
return; return;
// The following check is required for cases when a user passes a pointer to composite literal,
// but compiler makes it a pointer to global. For example:
// var Foo = &Object{}
// func main() {
// runtime.SetFinalizer(Foo, nil)
// }
// See issue 7656.
if((byte*)obj.data < runtime·mheap.arena_start || runtime·mheap.arena_used <= (byte*)obj.data)
return;
if(!runtime·mlookup(obj.data, &base, &size, nil) || obj.data != base) { if(!runtime·mlookup(obj.data, &base, &size, nil) || obj.data != base) {
// As an implementation detail we allow to set finalizers for an inner byte // As an implementation detail we allow to set finalizers for an inner byte
// of an object if it could come from tiny alloc (see mallocgc for details). // of an object if it could come from tiny alloc (see mallocgc for details).
if(ot->elem == nil || (ot->elem->kind&KindNoPointers) == 0 || ot->elem->size >= TinySize) { if(ot->elem == nil || (ot->elem->kind&KindNoPointers) == 0 || ot->elem->size >= TinySize) {
runtime·printf("runtime.SetFinalizer: pointer not at beginning of allocated block\n"); runtime·printf("runtime.SetFinalizer: pointer not at beginning of allocated block (%p)\n", obj.data);
goto throw; goto throw;
} }
} }
......
...@@ -216,3 +216,24 @@ func TestEmptyString(t *testing.T) { ...@@ -216,3 +216,24 @@ func TestEmptyString(t *testing.T) {
} }
var ssglobal string var ssglobal string
// Test for issue 7656.
func TestFinalizerOnGlobal(t *testing.T) {
runtime.SetFinalizer(Foo1, func(p *Object1) {})
runtime.SetFinalizer(Foo2, func(p *Object2) {})
runtime.SetFinalizer(Foo1, nil)
runtime.SetFinalizer(Foo2, nil)
}
type Object1 struct {
Something []byte
}
type Object2 struct {
Something byte
}
var (
Foo2 = &Object2{}
Foo1 = &Object1{}
)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment