From: Nico Weber Date: Mon, 29 Dec 2014 06:56:50 +0000 (+0000) Subject: Don't crash on malformed attributes in an incorrect location. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=1a0c408f379c2917912acb4eb91324a8e8d83481;p=clang Don't crash on malformed attributes in an incorrect location. r168626 added nicer diagnostics for attributes in the wrong places, such as after the `final` on a class. To do this, it added code that did high-level pattern matching for e.g. 'final' 'alignas' '(' and then skipped until the closing ')'. If it saw that, it then went down the regular class parsing path and then called MaybeParseCXX11Attributes() to parse the attribute after the 'final' using real attribute parsing code. On invalid attributes, the real attribute parsing code could eat more tokens than the pattern matching code and for example skip past the '{' starting the class, which would then lead to an assert. To prevent this, check for a good state after calling MaybeParseCXX11Attributes() (which morphed into CheckMisplacedCXX11Attribute() in r175575) and bail out if things look bleak. Found by SLi's afl bot. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@224915 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index 14fe9f7cf3..4377a78286 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -2706,6 +2706,16 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, // and the only possible place for them to appertain // to the class would be between class-key and class-name. CheckMisplacedCXX11Attribute(Attrs, AttrFixitLoc); + + // ParseClassSpecifier() does only a superficial check for attributes before + // deciding to call this method. For example, for + // `class C final alignas ([l) {` it will decide that this looks like a + // misplaced attribute since it sees `alignas '(' ')'`. But the actual + // attribute parsing code will try to parse the '[' as a constexpr lambda + // and consume enough tokens that the alignas parsing code will eat the + // opening '{'. So bail out if the next token isn't one we expect. + if (!Tok.is(tok::colon) && !Tok.is(tok::l_brace)) + return; } if (Tok.is(tok::colon)) { diff --git a/test/Parser/cxx0x-attributes.cpp b/test/Parser/cxx0x-attributes.cpp index e366d8582e..02791f4f54 100644 --- a/test/Parser/cxx0x-attributes.cpp +++ b/test/Parser/cxx0x-attributes.cpp @@ -330,3 +330,7 @@ namespace { [[deprecated()]] void foo(); // expected-error {{parentheses must be omitted if 'deprecated' attribute's argument list is empty}} [[gnu::deprecated()]] void quux(); } + +// The diagnostics here don't matter much, this just shouldn't crash: +class C final [[deprecated(l]] {}; // expected-error {{use of undeclared identifier}} expected-error {{expected ']'}} expected-error {{an attribute list cannot appear here}} +class C final alignas ([l) {}; // expected-error {{expected ';' after class}}