Skip to content

Commit

Permalink
Merge pull request #5075 from 9rnsr/fix15044
Browse files Browse the repository at this point in the history
[REG2.068.0] Issue 15044 - destroy might leak memory
  • Loading branch information
MartinNowak committed Sep 14, 2015
2 parents ea5d85a + 664b202 commit af4d3a4
Show file tree
Hide file tree
Showing 7 changed files with 132 additions and 3 deletions.
26 changes: 26 additions & 0 deletions src/class.c
Original file line number Diff line number Diff line change
Expand Up @@ -743,6 +743,32 @@ void ClassDeclaration::semantic(Scope *sc)
//printf("-ClassDeclaration::semantic(%s), type = %p\n", toChars(), type);
//members->print();

#if 0 // FIXME
LafterSizeok:
// The additions of special member functions should have its own
// sub-semantic analysis pass, and have to be deferred sometimes.
// See the case in compilable/test14838.d
for (size_t i = 0; i < fields.dim; i++)
{
VarDeclaration *v = fields[i];
Type *tb = v->type->baseElemOf();
if (tb->ty != Tstruct)
continue;
StructDeclaration *sd = ((TypeStruct *)tb)->sym;
if (sd->semanticRun >= PASSsemanticdone)
continue;

sc2->pop();

scope = scx ? scx : sc->copy();
scope->setNoFree();
scope->module->addDeferredSemantic(this);

//printf("\tdeferring %s\n", toChars());
return;
}
#endif

/* Look for special member functions.
* They must be in this class, not in a base class.
*/
Expand Down
11 changes: 10 additions & 1 deletion src/clone.c
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,7 @@ FuncDeclaration *buildOpAssign(StructDeclaration *sd, Scope *sc)
TypeFunction *tf = new TypeFunction(fparams, sd->handleType(), 0, LINKd, stc | STCref);

FuncDeclaration *fop = new FuncDeclaration(declLoc, Loc(), Id::assign, stc, tf);
fop->storage_class |= STCinference;

Expression *e = NULL;
if (stc & STCdisable)
Expand Down Expand Up @@ -310,7 +311,7 @@ FuncDeclaration *buildOpAssign(StructDeclaration *sd, Scope *sc)

fop->semantic(sc2);
fop->semantic2(sc2);
fop->semantic3(sc2);
// Bugzilla 15044: fop->semantic3 isn't run here for lazy forward reference resolution.

sc2->pop();
if (global.endGagging(errors)) // if errors happened
Expand Down Expand Up @@ -799,6 +800,7 @@ FuncDeclaration *buildPostBlit(StructDeclaration *sd, Scope *sc)
StructDeclaration *sdv = ((TypeStruct *)tv)->sym;
if (!sdv->postblit)
continue;
sdv->postblit->functionSemantic();

stc = mergeFuncAttrs(stc, sdv->postblit);
stc = mergeFuncAttrs(stc, sdv->dtor);
Expand Down Expand Up @@ -852,6 +854,8 @@ FuncDeclaration *buildPostBlit(StructDeclaration *sd, Scope *sc)
*/
if (!sdv->dtor)
continue;
sdv->dtor->functionSemantic();

ex = new ThisExp(loc);
ex = new DotVarExp(loc, ex, v, 0);
if (v->type->toBasetype()->ty == Tstruct)
Expand Down Expand Up @@ -896,6 +900,7 @@ FuncDeclaration *buildPostBlit(StructDeclaration *sd, Scope *sc)
{
//printf("Building __fieldPostBlit()\n");
PostBlitDeclaration *dd = new PostBlitDeclaration(declLoc, Loc(), stc, Id::__fieldPostblit);
dd->storage_class |= STCinference;
dd->fbody = a ? new CompoundStatement(loc, a) : NULL;
sd->postblits.shift(dd);
sd->members->push(dd);
Expand Down Expand Up @@ -930,6 +935,7 @@ FuncDeclaration *buildPostBlit(StructDeclaration *sd, Scope *sc)
e = Expression::combine(e, ex);
}
PostBlitDeclaration *dd = new PostBlitDeclaration(declLoc, Loc(), stc, Id::__aggrPostblit);
dd->storage_class |= STCinference;
dd->fbody = new ExpStatement(loc, e);
sd->members->push(dd);
dd->semantic(sc);
Expand Down Expand Up @@ -973,6 +979,7 @@ FuncDeclaration *buildDtor(AggregateDeclaration *ad, Scope *sc)
StructDeclaration *sdv = ((TypeStruct *)tv)->sym;
if (!sdv->dtor)
continue;
sdv->dtor->functionSemantic();

stc = mergeFuncAttrs(stc, sdv->dtor);
if (stc & STCdisable)
Expand Down Expand Up @@ -1025,6 +1032,7 @@ FuncDeclaration *buildDtor(AggregateDeclaration *ad, Scope *sc)
{
//printf("Building __fieldDtor()\n");
DtorDeclaration *dd = new DtorDeclaration(declLoc, Loc(), stc, Id::__fieldDtor);
dd->storage_class |= STCinference;
dd->fbody = new ExpStatement(loc, e);
ad->dtors.shift(dd);
ad->members->push(dd);
Expand Down Expand Up @@ -1059,6 +1067,7 @@ FuncDeclaration *buildDtor(AggregateDeclaration *ad, Scope *sc)
e = Expression::combine(ex, e);
}
DtorDeclaration *dd = new DtorDeclaration(declLoc, Loc(), stc, Id::__aggrDtor);
dd->storage_class |= STCinference;
dd->fbody = new ExpStatement(loc, e);
ad->members->push(dd);
dd->semantic(sc);
Expand Down
1 change: 1 addition & 0 deletions src/declaration.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ enum PINLINE;
#define STCnogc 0x40000000000LL // @nogc
#define STCvolatile 0x80000000000LL // destined for volatile in the back end
#define STCreturn 0x100000000000LL // 'return ref' for function parameters
#define STCinference 0x200000000000LL // do attribute inference

