bruno created this revision. bruno added a reviewer: doug.gregor. bruno added subscribers: cfe-commits, manmanren.
Fix a crash-on-invalid. When parsing type arguments and protocols, ParseTypeName() 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 '>'. ParseTypeName() can parse a variety combination of names, making this case complicated to handle by looking tokens ahead. Fix the issue by doing temptive parsing in the remaining type arg list, and revert the token state in case tok::eof is reached. rdar://problem/25063557 https://reviews.llvm.org/D23852 Files: lib/Parse/ParseObjc.cpp test/SemaObjC/crash-on-type-args-protocols.m Index: test/SemaObjC/crash-on-type-args-protocols.m =================================================================== --- /dev/null +++ test/SemaObjC/crash-on-type-args-protocols.m @@ -0,0 +1,37 @@ +// RUN: %clang_cc1 -DFIRST -fsyntax-only -verify %s +// RUN: %clang_cc1 -DSECOND -fsyntax-only -verify %s +// RUN: %clang_cc1 -DTHIRD -fsyntax-only -verify %s + +@protocol P; +@interface NSObject +@end +@protocol X +@end +@interface X : NSObject <X> +@end + +@class A; + +#ifdef FIRST +id<X> F1(id<[P> v) { // expected-error {{expected a type}} // expected-error {{use of undeclared identifier 'P'}} // expected-error {{use of undeclared identifier 'v'}} // expected-error {{expected '>'}} // expected-error {{expected ')'}} // expected-note {{to match this '('}} + return 0; +} + +id<X> F2(id<P[X> v) { // expected-error {{unknown type name 'P'}} // expected-error {{unexpected interface name 'X': expected expression}} // expected-error {{use of undeclared identifier 'v'}} // expected-error {{expected '>'}} // expected-error {{unexpected interface name 'X': expected expression}} // expected-error {{use of undeclared identifier 'v'}} // expected-note {{to match this '('}} + return 0; +} +#endif + +#ifdef SECOND +id<X> F3(id<P, P *[> v) { // expected-error {{unknown type name 'P'}} // expected-error {{expected expression}} // expected-error {{use of undeclared identifier 'v'}} // expected-error {{expected '>'}} // expected-error {{expected expression}} // expected-error {{use of undeclared identifier 'v'}} // expected-note {{to match this '('}} + return 0; +} +#endif + +#ifdef THIRD +id<X> F4(id<P, P *(> v { // expected-error {{unknown type name 'P'}} // expected-error {{expected ')'}} // expected-error {{expected '>'}} // expected-error {{expected ')'}} // expected-note {{to match this '('}} // expected-note {{to match this '('}} // expected-note {{to match this '('}} + return 0; +} +#endif + + // expected-error {{expected ')'}} // expected-error {{expected function body after function declarator}} Index: lib/Parse/ParseObjc.cpp =================================================================== --- lib/Parse/ParseObjc.cpp +++ lib/Parse/ParseObjc.cpp @@ -1740,6 +1740,10 @@ } } + // ParseTypeName() can advance the token stream up to tok::eof when there's + // an umatched token (e.g. "["). Restore the state in case this happens. + TentativeParsingAction TPA(*this); + // Continue parsing type-names. do { Token CurTypeTok = Tok; @@ -1763,6 +1767,11 @@ } } while (TryConsumeToken(tok::comma)); + if (Tok.is(tok::eof)) + TPA.Revert(); + else + TPA.Commit(); + // Diagnose the mix between type args and protocols. if (foundProtocolId && foundValidTypeId) Actions.DiagnoseTypeArgsAndProtocols(foundProtocolId, foundProtocolSrcLoc,
Index: test/SemaObjC/crash-on-type-args-protocols.m =================================================================== --- /dev/null +++ test/SemaObjC/crash-on-type-args-protocols.m @@ -0,0 +1,37 @@ +// RUN: %clang_cc1 -DFIRST -fsyntax-only -verify %s +// RUN: %clang_cc1 -DSECOND -fsyntax-only -verify %s +// RUN: %clang_cc1 -DTHIRD -fsyntax-only -verify %s + +@protocol P; +@interface NSObject +@end +@protocol X +@end +@interface X : NSObject <X> +@end + +@class A; + +#ifdef FIRST +id<X> F1(id<[P> v) { // expected-error {{expected a type}} // expected-error {{use of undeclared identifier 'P'}} // expected-error {{use of undeclared identifier 'v'}} // expected-error {{expected '>'}} // expected-error {{expected ')'}} // expected-note {{to match this '('}} + return 0; +} + +id<X> F2(id<P[X> v) { // expected-error {{unknown type name 'P'}} // expected-error {{unexpected interface name 'X': expected expression}} // expected-error {{use of undeclared identifier 'v'}} // expected-error {{expected '>'}} // expected-error {{unexpected interface name 'X': expected expression}} // expected-error {{use of undeclared identifier 'v'}} // expected-note {{to match this '('}} + return 0; +} +#endif + +#ifdef SECOND +id<X> F3(id<P, P *[> v) { // expected-error {{unknown type name 'P'}} // expected-error {{expected expression}} // expected-error {{use of undeclared identifier 'v'}} // expected-error {{expected '>'}} // expected-error {{expected expression}} // expected-error {{use of undeclared identifier 'v'}} // expected-note {{to match this '('}} + return 0; +} +#endif + +#ifdef THIRD +id<X> F4(id<P, P *(> v { // expected-error {{unknown type name 'P'}} // expected-error {{expected ')'}} // expected-error {{expected '>'}} // expected-error {{expected ')'}} // expected-note {{to match this '('}} // expected-note {{to match this '('}} // expected-note {{to match this '('}} + return 0; +} +#endif + + // expected-error {{expected ')'}} // expected-error {{expected function body after function declarator}} Index: lib/Parse/ParseObjc.cpp =================================================================== --- lib/Parse/ParseObjc.cpp +++ lib/Parse/ParseObjc.cpp @@ -1740,6 +1740,10 @@ } } + // ParseTypeName() can advance the token stream up to tok::eof when there's + // an umatched token (e.g. "["). Restore the state in case this happens. + TentativeParsingAction TPA(*this); + // Continue parsing type-names. do { Token CurTypeTok = Tok; @@ -1763,6 +1767,11 @@ } } while (TryConsumeToken(tok::comma)); + if (Tok.is(tok::eof)) + TPA.Revert(); + else + TPA.Commit(); + // Diagnose the mix between type args and protocols. if (foundProtocolId && foundValidTypeId) Actions.DiagnoseTypeArgsAndProtocols(foundProtocolId, foundProtocolSrcLoc,
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits