Skip to content

Commit

Permalink
Merge pull request dlang#5391 from 9rnsr/fix15422
Browse files Browse the repository at this point in the history
[REG2.066] Issue 15422 - associative array of nested struct - crash on usage
Conflicts:
	src/aggregate.d
	test/runnable/nested.d
  • Loading branch information
tramker committed Feb 6, 2016
1 parent d6c13ed commit 5064cc1
Show file tree
Hide file tree
Showing 3 changed files with 162 additions and 14 deletions.
12 changes: 6 additions & 6 deletions src/struct.c
Original file line number Diff line number Diff line change
Expand Up @@ -582,17 +582,17 @@ void AggregateDeclaration::makeNested()
Dsymbol *s = toParent2();
if (!s)
return;
AggregateDeclaration *ad = s->isAggregateDeclaration();
FuncDeclaration *fd = s->isFuncDeclaration();
Type *t = NULL;
if (fd)
if (FuncDeclaration *fd = s->isFuncDeclaration())
{
enclosing = fd;

AggregateDeclaration *agg = fd->isMember2();
t = agg ? agg->handleType() : Type::tvoidptr;
/* Bugzilla 14422: If a nested class parent is a function, its
* context pointer (== `outer`) should be void* always.
*/
t = Type::tvoidptr;
}
else if (ad)
else if (AggregateDeclaration *ad = s->isAggregateDeclaration())
{
if (isClassDeclaration() && ad->isClassDeclaration())
{
Expand Down
157 changes: 156 additions & 1 deletion test/runnable/nested.d
Original file line number Diff line number Diff line change
Expand Up @@ -866,6 +866,7 @@ class Foo35
//writefln("y = %s", y);
assert(x == 42);
assert(y == 43);
static assert(is(typeof(this.outer) == void*)); // Bugzilla 14442
}
};
}
Expand Down Expand Up @@ -2456,6 +2457,159 @@ void test14398()
}

/*******************************************/
// 15422

class App15422(T)
{
this() {}

auto test1(T val)
in {} body // necessary to reproduce the crash
{
struct Foo
{
this(int k) {}
T a;
}

Foo foo;
foo.a = val;

// Frame of test2 function, allocated on heap.
assert(foo.tupleof[$-1] !is null);

//printf("&foo = %p\n", &foo); // stack
//printf("&this = %p\n", &this); // stack?
//printf("foo.vthis = %p\n", foo.tupleof[$-1]); // stack...!?
//assert(cast(void*)&this !is *cast(void**)&foo.tupleof[$-1], "bad");
// BUG: currently foo.vthis set to the address of 'this' variable on the stack.
// It's should be stomped to null, because Foo.vthis is never be used.

int[Foo] map;
map[foo] = 1; // OK <- crash

return foo;
}

auto test2(T val)
//in {} body
{
int closVar;
struct Foo
{
this(int k) { closVar = k; }
// Make val a closure variable.

T a;
}

Foo foo;
foo.a = val;

// Frame of test2 function, allocated on heap.
assert(foo.tupleof[$-1] !is null);

return foo;
}
}

void test15422a()
{
alias App = App15422!int;
App app1 = new App;
{
auto x = app1.test1(1);
auto y = app1.test1(1);
static assert(is(typeof(x) == typeof(y)));

// int (bitwise comparison)
assert(x.a == y.a);

assert(*cast(void**)&x.tupleof[$-1] is *cast(void**)&y.tupleof[$-1]);

// bitwise equality (needOpEquals() and needToHash() returns false)
assert(x == y);

// BUG
//assert(*cast(void**)&x.tupleof[$-1] is null);
//assert(*cast(void**)&y.tupleof[$-1] is null);
auto getZ() { auto z = app1.test1(1); return z; }
auto z = getZ();
assert(x.a == z.a);
//assert(x.tupleof[$-1] is z.tupleof[$-1]); // should pass
//assert(x == z); // should pass

x = y; // OK, x.tupleof[$-1] = y.tupleof[$-1] is a blit copy.
}
App app2 = new App;
{
auto x = app1.test2(1);
auto y = app2.test2(1);
static assert(is(typeof(x) == typeof(y)));

// int (bitwise comparison)
assert(x.a == y.a);

// closure envirionments
assert(*cast(void**)&x.tupleof[$-1] !is *cast(void**)&y.tupleof[$-1]);

// Changed to bitwise equality (needOpEquals() and needToHash() returns false)
assert(x != y); // OK <- crash

x = y; // OK, x.tupleof[$-1] = y.tupleof[$-1] is a blit copy.
}
}

