Skip to content

Commit

Permalink
Issue 14532 - switch block allows creating uninitialized variables
Browse files Browse the repository at this point in the history
  • Loading branch information
ibuclaw committed Jul 23, 2017
1 parent 58b7f1c commit 38c1683
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 1 deletion.
51 changes: 50 additions & 1 deletion src/statement.c
Expand Up @@ -284,7 +284,7 @@ int Statement::blockExit(FuncDeclaration *func, bool mustNotThrow)

void visit(CompoundStatement *cs)
{
//printf("CompoundStatement::blockExit(%p) %d\n", cs, cs->statements->dim);
//printf("CompoundStatement::blockExit(%p) %d result = x%X\n", cs, cs->statements->dim, result);
result = BEfallthru;
Statement *slast = NULL;
for (size_t i = 0; i < cs->statements->dim; i++)
Expand Down Expand Up @@ -3350,6 +3350,8 @@ Statement *SwitchStatement::semantic(Scope *sc)

bool needswitcherror = false;

lastVar = sc->lastVar;

sc = sc->push();
sc->sbreak = this;
sc->sw = this;
Expand Down Expand Up @@ -3458,6 +3460,9 @@ Statement *SwitchStatement::semantic(Scope *sc)
_body = cs;
}

if (checkLabel())
goto Lerror;

sc->pop();
return this;

Expand All @@ -3471,6 +3476,46 @@ bool SwitchStatement::hasBreak()
return true;
}

static bool checkVar(SwitchStatement *s, VarDeclaration *vd)
{
if (!vd || vd->isDataseg() || (vd->storage_class & STCmanifest))
return false;

VarDeclaration *last = s->lastVar;
while (last && last != vd)
last = last->lastVar;
if (last == vd)
{
// All good, the label's scope has no variables
}
else if (vd->ident == Id::withSym)
{
s->error("'switch' skips declaration of 'with' temporary at %s", vd->loc.toChars());
return true;
}
else
{
s->error("'switch' skips declaration of variable %s at %s", vd->toPrettyChars(), vd->loc.toChars());
return true;
}

return false;
}

bool SwitchStatement::checkLabel()
{
if (sdefault && checkVar(this, sdefault->lastVar))
return true;

for (size_t i = 0; i < cases->dim; i++)
{
CaseStatement *scase = (*cases)[i];
if (scase && checkVar(this, scase->lastVar))
return true;
}
return false;
}

/******************************** CaseStatement ***************************/

CaseStatement::CaseStatement(Loc loc, Expression *exp, Statement *s)
Expand Down Expand Up @@ -3581,6 +3626,8 @@ Statement *CaseStatement::semantic(Scope *sc)
return statement;
if (errors || exp->op == TOKerror)
return new ErrorStatement();

lastVar = sc->lastVar;
return this;
}

Expand Down Expand Up @@ -3743,6 +3790,8 @@ Statement *DefaultStatement::semantic(Scope *sc)
statement = statement->semantic(sc);
if (errors || statement->isErrorStatement())
return new ErrorStatement();

lastVar = sc->lastVar;
return this;
}

Expand Down
4 changes: 4 additions & 0 deletions src/statement.h
Expand Up @@ -424,11 +424,13 @@ class SwitchStatement : public Statement
CaseStatements *cases; // array of CaseStatement's
int hasNoDefault; // !=0 if no default statement
int hasVars; // !=0 if has variable case values
VarDeclaration *lastVar;

SwitchStatement(Loc loc, Expression *c, Statement *b, bool isFinal);
Statement *syntaxCopy();
Statement *semantic(Scope *sc);
bool hasBreak();
bool checkLabel();

void accept(Visitor *v) { v->visit(this); }
};
Expand All @@ -440,6 +442,7 @@ class CaseStatement : public Statement
Statement *statement;

int index; // which case it is (since we sort this)
VarDeclaration *lastVar;

CaseStatement(Loc loc, Expression *exp, Statement *s);
Statement *syntaxCopy();
Expand Down Expand Up @@ -469,6 +472,7 @@ class DefaultStatement : public Statement
{
public:
Statement *statement;
VarDeclaration *lastVar;

DefaultStatement(Loc loc, Statement *s);
Statement *syntaxCopy();
Expand Down

0 comments on commit 38c1683

Please sign in to comment.