-
Notifications
You must be signed in to change notification settings - Fork 18k
runtime: update SetFinalizer docs to cover cases of package level data #17311
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
/cc some of the runtime folks @aclements @RLH. |
The existing docs is fine as is. "The argument obj must be a pointer to an object allocated by This means no other pointers are accepted, which includes We shouldn't document whether it checks the incoming obj |
@minux, "This means no other pointers are accepted, which includes package level variables." If the document is intended to exclude package level variables, please also exclude package level pointers to objects allocated by calling new and by taking the address of composite literals. |
You confused the differences between documented behavior
and actual implemented behavior.
The documented behavior is almost always a strict subset of
actual implemented behavior, i.e. the code implements some
unspecified behavior. In general it's not wise to depend on
those unspecified behaviors.
For this particular case, the documentation says you can't use
package level variables, but the implementation doesn't enforce
this, so you can actually set finalizer on package level variables,
but as this is not documented to be valid, it's not guaranteed to
stay valid for future Go versions.
The current docs is the correct one, and there is no need to
complicate it further (esp. the current docs already enumerates
all valid cases, there is no need to explicitly say excluded cases
are invalid).
|
But if the document doesn't forbid package level pointers to objects allocated by calling new and by taking the address of composite literals, why it forbids general package level pointers? |
If the document has no problems, can I file an issue for the compiler implementation? Whatever, the docs for SetFinalizer should be more detailed to address the differences between documented behavior and actual implemented behavior. |
I tried some of the previous releases for setting finalizer on
package level variable. OK means no panic.
go version go1
runtime.SetFinalizer: pointer not at beginning of allocated block
go version go1.1.2 linux/amd64
runtime.SetFinalizer: pointer not at beginning of allocated block
go version go1.2.1 linux/amd64
runtime.SetFinalizer: pointer not at beginning of allocated block
go version go1.2.2 linux/amd64
runtime.SetFinalizer: pointer not at beginning of allocated block
go version go1.3 linux/amd64
OK
go version go1.3.3 linux/amd64
OK
go version go1.4 linux/amd64
OK
go version go1.4.1 linux/amd64
OK
go version go1.4.3 linux/amd64
OK
go version go1.5 linux/amd64
OK
go version go1.5.3 linux/amd64
OK
go version go1.6 linux/amd64
OK
go version go1.7.1 linux/amd64
OK
As you can see, this is not regression. The previous panic is actually
not because it's checking that the pointer is not on heap, it's because
it fails to find the beginning of allocated object on the heap. I don't
think we need to change the runtime to panic now as it used to panic
only by coincidence and the panic doesn't explain the real reason
anyway.
|
Good explanation, ok, I don't insist on changing the docs any more. |
There is a slight bug in the documentation. As written, it technically guarantees that SetFinalizer will panic if passed a pointer to a package-level variable. That clearly isn't the case. In fact, this claim is nonsense even if you ignore package-level variables, since we can't tell the difference between passing, say, a pointer to a composite literal and a pointer to its first element. So we should change this to say that it "may abort the program." However, I'm inclined to change the guarantee here as well (and also the docs) to accept pointers to package-level variables just to simplify the API and its specification. I can't see how this would unduly constrain future implementations. @RLH? |
CL https://golang.org/cl/30137 mentions this issue. |
Currently the SetFinalizer documentation makes a strong claim that SetFinalizer will panic if the pointer is not to an object allocated by calling new, to a composite literal, or to a local variable. This is not true. For example, it doesn't panic when passed the address of a package-level variable. Nor can we practically make it true. For example, we can't distinguish between passing a pointer to a composite literal and passing a pointer to its first field. Hence, weaken the guarantee to say that it "may" panic. Updates #17311. (Might fix it, depending on what we want to do with package-level variables.) Change-Id: I1c68ea9d0a5bbd3dd1b7ce329d92b0f05e2e0877 Reviewed-on: https://go-review.googlesource.com/30137 Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
@aclements @RLH Can we close this issue now? |
@RLH and I chatted about whether to guarantee that SetFinalizer won't panic if passed a package-level variable. Neither of us have strong feelings about this either way, but the existing non-guarantee is more permissive for the implementation of finalizers and lets us change our minds later if there's more evidence. Further, it's important in general that SetFinalizer only be called for the beginning of an object, but we can't check that for package-level data, so we're leaning towards not trying to make any guarantees about pointers to package-level variables. Hence, we're going to leave the documentation alone unless there's more compelling evidence for specifying this than the documentation being more restrictive than the implementation. |
the original title of this issue is "Make the SetFinalizer docs perfect". For example, in the tip version, the docs says:
So I think the following SetFinalizer callings for a, b, c will be always safe in later go versions:
However, the docs then says this:
Now, I can't confirm if the SetFinalizer callings for a, b will be always safe or not. |
@yaxinlx, maybe I don't understand what you mean by SetFinalizer being "safe". To me, SetFinalizer is "safe" in situations it guarantees won't panic. But your second quote from the documentation doesn't say anything about SetFinalizer panicking. It just says the finalizer may not run for a or b (which is true in general, since finalizers are never guaranteed to be run). |
The complaint for the docs is I don't understand what the "must" mean in the first quote. Thanks for your explanation. By your explanation, I think "must" means "must be xxx to avoid paniking in later go versions". |
Either may be true. The point is that this is an intentionally underspecified contract between SetFinalizer and the caller of SetFinalizer. "The argument obj must be a pointer to an object allocated by calling new, by taking the address of a composite literal, or by taking the address of a local variable." means it's the caller's responsibility to pass an obj that satisfies these requirements. If the caller does something else, the behavior of SetFinalizer is unspecified. It may panic (a possibility suggested by the last sentence in that paragraph). It may do nothing (in which case the finalizer will never run). It may reboot your computer (though that would be rude). Who knows? And, as you point out, it may behave differently in other versions of Go or other implementations of Go (e.g., gccgo, GopherJS). |
What version of Go are you using (
go version
)?go1.7.1 linux/amd64
What did you see instead?
see this discussion for details: https://groups.google.com/forum/#!topic/golang-dev/JAgv8kBTgk4
summary:
The text was updated successfully, but these errors were encountered: