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
proposal: Go 2: leaking argument qualifier #30317
Comments
While syntax is not that important, seeing how now most annotations in Go are done using magic comments, perhaps the syntax could be type Reader interface {
// go:leaking(p)
Read(p []byte) (int, error)
} Like this, Go compilers that don't understand how to handle this feature will ignore it. |
If I'm reading this correctly, the |
https://dave.cheney.net/2018/01/08/gos-hidden-pragmas |
@beoran I think its the same, except the thing, that it could not be applied (I think so?) to the interface methods. @ianlancetaylor any better naming are welcome =) Like @beoran suggested |
The That is quite different from what is being proposed here, which is attempting to describe code written in Go, not code written in assembler. I'm not saying that we can't do this, but it's really completely different from |
If you flag an argument as "leaking", the compiler would need to carry that through the rest of the code to make sure it isn't (say) assigned to a variable which is placed in a slice which is pointed to by a struct which is retained. At that point, it seems like you're asking for something like the Rust borrow checker in Go? |
@lpar It could be named like "Rust's borrow checker in Go" or just "Go's advanced escape analysis". What would need the compiler to carry except the interface implementation? I mean, if interface implementation does not pass "not escaping/leaking" argument to the interface without such qualifier, nor to the non-interface function where the argument could escape (which current escape analysis already doing) and does not save this argument in heap-based data structures, then such implementation is compatible for such interface? |
If we add this type qualifier, then presumably the compiler will follow it. That means if a method with a non-leaking parameter does accidentally leak it, the program has a serious bug that will lead to memory corruption. |
@ianlancetaylor how could we pass non compatible implementation of an interface to the method expecting it? I mean, if concrete type X is passed (or assigned) as interface Y, compiler must check the compatibility, including arguments qualifier restrictions. Thus, X could not accidentally leak its argument. |
It seems to me that this proposal confuses two different (albeit intertwined) ideas:
Comments such as "Implementations must not retain p." are the latter (2): What the annotation says is that independent of the actual details of code generation and variable allocation, a concrete method Note that this is independent of escape information. Yes, it's true that if my On the other hand, if this proposal is about (1), then we would have to annotate all func (*T) Read(p noescape []byte) (int, error) {
...
} where (The existing annotations In summary, I don't think we want to pursue this: As explained above, if this proposal is about 1), whether code is valid or not becomes implementation dependent, not spec specified. If this proposal is about 2) we're opening Pandorra's box: There's much more one might want to express in "usage protocols" for function and method calls. I don't think we want to go there. |
PS: I should add that in the case of (2) it will also be tricky for a compiler to decide whether a certain property (such as "noescape") is satisfied in general, same as for (1). |
You can use a type assertion on an interface value, so you can get a value of an interface type without having any knowledge of the dynamic type. |
Ah, I see, what (2) boils down to is "Contract based programming" like exists in Ada 2012. But, are we sure Go doesn't need that? With the discussion on Generics, "contracts" were suggested to verify the qualities of the type that is used to parameterize a generic type. Now imagine that in stead of just using contracts for generics, contracts could become a first class construct in Go, usable for all sorts of compile time or run time checking... think of the possibilities. 🌠 If we had something like first class contracts, I would say that the range types I was proposing before could simply reuse those contracts. Something like |
While there may be interesting ideas to explore in this area, we aren't going to adopt this specific proposal. |
Hi,
This proposal presents the simple idea of transfering comment like "Implementations must not retain p." from interfaces like
io.Reader
,io.Writer
and similar to the appropriate type qualifier.The reason for doing so is that comments can not give the Go compiler any knowledge of how argument is being used inside the interface implementation, thus compiler could only "give up" and move argument to the heap, leading to probably unneccessary memory allocations.
Example. Suppose we have some interface like this:
When some implementation of
Reader
is used, and some user code calls it as an interface method,we got something like this from escape anlysis about the argument
p
:The idea is pretty straightforward:
Or:
Or whatever other syntax representation. That is, the idea is not in the syntax which always very controversial, but in the benefits which this qualification may give us.
With
leaking
(just to name it somehow) type qualifier compiler will able to do two things: first is to prepare escape analysis with little more additional knowledge (and not move leaking objects to heap); second is to restrict use of implementations that try to retain leaking arguments somewhere.Bonus: Cases with variadic functions may also be optimized. E.g.:
Sergey.
The text was updated successfully, but these errors were encountered: