]> granicus.if.org Git - clang/commitdiff
Don't crash on malformed attributes in an incorrect location.
authorNico Weber <nicolasweber@gmx.de>
Mon, 29 Dec 2014 06:56:50 +0000 (06:56 +0000)
committerNico Weber <nicolasweber@gmx.de>
Mon, 29 Dec 2014 06:56:50 +0000 (06:56 +0000)
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

lib/Parse/ParseDeclCXX.cpp
test/Parser/cxx0x-attributes.cpp

index 14fe9f7cf37f51d7bf68435869b498f540b438c3..4377a7828646ffd1e1a864fecfc02f48f276136f 100644 (file)
@@ -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)) {
index e366d8582e857193e3e1213449b3fb99832d362f..02791f4f54c584fe5bc677abb096903caa31062e 100644 (file)
@@ -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}}