Skip to content

Commit

Permalink
fix Issue 15524 - 64bit app with anon-class crashes in contract
Browse files Browse the repository at this point in the history
The regression has been introduce by issue 9383 fix (PR dlang#4788).
In Win64, some function parameters are passed by registers (`SCshadowreg`). When the parameters are placed in closure context, their access was not well handled in dlang#4788.
Also in Posix 64bit platforms, parameter variables have SCauto. So there was same issue.
  • Loading branch information
9rnsr committed Feb 13, 2016
1 parent 8ec7ea9 commit 2fa1e1b
Show file tree
Hide file tree
Showing 3 changed files with 139 additions and 4 deletions.
5 changes: 2 additions & 3 deletions src/e2ir.c
Expand Up @@ -994,8 +994,7 @@ elem *toElem(Expression *e, IRState *irs)
* contract, instead look at the original stack data.
*/
bool forceStackAccess = false;
if (s->Sclass == SCparameter &&
fd->isVirtual() && (fd->fdrequire || fd->fdensure))
if (fd->isVirtual() && (fd->fdrequire || fd->fdensure))
{
Dsymbol *sx = irs->getFunc();
while (sx != fd)
Expand Down Expand Up @@ -1035,7 +1034,7 @@ elem *toElem(Expression *e, IRState *irs)
e = el_bin(OPadd, TYnptr, ethis, el_long(TYnptr, soffset));
if (se->op == TOKvar)
e = el_una(OPind, TYnptr, e);
if (ISREF(se->var, tb) && !(ISWIN64REF(se->var) && v && v->offset))
if (ISREF(se->var, tb) && !(ISWIN64REF(se->var) && v && v->offset && !forceStackAccess))
e = el_una(OPind, s->ty(), e);
else if (se->op == TOKsymoff && nrvo)
{
Expand Down
3 changes: 2 additions & 1 deletion src/toir.c
Expand Up @@ -671,7 +671,7 @@ void buildClosure(FuncDeclaration *fd, IRState *irs)
* ~this() { call destructor }
* }
*/
//printf("FuncDeclaration::buildClosure() %s\n", toChars());
//printf("FuncDeclaration::buildClosure() %s\n", fd->toChars());

/* Generate type name for closure struct */
const char *name1 = "CLOSURE.";
Expand Down Expand Up @@ -711,6 +711,7 @@ void buildClosure(FuncDeclaration *fd, IRState *irs)
*/
v->error("cannot reference variadic arguments from closure");
}

/* Align and allocate space for v in the closure
* just like AggregateDeclaration::addField() does.
*/
Expand Down
135 changes: 135 additions & 0 deletions test/runnable/testcontracts.d
Expand Up @@ -697,6 +697,139 @@ void test9383()
a.bar3(103); assert(A9383.val == 103); // closure [parameter]
}

/*******************************************/
// 15524 - Different from issue 9383 cases, closed variable size is bigger than REGSIZE.

class A15524
{
static void delegate() dg;
static string val;

void failInBase() { assert(typeid(this) is typeid(A15524)); }

// in-contract tests
void foo1(string s) in { A15524.val = s; failInBase; } body { } // no closure
void foo2(string s) in { A15524.val = s; failInBase; } body { string x; dg = { x = null; }; } // closure [local]
void foo3(string s) in { A15524.val = s; failInBase; } body { dg = { s = null; }; } // closure [parameter]
void foo4(string s) in { A15524.val = s; failInBase; } body { } // no closure
void foo5(string s) in { A15524.val = s; failInBase; } body { } // no closure
void foo6(string s) in { A15524.val = s; failInBase; } body { string x; dg = { x = null; }; } // closure [local]
void foo7(string s) in { A15524.val = s; failInBase; } body { dg = { s = null; }; } // closure [parameter]

// out-contract tests
void bar1(string s) out { A15524.val = s; } body { } // no closure
void bar2(string s) out { A15524.val = s; } body { string x; dg = { x = null; }; } // closure [local]
void bar3(string s) out { A15524.val = s; } body { dg = { s = null; }; } // closure [parameter]
void bar4(string s) out { A15524.val = s; } body { } // no closure
void bar5(string s) out { A15524.val = s; } body { } // no closure
void bar6(string s) out { A15524.val = s; } body { string x; dg = { x = null; }; } // closure [local]
void bar7(string s) out { A15524.val = s; } body { dg = { s = null; }; } // closure [parameter]
}

