fix #20508 escaping sliced stack arrays not detected#22207
fix #20508 escaping sliced stack arrays not detected#22207WalterBright wants to merge 1 commit intodlang:masterfrom
Conversation
|
Thanks for your pull request, @WalterBright! Bugzilla referencesYour PR doesn't reference any Bugzilla issue. If your PR contains non-trivial changes, please reference a Bugzilla issue or create a manual changelog.
|
Anyone know anything about this code? |
a38cd05 to
0793197
Compare
|
@dkorpel may need to enable this with an |
0793197 to
7ebdca1
Compare
If you guard the code with |
It looks like it incorrectly marks the allocator parameter as |
| if (va && !(vaIsFirstRef && v.isReturn()) && va.enclosesLifetimeOf(v)) | ||
| { | ||
| if (sc.setUnsafeDIP1000(gag, ae.loc, "assigning address of variable `%s` to `%s` with longer lifetime", v, va)) | ||
| if (setUnsafe(&sc, gag, ae.loc, "assigning address of variable `%s` to `%s` with longer lifetime", v, va)) |
There was a problem hiding this comment.
This is the wrong place to change. This still enables escaping stack allocated slices through other means than return, and if you were to perform this change consistently you are basically just enabling DIP1000 by default.
Without dip1000, slicing a static array a[] should be treated the same as taking the address of a local &a as far as @safe is concerned, and taking the address of locals is prevented by the checkAddressVar function called from AddrExp::semantic. The same could be done with SliceExp::semantic:
--- a/compiler/src/dmd/expressionsem.d
+++ b/compiler/src/dmd/expressionsem.d
@@ -10954,6 +10954,17 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
}
else if (t1b.ty == Tsarray)
{
+ if (auto ve = exp.e1.isVarExp())
+ {
+ if (auto vd = ve.var.isVarDeclaration())
+ {
+ if (!checkAddressVar(sc, exp, vd))
+ {
+ result = ErrorExp.get();
+ return;
+ }
+ }
+ }
}
else if (t1b.ty == Ttuple)
{
@@ -17649,7 +17660,7 @@ Expression modifiableLvalue(Expression _this, Scope* sc, Expression eorig = nullOf course this is a massive breaking change so it needs to be guarded by an edition.
There was a problem hiding this comment.
BTW DIP1000 is currently enabled for the 2024 edition, so it catches escaping slices anyway.
There was a problem hiding this comment.
I appreciate your ideas here. But I have a bit of a different take. As you explained, I put the check on the return. (I also put it on an assignment to a global.) Returning a pointer to the stack is always an error (detected or not). That's why there is value in not requiring dip1000 to check it. But taking a slice of a stack array is legitimate (I use it often as a temporary buffer.
The compiler already attaches scope to any pointer or slice of a stack variable. Making use of that does not require any annotations nor inference of function interfaces, which were the problems with dip1000.
Returning a pointer to the stack is always a bug in the code, and I have no qualms about checking for this without adding the noted difficulties of dip1000. Yes, this doesn't detect everything dip1000 does, but I don't see a downside to adding these checks without requiring dip1000.
I'd like to see what more we can do without the problems of dip1000.
I was a bit nervous about what failures we'd encounter with this PR, but it seems that it is only detecting overlooked bugs in existing code. Which is good news! But in the spirit of not breaking existing code, putting it behind an edition is reasonable.
There was a problem hiding this comment.
But taking a slice of a stack array is legitimate
Which you can always do in @system or @trusted code. You said before that @safe is not just a warning / linting system, it's supposed to be robust. Are we watering it down now, intentionally leaving holes in it?
There was a problem hiding this comment.
We want to move to @safe by default. This PR increases safety by default, and the only code it breaks is code that is broken already. It does not carry with it the difficulties that dip1000 has. dip1000 makes @safe safer, but has turned out to be too much of a burden for programmers. I aim to make it safe without those difficulties. This is a good step in that direction.
There was a problem hiding this comment.
Good observations!
- yes, it is incomplete. It doesn't detect
b = c ? null : s[1..2];for example. But these cases are all fixable. But I don't see a point in doing that work if this doesn't move forward. - robust: yes, your proposed solution is robust. But it also does not allow practical and verifiably safe use cases. I use stack allocated arrays as buffers and then use slices of them. We should be allowing things that are verifiably safe.
- I agree that dip1000 is a failure. Its failure is because of the confusing nature of the annotations. The failure is not one of concept. The semantics can be implemented without the need for annotations (except for functions with no bodies). We should be heading in that direction.
- I agree the error message could be more helpful. A bad error message is insufficient reason to abandon the idea. Note that the user will get an error message with both your proposal and mine.
There was a problem hiding this comment.
I'd like to add that:
int i;
int* p = &i;
can be replaced with ref r = i; but there isn't an equivalent ref slice. Therefore, the pointer restriction is not equivalent to restricting a slice.
There was a problem hiding this comment.
I guess we'll have to wait until the editions meeting to see how we decide on this matter. As a reminder: this PR's code changes are still useless because of #22207 (comment), I can revert them with no observable change. (Try it if you don't believe me, I can even do it for you if you want)
There was a problem hiding this comment.
I improved the error message to indicate inference of scope.
There was a problem hiding this comment.
Yes, it is only in-play with the edition.
7ebdca1 to
527b4fd
Compare
|
@dkorpel I added the edition check, thanks! |
ca99e47 to
06f66c1
Compare
|
This is ready to go. |
06f66c1 to
658f1bb
Compare
|
@dkorpel spec pr dlang/dlang.org#4356 |
|
@dkorpel spec PR has been merged |
|
That doesn't change anything about #22207 (comment) though |
|
@dkorpel I replied upthread. |
658f1bb to
978e3e8
Compare
No description provided.