digitalmars.D.bugs - [Issue 18554] New: `tupleof` ignoring `private` shouldn't be
- d-bugmail puremagic.com (65/65) Mar 04 2018 https://issues.dlang.org/show_bug.cgi?id=18554
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 puremagic.com Reporter: ag0aep6g 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 */ } ---- --
Mar 04 2018