From 218c8743c8d5d18e42ee22afad2eaa9603575507 Mon Sep 17 00:00:00 2001 From: Bruno Cardoso Lopes Date: Tue, 13 Sep 2016 20:04:35 +0000 Subject: [PATCH] [SemaObjC] Be more strict while parsing type arguments and protocols Fix a crash-on-invalid. When parsing type arguments and protocols, parseObjCTypeArgsOrProtocolQualifiers() calls ParseTypeName(), which tries to find matching tokens for '[', '(', etc whenever they appear among potential type names. If unmatched, ParseTypeName() yields a tok::eof token stream. This leads to crashes since the parsing at this point is not expected to go beyond the param list closing '>'. Fix that by properly handling tok::eof in parseObjCTypeArgsOrProtocolQualifiers() callers. Differential Revision: https://reviews.llvm.org/D23852 rdar://problem/25063557 llvm-svn: 281383 --- clang/lib/Parse/ParseDecl.cpp | 3 +- clang/lib/Parse/ParseObjc.cpp | 9 ++++- clang/lib/Parse/Parser.cpp | 4 +++ clang/test/SemaObjC/crash-on-type-args-protocols.m | 40 ++++++++++++++++++++++ 4 files changed, 54 insertions(+), 2 deletions(-) create mode 100644 clang/test/SemaObjC/crash-on-type-args-protocols.m diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 71cbc45..1dfa2f4 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -5877,7 +5877,8 @@ bool Parser::isFunctionDeclaratorIdentifierList() { // To handle this, we check to see if the token after the first // identifier is a "," or ")". Only then do we parse it as an // identifier list. - && (NextToken().is(tok::comma) || NextToken().is(tok::r_paren)); + && (!Tok.is(tok::eof) && + (NextToken().is(tok::comma) || NextToken().is(tok::r_paren))); } /// ParseFunctionDeclaratorIdentifierList - While parsing a function declarator diff --git a/clang/lib/Parse/ParseObjc.cpp b/clang/lib/Parse/ParseObjc.cpp index b556995..ecf8ae8 100644 --- a/clang/lib/Parse/ParseObjc.cpp +++ b/clang/lib/Parse/ParseObjc.cpp @@ -344,9 +344,11 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc, protocols, protocolLocs, EndProtoLoc, /*consumeLastToken=*/true, /*warnOnIncompleteProtocols=*/true); + if (Tok.is(tok::eof)) + return nullptr; } } - + // Next, we need to check for any protocol references. if (LAngleLoc.isValid()) { if (!ProtocolIdents.empty()) { @@ -1814,6 +1816,8 @@ void Parser::parseObjCTypeArgsAndProtocolQualifiers( protocolRAngleLoc, consumeLastToken, /*warnOnIncompleteProtocols=*/false); + if (Tok.is(tok::eof)) // Nothing else to do here... + return; // An Objective-C object pointer followed by type arguments // can then be followed again by a set of protocol references, e.g., @@ -1862,6 +1866,9 @@ TypeResult Parser::parseObjCTypeArgsAndProtocolQualifiers( protocols, protocolLocs, protocolRAngleLoc, consumeLastToken); + if (Tok.is(tok::eof)) + return true; // Invalid type result. + // Compute the location of the last token. if (consumeLastToken) endLoc = PrevTokLocation; diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index 8cc97e5..78eba62 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -1539,6 +1539,8 @@ Parser::TryAnnotateName(bool IsAddressOfOperand, NewEndLoc); if (NewType.isUsable()) Ty = NewType.get(); + else if (Tok.is(tok::eof)) // Nothing to do here, bail out... + return ANK_Error; } Tok.setKind(tok::annot_typename); @@ -1770,6 +1772,8 @@ bool Parser::TryAnnotateTypeOrScopeTokenAfterScopeSpec(bool EnteringContext, NewEndLoc); if (NewType.isUsable()) Ty = NewType.get(); + else if (Tok.is(tok::eof)) // Nothing to do here, bail out... + return false; } // This is a typename. Replace the current token in-place with an diff --git a/clang/test/SemaObjC/crash-on-type-args-protocols.m b/clang/test/SemaObjC/crash-on-type-args-protocols.m new file mode 100644 index 0000000..f7d8478 --- /dev/null +++ b/clang/test/SemaObjC/crash-on-type-args-protocols.m @@ -0,0 +1,40 @@ +// RUN: %clang_cc1 -DFIRST -fsyntax-only -verify %s +// RUN: %clang_cc1 -DSECOND -fsyntax-only -verify %s +// RUN: %clang_cc1 -DTHIRD -fsyntax-only -verify %s +// RUN: %clang_cc1 -DFOURTH -fsyntax-only -verify %s + +@protocol P; +@interface NSObject +@end +@protocol X +@end +@interface X : NSObject +@end + +@class A; + +#ifdef FIRST +id F1(id<[P> v) { // expected-error {{expected a type}} // expected-error {{use of undeclared identifier 'P'}} // expected-error {{use of undeclared identifier 'v'}} // expected-note {{to match this '('}} + return 0; +} +#endif + +#ifdef SECOND +id F2(id v) { // expected-error {{unknown type name 'P'}} // expected-error {{unexpected interface name 'X': expected expression}} // expected-error {{use of undeclared identifier 'v'}} // expected-note {{to match this '('}} + return 0; +} +#endif + +#ifdef THIRD +id F3(id v) { // expected-error {{unknown type name 'P'}} // expected-error {{expected expression}} // expected-error {{use of undeclared identifier 'v'}} // expected-note {{to match this '('}} + return 0; +} +#endif + +#ifdef FOURTH +id F4(id v { // expected-error {{unknown type name 'P'}} // expected-error {{expected ')'}} // expected-note {{to match this '('}} // expected-note {{to match this '('}} + return 0; +} +#endif + +// expected-error {{expected '>'}} // expected-error {{expected parameter declarator}} // expected-error {{expected ')'}} // expected-error {{expected function body after function declarator}} -- 2.7.4