[Issue 18554] New: `tupleof` ignoring `private` shouldn't be accepted in @safe code
d-bugmail at puremagic.com
d-bugmail at puremagic.com
Sun Mar 4 20:51:32 UTC 2018
https://issues.dlang.org/show_bug.cgi?id=18554
Issue ID: 18554
Summary: `tupleof` ignoring `private` shouldn't be accepted in
@safe code
Product: D
Version: D2
Hardware: All
OS: All
Status: NEW
Keywords: safe
Severity: normal
Priority: P1
Component: dmd
Assignee: nobody at puremagic.com
Reporter: ag0aep6g at gmail.com
Lifted from the forum:
https://forum.dlang.org/post/p7cmbs$2h1q$1@digitalmars.com
There is an assumption that you can use visibility attributes like `private` to
protect your stuff from outside meddling, and that you can rely on this to
ensure safety (à la @safe).
For example, std.stdio.File assumes this. It `malloc`s its internal data and
keeps a reference count. It does an `@trusted` call to `free` when the count
hits 0. The data is stored in a `private` field, and `File` assumes that it
can't be messed with from the outside, at least not in an `@safe` manner.
As far as I'm aware, that's exactly how `@safe` reference counting is supposed
to be done.
But `tupleof` ignores `private` even in `@safe` code. So it can be used to
violate the assumption, which leads to memory corruption.
The `File` example in code (<https://run.dlang.io/is/1QSsUk>):
----
void main() @safe
{
import std.stdio: File, writeln;
auto hosts = File("/etc/hosts");
{
auto hosts_copy = hosts;
hosts_copy.tupleof[0].refs = 1; /* uh-oh */
}
auto self = File(__FILE__);
writeln(hosts.rawRead(new char[1000]));
/* Reads from __FILE__ instead of /etc/hosts. */
}
----
And the issue reduced to its core (<https://run.dlang.io/is/reMMQt>):
----
--- foo.d
struct S
{
private int* p;
this(int x, int y) @safe { p = &[x, y][0]; }
int get2nd() @trusted { return p is null ? 0 : p[1]; }
/* Assuming that p is only ever set by the constructor.
So it's either null or there must be two elements. */
}
--- bar.d
import foo;
import std.stdio;
void main() @safe
{
auto s = S(1, 2);
s.tupleof[0] = &[10][0]; /* Should not be allowed. */
writeln(s.get2nd()); /* garbage */
}
----
--
More information about the Digitalmars-d-bugs
mailing list