From 4b4be84a2f747bc65ccfe53281ae0aa19259744c Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Mon, 29 Dec 2014 06:56:50 +0000 Subject: [PATCH] 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. llvm-svn: 224915 --- clang/lib/Parse/ParseDeclCXX.cpp | 10 ++++++++++ clang/test/Parser/cxx0x-attributes.cpp | 4 ++++ 2 files changed, 14 insertions(+) diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index 14fe9f7..4377a78 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/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/clang/test/Parser/cxx0x-attributes.cpp b/clang/test/Parser/cxx0x-attributes.cpp index e366d85..02791f4 100644 --- a/clang/test/Parser/cxx0x-attributes.cpp +++ b/clang/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}} -- 2.7.4