class B15524 : A15524
{
static string val;

// in-contract tests
override void foo1(string s) in { B15524.val = s; } body { } // -> no closure
override void foo2(string s) in { B15524.val = s; } body { string x; dg = { x = null; }; } // -> closure [local] appears
override void foo3(string s) in { B15524.val = s; } body { dg = { s = null; }; } // -> closure [parameter]
override void foo4(string s) in { B15524.val = s; } body { string x; dg = { x = null; }; } // -> closure [local] appears
override void foo5(string s) in { B15524.val = s; } body { dg = { s = null; }; } // -> closure [parameter] appears
override void foo6(string s) in { B15524.val = s; } body { } // -> closure [local] disappears
override void foo7(string s) in { B15524.val = s; } body { } // -> closure [parameter] disappears

// out-contract tests
override void bar1(string s) out { B15524.val = s; } body { } // -> no closure
override void bar2(string s) out { B15524.val = s; } body { string x; dg = { x = null; }; } // -> closure [local] appears
override void bar3(string s) out { B15524.val = s; } body { dg = { s = null; }; } // -> closure [parameter]
override void bar4(string s) out { B15524.val = s; } body { string x; dg = { x = null; }; } // -> closure [local] appears
override void bar5(string s) out { B15524.val = s; } body { dg = { s = null; }; } // -> closure [parameter] appears
override void bar6(string s) out { B15524.val = s; } body { } // -> closure [local] disappears
override void bar7(string s) out { B15524.val = s; } body { } // -> closure [parameter] disappears
}

void test15524()
{
auto a = new A15524();
auto b = new B15524();

// base class in-contract is used from derived class. // base derived
b.foo1("1"); assert(A15524.val == "1" && B15524.val == "1"); // no closure -> no closure
b.foo2("2"); assert(A15524.val == "2" && B15524.val == "2"); // closure [local] -> closure [local] appears
b.foo3("3"); assert(A15524.val == "3" && B15524.val == "3"); // closure [parameter] -> closure [parameter]
b.foo4("4"); assert(A15524.val == "4" && B15524.val == "4"); // no closure -> closure [local] appears
b.foo5("5"); assert(A15524.val == "5" && B15524.val == "5"); // no closure -> closure [parameter] appears
b.foo6("6"); assert(A15524.val == "6" && B15524.val == "6"); // closure [local] -> closure [local] disappears
b.foo7("7"); assert(A15524.val == "7" && B15524.val == "7"); // closure [parameter] -> closure [parameter] disappears

// base class out-contract is used from derived class. // base derived
b.bar1("1"); assert(A15524.val == "1" && B15524.val == "1"); // no closure -> no closure
b.bar2("2"); assert(A15524.val == "2" && B15524.val == "2"); // closure [local] -> closure [local] appears
b.bar3("3"); assert(A15524.val == "3" && B15524.val == "3"); // closure [parameter] -> closure [parameter]
b.bar4("4"); assert(A15524.val == "4" && B15524.val == "4"); // no closure -> closure [local] appears
b.bar5("5"); assert(A15524.val == "5" && B15524.val == "5"); // no closure -> closure [parameter] appears
b.bar6("6"); assert(A15524.val == "6" && B15524.val == "6"); // closure [local] -> closure [local] disappears
b.bar7("7"); assert(A15524.val == "7" && B15524.val == "7"); // closure [parameter] -> closure [parameter] disappears

// in-contract in base class.
a.foo1("1"); assert(A15524.val == "1"); // no closure
a.foo2("2"); assert(A15524.val == "2"); // closure [local]
a.foo3("3"); assert(A15524.val == "3"); // closure [parameter]

// out-contract in base class.
a.bar1("1"); assert(A15524.val == "1"); // no closure
a.bar2("2"); assert(A15524.val == "2"); // closure [local]
a.bar3("3"); assert(A15524.val == "3"); // closure [parameter]
}

void test15524a()
{
auto t1 = new Test15524a();
t1.infos["first"] = 0; //t1.add("first");
t1.add("second");

auto t2 = new Test15524b();
t2.add("second");
}

class Test15524a
{
int[string] infos;

void add(string key)
in
{
assert(key !in infos); // @@@ crash here at second
}
body
{
auto item = new class
{
void notCalled()
{
infos[key] = 0;
// affects, key parameter is made a closure variable.
}
};
}
}

class Test15524b
{
void add(string key)
in
{
assert(key == "second"); // @@@ fails
}
body
{
static void delegate() dg;
dg = { auto x = key; };
// affects, key parameter is made a closure variable.
}
}

/*******************************************/
// 10479

Expand Down Expand Up @@ -791,6 +924,8 @@ int main()
test8073();
test8093();
test9383();
test15524();
test15524a();
test14779();

printf("Success\n");
Expand Down

0 comments on commit 2fa1e1b

Please sign in to comment.