const StorageClass STCStorageClass = (STCauto | STCscope | STCstatic | STCextern | STCconst | STCfinal |
STCabstract | STCsynchronized | STCdeprecated | STCoverride | STClazy | STCalias |
Expand Down
31 changes: 29 additions & 2 deletions src/func.c
Original file line number Diff line number Diff line change
Expand Up @@ -1167,6 +1167,7 @@ void FuncDeclaration::semantic(Scope *sc)
TemplateInstance *ti;
if (fbody &&
(isFuncLiteralDeclaration() ||
(storage_class & STCinference) ||
(inferRetType && !isCtorDeclaration()) ||
isInstantiated() && !isVirtualMethod() &&
!(ti = parent->isTemplateInstance(), ti && !ti->isTemplateMixin() && ti->tempdecl->ident != ident)))
Expand Down Expand Up @@ -1226,7 +1227,6 @@ void FuncDeclaration::semantic3(Scope *sc)
{
VarDeclaration *argptr = NULL;
VarDeclaration *_arguments = NULL;
int nerrors = global.errors;

if (!parent)
{
Expand All @@ -1243,6 +1243,28 @@ void FuncDeclaration::semantic3(Scope *sc)
//{ static int x; if (++x == 2) *(char*)0=0; }
//printf("\tlinkage = %d\n", sc->linkage);

if (ident == Id::assign && !inuse)
{
if (storage_class & STCinference)
{
/* Bugzilla 15044: For generated opAssign function, any errors
* from its body need to be gagged.
*/
unsigned oldErrors = global.startGagging();
++inuse;
semantic3(sc);
--inuse;
if (global.endGagging(oldErrors)) // if errors happened
{
// Disable generated opAssign, because some members forbid identity assignment.
storage_class |= STCdisable;
fbody = NULL; // remove fbody which contains the error
semantic3Errors = false;
}
return;
}
}

//printf(" sc->incontract = %d\n", (sc->flags & SCOPEcontract));
if (semanticRun >= PASSsemantic3)
return;
Expand All @@ -1261,6 +1283,8 @@ void FuncDeclaration::semantic3(Scope *sc)
return;
}

unsigned oldErrors = global.errors;

if (frequire)
{
for (size_t i = 0; i < foverrides.dim; i++)
Expand Down Expand Up @@ -2189,7 +2213,7 @@ void FuncDeclaration::semantic3(Scope *sc)
* Otherwise, error gagging should be temporarily ungagged by functionSemantic3.
*/
semanticRun = PASSsemantic3done;
semantic3Errors = (global.errors != nerrors) || (fbody && fbody->isErrorStatement());
semantic3Errors = (global.errors != oldErrors) || (fbody && fbody->isErrorStatement());
if (type->ty == Terror)
errors = true;
//printf("-FuncDeclaration::semantic3('%s.%s', sc = %p, loc = %s)\n", parent->toChars(), toChars(), sc, loc.toChars());
Expand Down Expand Up @@ -2237,6 +2261,9 @@ bool FuncDeclaration::functionSemantic()
return functionSemantic3();
}

if (storage_class & STCinference)
return functionSemantic3();

return true;
}

Expand Down
1 change: 1 addition & 0 deletions src/magicport.json
Original file line number Diff line number Diff line change
Expand Up @@ -1597,6 +1597,7 @@
"variable STCnogc",
"variable STCvolatile",
"variable STCreturn",
"variable STCinference",
"variable STCStorageClass",
"struct Match",
"enum Semantic",
Expand Down
32 changes: 32 additions & 0 deletions test/fail_compilation/fail15044.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
TEST_OUTPUT:
---
fail_compilation/fail15044.d(30): Error: function fail15044.V.opAssign is not callable because it is annotated with @disable
---
*/

struct S
{
void opAssign(S) {}
}

struct V
{
// `s` has opAssign, so struct V needs to generate member-wise opAssign.
// But S.opAssign is not callable on const object, so V.opAssign should be
// @disable.
const S s;

// Here, the initializer of x is evaluated in V.semantic2. But
// V.opAssign.semantic3 is not yet invoked, so its attribute should be
// lazily inferred in functionSemantic even though it's non-instantiated function.
enum int x = ()
{
// Here, the initializer of x is evaluated in V.semantic2, and
// V.opAssign.semantic3 is not yet invoked in this time.
// Therefore its @disable attribute needs to be inferred by
// functionSemantic, even though it's non-instantiated function.
V v;
v = v;
}();
}
33 changes: 33 additions & 0 deletions test/runnable/testassign.d
Original file line number Diff line number Diff line change
Expand Up @@ -1129,6 +1129,39 @@ void test14672()
assert(ba[0] is d);
}

/***************************************************/
// 15044

void destroy15044(T)(ref T obj)
{
static if (__traits(hasMember, T, "__xdtor"))
obj.__xdtor();
else
static assert(0, T.stringof);
}

struct V15044
{
~this()
{
}

RC15044!V15044 dup()
{
return RC15044!V15044(&this);
}
}

struct RC15044(T)
{
~this()
{
destroy15044(*t);
static assert(__traits(hasMember, T, "__xdtor"));
}
T* t;
}

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

int main()
Expand Down

0 comments on commit af4d3a4

Please sign in to comment.