Bug 13508 – array vararg function safety not inferred
Status
RESOLVED
Resolution
FIXED
Severity
normal
Priority
P1
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2014-09-20T13:39:00Z
Last change time
2015-02-18T03:37:25Z
Keywords
pull, rejects-valid
Assigned to
nobody
Creator
monarchdodra
Comments
Comment #0 by monarchdodra — 2014-09-20T13:39:01Z
struct S
{
this(T)(T[] t...)
{}
}
template make(T)
{
T make(Args...)(Args args) //@safe
{
return T(args);
}
}
void main() @safe
{
S s = make!S(5);
}
//----
Error: safe function 'D main' cannot call system function 'main.make!(S).make!(int).make'
//----
If you mark "make" as explicitly safe, then it works.
Then again, I believe using "T[] t..." isn't safe to begin with...? (slice contents are destroyed at end of scope). Either way, there's a bug in there.
Comment #1 by hsteoh — 2014-09-20T21:05:21Z
Array vararg functions are not safe, because they take a slice of arguments on the stack. Example problem:
-----
class C {
int[] data;
this(int[] args...) {
data = args; // oops: this.data now points to the stack...
}
}
-----
Comment #2 by monarchdodra — 2014-09-20T22:01:28Z
(In reply to hsteoh from comment #1)
> Array vararg functions are not safe, because they take a slice of arguments
> on the stack. Example problem:
> -----
> class C {
> int[] data;
> this(int[] args...) {
> data = args; // oops: this.data now points to the stack...
> }
> }
> -----
That's what I thought, but:
"If you mark "make" as explicitly safe, then it works."
So there's a loophole somewhere here.
Also related, I think it is a flaw that the very *signature* of something is unsafe. In particular, the "array vararg" signature is *also* the one chosen when you pass an array, which is perfectly defined and safe behavior...
Comment #3 by hsteoh — 2014-09-20T22:30:20Z
Yes, definitely there's a loophole somewhere. So that must be fixed.
But "conditionally safe" (i.e., conditional upon what arguments are passed by the caller) is the same as "unsafe", because for example, if a function performs pointer arithmetic, then as long as you make sure the pointers you pass in are within bounds, then you won't get any unsafe operations in the function. But that doesn't change the fact that the function is unsafe.
Comment #4 by monarchdodra — 2014-09-20T23:06:51Z
(In reply to hsteoh from comment #3)
> But "conditionally safe" (i.e., conditional upon what arguments are passed
> by the caller) is the same as "unsafe", because for example, if a function
> performs pointer arithmetic, then as long as you make sure the pointers you
> pass in are within bounds, then you won't get any unsafe operations in the
> function. But that doesn't change the fact that the function is unsafe.
Right, but in this case, we're talking about the static types used by the caller. From caller point of view, it's 2 different signatures:
make!S(1, 2, 3); //(1) unsafe
make!S([1, 2, 3]); //(2) safe
In this case, 1 is unsafe, but 2 is (should) be safe.
(In reply to hsteoh from comment #1)
> Array vararg functions are not safe, because they take a slice of arguments
> on the stack. Example problem:
> -----
> class C {
> int[] data;
> this(int[] args...) {
> data = args; // oops: this.data now points to the stack...
> }
> }
> -----
I think that typesafe variadic parameters would be designed to be safe, because the following case is correctly rejected by the compile time check.
int[] foo(int[] args...) {
return args; // Error: escaping reference to variadic parameter args
}
But as you know, current escape analysis mechanism is incomplete, and scope attribute is yet not defined well.
Comment #7 by github-bugzilla — 2014-09-24T00:30:23Z