Bug 18554 – `tupleof` ignoring `private` shouldn't be accepted in @safe code

Status
RESOLVED
Resolution
FIXED
Severity
normal
Priority
P1
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2018-03-04T20:51:32Z
Last change time
2021-07-24T11:38:19Z
Keywords
safe
Assigned to
No Owner
Creator
ag0aep6g
See also
https://issues.dlang.org/show_bug.cgi?id=22137

Comments

Comment #0 by ag0aep6g — 2018-03-04T20:51:32Z
Lifted from the forum: https://forum.dlang.org/post/[email protected] 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 */ } ----
Comment #1 by bugzilla — 2018-03-15T04:36:02Z
Comment #2 by github-bugzilla — 2018-03-15T06:58:13Z
Commits pushed to master at https://github.com/dlang/dmd https://github.com/dlang/dmd/commit/a070de9d094c41785d00e3ec906664c3b482d0af fix Issue 18554 - tupleof ignoring private shouldn't be accepted in @safe code https://github.com/dlang/dmd/commit/cad484b390e8b638e204281d78885a82ba5cc4a6 Merge pull request #8035 from WalterBright/fix18554 fix Issue 18554 - tupleof ignoring private shouldn't be accepted in @… merged-on-behalf-of: Walter Bright <[email protected]>