void test15422b()
{
alias App = App15422!string;
App app1 = new App;
{
auto x = app1.test1("a".idup);
auto y = app1.test1("a".idup);
static assert(is(typeof(x) == typeof(y)));

// string (element-wise comparison)
assert(x.a == y.a);

assert(*cast(void**)&x.tupleof[$-1] is *cast(void**)&y.tupleof[$-1]);

// memberwise equality (needToHash() returns true)
assert(x == y);
// Lowered to: x.a == y.a && x.tupleof[$-1] is y.tupleof[$-1]

// BUG
//assert(*cast(void**)&x.tupleof[$-1] is null);
//assert(*cast(void**)&y.tupleof[$-1] is null);
auto getZ() { auto z = app1.test1("a".idup); return z; }
auto z = getZ();
assert(x.a == z.a);
//assert(x.tupleof[$-1] is z.tupleof[$-1]); // should pass
//assert(x == z); // should pass

x = y; // OK, x.tupleof[$-1] = y.tupleof[$-1] is a blit copy.
}
App app2 = new App;
{
auto x = app1.test2("a".idup);
auto y = app2.test2("a".idup);
static assert(is(typeof(x) == typeof(y)));

// string (element-wise comparison)
assert(x.a == y.a);

// closure envirionments
assert(*cast(void**)&x.tupleof[$-1] !is *cast(void**)&y.tupleof[$-1]);

// Changed to memberwise equality (needToHash() returns true)
// Lowered to: x.a == y.a && x.tupleof[$-1] is y.tupleof[$-1]
assert(x != y); // OK <- crash

x = y; // OK, x.tupleof[$-1] = y.tupleof[$-1] is a blit copy.
}
}

/***************************************************/

int main()
{
Expand Down Expand Up @@ -2546,8 +2700,9 @@ int main()
test12234();
test13861();
test14398();
test15422a();
test15422b();

printf("Success\n");
return 0;
}

7 changes: 0 additions & 7 deletions test/runnable/test11.d
Original file line number Diff line number Diff line change
Expand Up @@ -1275,9 +1275,6 @@ void test8809()
char test3Bx() { return (new class Object { char bar() { return B.foo(); } }).bar(); }
char test3Cx() { return (new class Object { char bar() { return C.foo(); } }).bar(); }
char test3Dx() { return (new class Object { char bar() { return foo(); } }).bar(); }
char test3By() { return (new class Object { char bar() { return this.outer.B.foo(); } }).bar(); }
char test3Cy() { return (new class Object { char bar() { return this.outer.C.foo(); } }).bar(); }
char test3Dy() { return (new class Object { char bar() { return this.outer. foo(); } }).bar(); }

override char foo() { return 'C'; }
}
Expand Down Expand Up @@ -1311,10 +1308,6 @@ void test8809()
assert(c.test3Bx() == 'B'); // NG('D') -> OK
assert(c.test3Cx() == 'C'); // NG('D') -> OK
assert(c.test3Dx() == 'D');

assert(c.test3By() == 'B');
assert(c.test3Cy() == 'C');
assert(c.test3Dy() == 'D');
}

/**************************************/
Expand Down

0 comments on commit 5064cc1

Please sign in to comment.