digitalmars.D - A Riddle: what is wrong with this code using std.array.Appender?
- FeepingCreature (7/7) Mar 25 2019 class Class
- Andrea Fontana (3/10) Mar 25 2019 Previously on dlang forum:
- Adam D. Ruppe (2/3) Mar 25 2019 not the same!
- Andrea Fontana (2/5) Mar 25 2019 Yep, but same topic :)
- user1234 (20/27) Mar 25 2019 My bet is that null is converted to int[]
- Meta (16/23) Mar 25 2019 I can't see the bug in this minimal example:
- Steven Schveighoffer (4/34) Mar 25 2019 I have a feeling it's an aliasing thing -- like every app member in
- Meta (27/49) Mar 25 2019 Ouch, you're right.
- H. S. Teoh (8/15) Mar 25 2019 [...]
- Meta (8/24) Mar 25 2019 Yes, this part of the language *needs* to be changed if D is
- FeepingCreature (6/31) Mar 25 2019 Yep, that's correct. If you look at the AST analysis in
- Daniel Kozak (12/19) Mar 25 2019 Yeah I remember this bug. But to be honest I believe it is already fixed...
class Class { Appender!(int[]) app = null; } This is the most evil bug I've seen this year yet. Hint: Appender is a struct, not a class. So what does "= null" do, when it appears as a default initializer?
Mar 25 2019
On Monday, 25 March 2019 at 14:58:08 UTC, FeepingCreature wrote:class Class { Appender!(int[]) app = null; } This is the most evil bug I've seen this year yet. Hint: Appender is a struct, not a class. So what does "= null" do, when it appears as a default initializer?Previously on dlang forum: https://forum.dlang.org/post/suezctpobjjoanyummjm forum.dlang.org
Mar 25 2019
On Monday, 25 March 2019 at 15:44:08 UTC, Andrea Fontana wrote:Previously on dlang forum:not the same!
Mar 25 2019
On Monday, 25 March 2019 at 15:45:56 UTC, Adam D. Ruppe wrote:On Monday, 25 March 2019 at 15:44:08 UTC, Andrea Fontana wrote:Yep, but same topic :)Previously on dlang forum:not the same!
Mar 25 2019
On Monday, 25 March 2019 at 14:58:08 UTC, FeepingCreature wrote:class Class { Appender!(int[]) app = null; } This is the most evil bug I've seen this year yet. Hint: Appender is a struct, not a class. So what does "= null" do, when it appears as a default initializer?My bet is that null is converted to int[] /// class Class { enum int[] initializer = null; Appender!(int[]) app0 = initializer; Appender!(int[]) app1 = null; this() { assert(app0 == app1); } } void main() { new Class; } /// because Appender ctor can take a int[] i.e a range, no only a single elem.
Mar 25 2019
On Monday, 25 March 2019 at 14:58:08 UTC, FeepingCreature wrote:class Class { Appender!(int[]) app = null; } This is the most evil bug I've seen this year yet. Hint: Appender is a struct, not a class. So what does "= null" do, when it appears as a default initializer?I can't see the bug in this minimal example: import std.array: Appender; class Class { Appender!(int[]) app = null; } void main() { auto c = new Class(); import std.stdio; writeln(c.app.data); //Prints "[]" c.app ~= 10; writeln(c.app.data); //Prints "[10]" } What's the problem?
Mar 25 2019
On 3/25/19 1:06 PM, Meta wrote:On Monday, 25 March 2019 at 14:58:08 UTC, FeepingCreature wrote:I have a feeling it's an aliasing thing -- like every app member in every class points at the same IMPL struct. -Steveclass Class { Appender!(int[]) app = null; } This is the most evil bug I've seen this year yet. Hint: Appender is a struct, not a class. So what does "= null" do, when it appears as a default initializer?I can't see the bug in this minimal example: import std.array: Appender; class Class { Appender!(int[]) app = null; } void main() { auto c = new Class(); import std.stdio; writeln(c.app.data); //Prints "[]" c.app ~= 10; writeln(c.app.data); //Prints "[10]" } What's the problem?
Mar 25 2019
On Monday, 25 March 2019 at 17:32:13 UTC, Steven Schveighoffer wrote:Ouch, you're right. import std.array: Appender; class Class { Appender!(int[]) app = null; } void testAppender(Class c) { import std.stdio; writeln(c.app.data); c.app ~= 10; writeln(c.app.data); } void main() { auto c1 = new Class(); auto c2 = new Class(); testAppender(c1); //Prints [] and [10] testAppender(c2); //Prints [10] and [10, 10] } I find that a bit strange, since you'd think that Appender would initialize its payload on the first append; and it seems like it does if you look at the code (in Appender.ensureAddable). I'm not sure how it shakes out that the two Appenders end up sharing the same memory.I can't see the bug in this minimal example: import std.array: Appender; class Class { Appender!(int[]) app = null; } void main() { auto c = new Class(); import std.stdio; writeln(c.app.data); //Prints "[]" c.app ~= 10; writeln(c.app.data); //Prints "[10]" } What's the problem?I have a feeling it's an aliasing thing -- like every app member in every class points at the same IMPL struct. -Steve
Mar 25 2019
On Mon, Mar 25, 2019 at 06:21:12PM +0000, Meta via Digitalmars-d wrote:On Monday, 25 March 2019 at 17:32:13 UTC, Steven Schveighoffer wrote:[...][...]I have a feeling it's an aliasing thing -- like every app member in every class points at the same IMPL struct.I find that a bit strange, since you'd think that Appender would initialize its payload on the first append; and it seems like it does if you look at the code (in Appender.ensureAddable). I'm not sure how it shakes out that the two Appenders end up sharing the same memory.This is pretty bad; two Appenders sharing the same memory could potentially be exploited to break immutable. T -- In a world without fences, who needs Windows and Gates? -- Christian Surchi
Mar 25 2019
On Monday, 25 March 2019 at 18:39:26 UTC, H. S. Teoh wrote:On Mon, Mar 25, 2019 at 06:21:12PM +0000, Meta via Digitalmars-d wrote:Yes, this part of the language *needs* to be changed if D is going to claim that it's memory safe. Either things such as: struct Test { Object o = new Object(); } needs to be disallowed, or the semantics need to be changed.On Monday, 25 March 2019 at 17:32:13 UTC, Steven Schveighoffer wrote:[...][...]I have a feeling it's an aliasing thing -- like every app member in every class points at the same IMPL struct.I find that a bit strange, since you'd think that Appender would initialize its payload on the first append; and it seems like it does if you look at the code (in Appender.ensureAddable). I'm not sure how it shakes out that the two Appenders end up sharing the same memory.This is pretty bad; two Appenders sharing the same memory could potentially be exploited to break immutable. T
Mar 25 2019
On Monday, 25 March 2019 at 18:21:12 UTC, Meta wrote:Ouch, you're right. import std.array: Appender; class Class { Appender!(int[]) app = null; } void testAppender(Class c) { import std.stdio; writeln(c.app.data); c.app ~= 10; writeln(c.app.data); } void main() { auto c1 = new Class(); auto c2 = new Class(); testAppender(c1); //Prints [] and [10] testAppender(c2); //Prints [10] and [10, 10] } I find that a bit strange, since you'd think that Appender would initialize its payload on the first append; and it seems like it does if you look at the code (in Appender.ensureAddable). I'm not sure how it shakes out that the two Appenders end up sharing the same memory.Yep, that's correct. If you look at the AST analysis in run.dlang, what ends up happening is the constructor for Appender is evaluated statically as a side effect of "= null" becoming "= Appender(null)" and produces a static initializer referencing a shared global payload.
Mar 25 2019
On Mon, Mar 25, 2019 at 4:00 PM FeepingCreature via Digitalmars-d < digitalmars-d puremagic.com> wrote:class Class { Appender!(int[]) app = null; } This is the most evil bug I've seen this year yet. Hint: Appender is a struct, not a class. So what does "= null" do, when it appears as a default initializer?Yeah I remember this bug. But to be honest I believe it is already fixed, but few days ago I still write something like this to be sure: class Class { Appender!(int[]) app; this() { app = appender!(int[]); } }
Mar 25 2019