Bug 3925 – Missed escaping reference of a local variable
Status
RESOLVED
Resolution
FIXED
Severity
normal
Priority
P2
Component
dmd
Product
D
Version
D2
Platform
x86
OS
Windows
Creation time
2010-03-10T07:38:56Z
Last change time
2018-04-21T12:38:33Z
Keywords
diagnostic
Assigned to
No Owner
Creator
bearophile_hugs
Comments
Comment #0 by bearophile_hugs — 2010-03-10T07:38:56Z
This is a wrong program, and the compiler shows the right error messages, of x and y escaping:
ref int foo(int x) {
return x;
}
int* baz() {
int y;
return &y;
}
void main() {}
-------------------
But in the following case the compiler doesn't show an error:
ref int foo(ref int x) {
return x;
}
ref int bar() {
int x;
return foo(x); // escaping reference of x
}
void main() {}
Comment #1 by bearophile_hugs — 2010-03-10T10:08:04Z
This was the original code by Michel Fortin:
@safe ref int foo(ref int a) {
return a;
}
@safe ref int bar() {
int a;
return foo(a);
}
Norbert Nemec comments:
>I would say the possibility of a bug makes this code unsafe by definition. Ref returns must be considered unsafe by default, unless the compiler can know for sure that the object will exist beyond the lifetime of the function.<
So I think Norbert Nemec idea is: while the normal compiler error messages assume correctness and need a demonstration of unsafety to be shown, @safe can do the opposite assuming unsafety and requiring a demonstration of safety.
Comment #2 by clugdbug — 2010-03-10T11:12:03Z
(In reply to comment #1)
> This was the original code by Michel Fortin:
>
> @safe ref int foo(ref int a) {
> return a;
> }
> @safe ref int bar() {
> int a;
> return foo(a);
> }
>
>
> Norbert Nemec comments:
> >I would say the possibility of a bug makes this code unsafe by definition. Ref returns must be considered unsafe by default, unless the compiler can know for sure that the object will exist beyond the lifetime of the function.<
>
>
> So I think Norbert Nemec idea is: while the normal compiler error messages
> assume correctness and need a demonstration of unsafety to be shown, @safe can
> do the opposite assuming unsafety and requiring a demonstration of safety.
I've just been dealing with ref returns in my recent CTFE patch. But I don't think it's very complicated.
As far as I can tell, ref returns are only a problem if a local variable is passed as a ref parameter, or if it is a member function of a local struct.
If either of those is true, it should be considered to potentially be a return of a local variable.
I don't think there's any problem with foo, but bar should generate an error.
Comment #3 by michel.fortin — 2010-03-10T12:04:05Z
(In reply to comment #2)
> I've just been dealing with ref returns in my recent CTFE patch. But I don't
> think it's very complicated.
> As far as I can tell, ref returns are only a problem if a local variable is
> passed as a ref parameter, or if it is a member function of a local struct.
> If either of those is true, it should be considered to potentially be a return
> of a local variable.
> I don't think there's any problem with foo, but bar should generate an error.
This seems fair. There is a similar problem with delegates:
@safe
void delegate() foo(ref int a) {
return { writeln(a); };
}
@safe
void delegate() bar() {
int a;
return foo(a); // leaking reference to a beyound bar's scope
}
It could be solved in the same way.
Comment #4 by bearophile_hugs — 2010-10-22T19:26:06Z
Here DMD 2.049 doesn't find the error, but it should:
int* foo() {
int x;
int* p = &x;
return p;
}
void main() {}
Comment #5 by dfj1esp02 — 2010-10-25T13:59:45Z
---
class A{}
A foo(A a)
{
return a;
}
A bar()
{
scope A a=new A();
return foo(a);
}
---
Comment #6 by bearophile_hugs — 2010-10-25T15:40:48Z
(In reply to comment #5)
> ---
> class A{}
>
> A foo(A a)
> {
> return a;
> }
>
> A bar()
> {
> scope A a=new A();
> return foo(a);
> }
> ---
The "scope" is deprecated, so I think yours isn't a valid error case, sorry :-(
Comment #7 by bearophile_hugs — 2011-06-29T15:32:18Z
Two more cases of undetected escaping of reference:
int* ptr;
void foo1() {
int local;
ptr = &local;
}
void foo2(int** x) {
int i;
*x = &i;
}
void main() {}
See also bug 5541 and bug 1313
Comment #8 by nick — 2018-04-21T12:38:33Z
All code samples here fail to compile with @safe and -dip1000, dmd v2.079.1, except this one:
(In reply to Michel Fortin from comment #3)
> There is a similar problem with delegates:
I looked to see if this is filed, the closest I could find is Issue 18738, which is strongly related. Closing this.