GH-955: Prohibit fallthrough in typecasting switch cases

This commit is contained in:
Jon Siwek 2020-08-26 12:55:10 -07:00
parent ff0aa6b050
commit 3368958ac1
4 changed files with 101 additions and 5 deletions

View file

@ -484,6 +484,23 @@ static StmtTag get_last_stmt_tag(const Stmt* stmt)
return get_last_stmt_tag(stmts->Stmts()[len - 1]);
}
class FallthroughFinder : public TraversalCallback {
TraversalCode PreStmt(const Stmt* stmt) override
{
if ( stmt->Tag() == STMT_SWITCH )
// Don't search within nested switch-statements.
return TC_ABORTSTMT;
if ( stmt->Tag() != STMT_FALLTHROUGH )
return TC_CONTINUE;
reporter->PushLocation(stmt->GetLocationInfo());
reporter->Error("invalid 'fallthrough' in type-casting 'case' block");
reporter->PopLocation();
return TC_CONTINUE;
}
};
Case::Case(ListExprPtr arg_expr_cases, IDPList* arg_type_cases,
StmtPtr arg_s)
: expr_cases(std::move(arg_expr_cases)), type_cases(arg_type_cases),
@ -493,15 +510,27 @@ Case::Case(ListExprPtr arg_expr_cases, IDPList* arg_type_cases,
if ( t != STMT_BREAK && t != STMT_FALLTHROUGH && t != STMT_RETURN )
Error("case block must end in break/fallthrough/return statement");
if ( type_cases && Body() )
for ( const auto& id : *type_cases )
if ( id->Name() )
{
FallthroughFinder ff;
Body()->Traverse(&ff);
break;
}
}
Case::~Case()
{
if ( type_cases )
{
for ( const auto& id : *type_cases )
Unref(id);
delete type_cases;
}
}
void Case::Describe(ODesc* d) const
{

View file

@ -1638,13 +1638,13 @@ case_list:
case:
TOK_CASE expr_list ':' stmt_list
{ $$ = new zeek::detail::Case({zeek::AdoptRef{}, $2}, 0, {zeek::AdoptRef{}, $4}); }
{ $$ = new zeek::detail::Case({zeek::AdoptRef{}, $2}, nullptr, {zeek::AdoptRef{}, $4}); }
|
TOK_CASE case_type_list ':' stmt_list
{ $$ = new zeek::detail::Case(nullptr, $2, {zeek::AdoptRef{}, $4}); }
|
TOK_DEFAULT ':' stmt_list
{ $$ = new zeek::detail::Case(nullptr, 0, {zeek::AdoptRef{}, $3}); }
{ $$ = new zeek::detail::Case(nullptr, nullptr, {zeek::AdoptRef{}, $3}); }
;
case_type_list:

View file

@ -0,0 +1,3 @@
error in /home/jon/pro/zeek/zeek/testing/btest/.tmp/language.switch-type-cast-fallthrough-error/switch-type-cast-fallthrough-error.zeek, line 9: invalid 'fallthrough' in type-casting 'case' block
error in /home/jon/pro/zeek/zeek/testing/btest/.tmp/language.switch-type-cast-fallthrough-error/switch-type-cast-fallthrough-error.zeek, line 20: invalid 'fallthrough' in type-casting 'case' block
error in /home/jon/pro/zeek/zeek/testing/btest/.tmp/language.switch-type-cast-fallthrough-error/switch-type-cast-fallthrough-error.zeek, line 22: invalid 'fallthrough' in type-casting 'case' block

View file

@ -0,0 +1,64 @@
# @TEST-EXEC-FAIL: zeek -b %INPUT >out 2>&1
# @TEST-EXEC: TEST_DIFF_CANONIFIER=$SCRIPTS/diff-remove-abspath btest-diff out
local x: any = 0;
switch ( x ) {
case type count as i:
print "count", i;
fallthrough; # This is invalid
case type double as d:
print "double", d;
break;
}
switch ( x ) {
case type count as i:
print "count", i;
if ( i == 0 )
fallthrough; # This is invalid
else
fallthrough; # This is invalid
break;
case type double as d:
print "double", d;
break;
}
switch ( x ) {
case type count as i:
print "count", i;
switch ( x as count ) {
case 0:
fallthrough; # This is valid (inside nested switch statement)
case 1:
print "1";
break;
}
break;
case type double as d:
print "double", d;
break;
}
switch ( x as count ) {
case 0:
print "0";
fallthrough;
case 1:
print "1";
break;
}
switch ( x ) {
case type count:
print "count";
fallthrough;
case type double:
print "double";
break;
}