From: Bruno Cardoso Lopes Date: Tue, 13 Sep 2016 20:04:35 +0000 (+0000) Subject: [SemaObjC] Be more strict while parsing type arguments and protocols X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=cd4da5b10180783b2520362a76cccfe97cd4b768;p=clang [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 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@281383 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 71cbc451e1..1dfa2f4e7c 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/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/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp index b556995002..ecf8ae8dff 100644 --- a/lib/Parse/ParseObjc.cpp +++ b/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/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index 8cc97e5f0d..78eba62695 100644 --- a/lib/Parse/Parser.cpp +++ b/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/test/SemaObjC/crash-on-type-args-protocols.m b/test/SemaObjC/crash-on-type-args-protocols.m new file mode 100644 index 0000000000..f7d847851f --- /dev/null +++ b/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}}