Bug 17261 – Implicit cast from static array to immutable should not be allowed
Status
RESOLVED
Resolution
DUPLICATE
Severity
normal
Priority
P1
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2017-03-16T17:25:00Z
Last change time
2017-03-16T18:35:41Z
Keywords
accepts-invalid, safe, wrong-code
Assigned to
nobody
Creator
hsteoh
Comments
Comment #0 by hsteoh — 2017-03-16T17:25:51Z
Code:
--------
import std.stdio;
char[32] func() {
char[32] staticArr = "A123456789abcdefB123456789abcdef"; // canary
return staticArr; // OK, by-value return
}
string gunk() {
string x = func(); // implicit conversion char[16] -> string
writeln(x.ptr);
writeln(x);
return x;
}
void main() {
auto s = gunk();
writeln(s.ptr);
writeln(s);
}
--------
Output:
--------
7FFCD89895C0
A123456789abcdefB123456789abcdef
7FFCD89895C0
9abcdef ����
--------
Basically, func() returns a static array by value, so it resides on the stack. The implicit conversion in gunk() produces a slice of this stack data (red flag), which gets corrupted (overwritten) when it returns to main().
Implicitly casting static arrays to immutable should not be allowed.
Comment #1 by hsteoh — 2017-03-16T17:27:50Z
P.S. the comment in gunk() has a typo, it should say "implicit conversion char[32] -> string" (not char[16]). But that's immaterial to the issue at hand.
Comment #2 by ag0aep6g — 2017-03-16T17:56:52Z
I think immutable doesn't matter here. Code is also accepted (wrongly) when you convert to a `char[]` instead of a `string`. Also, implicit and explicit slicing are both accepted (and both wrong). Also accepted in `@safe` code.
dmd's -dip1000 mode correctly rejects this. I don't know if this counts as fixed.
Comment #3 by hsteoh — 2017-03-16T17:57:34Z
Note that while some may blame implicit slicing for this bug, it still happens with explicit slicing:
-----
string gunk() {
string x = func()[]; // still allowed, but shouldn't be
writeln(x.ptr);
writeln(x);
return x;
}
-----
Looks like the compiler's escaping ref analysis has a hole here.
Verified that compiling with -dip1000 correctly rejects this code.
Comment #6 by petar.p.kirov — 2017-03-16T18:35:41Z
(In reply to hsteoh from comment #0)
> Code:
> --------
> import std.stdio;
>
> char[32] func() {
> char[32] staticArr = "A123456789abcdefB123456789abcdef"; // canary
> return staticArr; // OK, by-value return
> }
>
> string gunk() {
> string x = func(); // implicit conversion char[16] -> string
> writeln(x.ptr);
> writeln(x);
> return x;
> }
>
> void main() {
> auto s = gunk();
> writeln(s.ptr);
> writeln(s);
> }
> --------
>
>
> Output:
> --------
> 7FFCD89895C0
> A123456789abcdefB123456789abcdef
> 7FFCD89895C0
> 9abcdef ����
> --------
>
>
> Basically, func() returns a static array by value, so it resides on the
> stack. The implicit conversion in gunk() produces a slice of this stack data
> (red flag), which gets corrupted (overwritten) when it returns to main().
>
> Implicitly casting static arrays to immutable should not be allowed.
After commenting-out the writeln calls I get:
scope_test2.d(12): Error: scope variable x may not be returned
when compiling with -dip1000 & DMD 2.073.2.
(Without commenting-out the writeln calls I still get a compiler error, but it's because not all of Phobos is compatible with -dip1000.)
After replacing gunk with the one posted above:
string gunk() {
string x = func()[]; // still allowed, but shouldn't be
writeln(x.ptr);
writeln(x);
return x;
}
I get the same message:
scope_test3.d(12): Error: scope variable x may not be returned
*** This issue has been marked as a duplicate of issue 12625 ***