| package main | |
| import "runtime" | |
| func final1a(x *int) int { | |
| print(x) // @pointsto new@newint:10 | |
| return *x | |
| } | |
| func final1b(x *bool) { | |
| print(x) // @pointsto | |
| } | |
| func runtimeSetFinalizer1() { | |
| x := new(int) // @line newint | |
| runtime.SetFinalizer(x, final1a) // ok: final1a's result is ignored | |
| runtime.SetFinalizer(x, final1b) // param type mismatch: no effect | |
| } | |
| // @calls main.runtimeSetFinalizer1 -> main.final1a | |
| // @calls main.runtimeSetFinalizer1 -> main.final1b | |
| func final2a(x *bool) { | |
| print(x) // @pointsto new@newbool1:10 | new@newbool2:10 | |
| } | |
| func final2b(x *bool) { | |
| print(x) // @pointsto new@newbool1:10 | new@newbool2:10 | |
| } | |
| func runtimeSetFinalizer2() { | |
| x := new(bool) // @line newbool1 | |
| f := final2a | |
| if unknown { | |
| x = new(bool) // @line newbool2 | |
| f = final2b | |
| } | |
| runtime.SetFinalizer(x, f) | |
| } | |
| // @calls main.runtimeSetFinalizer2 -> main.final2a | |
| // @calls main.runtimeSetFinalizer2 -> main.final2b | |
| type T int | |
| func (t *T) finalize() { | |
| print(t) // @pointsto new@final3:10 | |
| } | |
| func runtimeSetFinalizer3() { | |
| x := new(T) // @line final3 | |
| runtime.SetFinalizer(x, (*T).finalize) | |
| } | |
| // @calls main.runtimeSetFinalizer3 -> (*main.T).finalize$thunk | |
| // I hope I never live to see this code in the wild. | |
| var setFinalizer = runtime.SetFinalizer | |
| func final4(x *int) { | |
| print(x) // @pointsto new@finalIndirect:10 | |
| } | |
| func runtimeSetFinalizerIndirect() { | |
| // In an indirect call, the shared contour for SetFinalizer is | |
| // used, i.e. the call is not inlined and appears in the call graph. | |
| x := new(int) // @line finalIndirect | |
| setFinalizer(x, final4) | |
| } | |
| // Exercise the elimination of SetFinalizer | |
| // constraints with non-pointer operands. | |
| func runtimeSetFinalizerNonpointer() { | |
| runtime.SetFinalizer(nil, (*T).finalize) // x is a non-pointer | |
| runtime.SetFinalizer((*T).finalize, nil) // f is a non-pointer | |
| } | |
| // @calls main.runtimeSetFinalizerIndirect -> runtime.SetFinalizer | |
| // @calls runtime.SetFinalizer -> main.final4 | |
| func main() { | |
| runtimeSetFinalizer1() | |
| runtimeSetFinalizer2() | |
| runtimeSetFinalizer3() | |
| runtimeSetFinalizerIndirect() | |
| runtimeSetFinalizerNonpointer() | |
| } | |
| var unknown bool // defeat dead-code elimination |