diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index c0597cddd55d134e9cea05f96065681d453b8b9d..1f57b26c9efc435d599be43d6eac45e492315127 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -2085,6 +2085,8 @@ void CheckFormatHandler::HandleNullChar(const char *nullCharacter) { } } +// Note that this may return NULL if there was an error parsing or building +// one of the argument expressions. const Expr *CheckFormatHandler::getDataArg(unsigned i) const { return Args[FirstDataArg + i]; } @@ -2098,11 +2100,13 @@ void CheckFormatHandler::DoneProcessing() { signed notCoveredArg = CoveredArgs.find_first(); if (notCoveredArg >= 0) { assert((unsigned)notCoveredArg < NumDataArgs); - SourceLocation Loc = getDataArg((unsigned) notCoveredArg)->getLocStart(); - if (!S.getSourceManager().isInSystemMacro(Loc)) { - EmitFormatDiagnostic(S.PDiag(diag::warn_printf_data_arg_not_used), - Loc, - /*IsStringLocation*/false, getFormatStringRange()); + if (const Expr *E = getDataArg((unsigned) notCoveredArg)) { + SourceLocation Loc = E->getLocStart(); + if (!S.getSourceManager().isInSystemMacro(Loc)) { + EmitFormatDiagnostic(S.PDiag(diag::warn_printf_data_arg_not_used), + Loc, /*IsStringLocation*/false, + getFormatStringRange()); + } } } } @@ -2310,6 +2314,9 @@ bool CheckPrintfHandler::HandleAmount( // doesn't emit a warning for that case. CoveredArgs.set(argIndex); const Expr *Arg = getDataArg(argIndex); + if (!Arg) + return false; + QualType T = Arg->getType(); const analyze_printf::ArgTypeResult &ATR = Amt.getArgType(S.Context); @@ -2571,8 +2578,11 @@ CheckPrintfHandler::HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier if (!CheckNumArgs(FS, CS, startSpecifier, specifierLen, argIndex)) return false; - return checkFormatExpr(FS, startSpecifier, specifierLen, - getDataArg(argIndex)); + const Expr *Arg = getDataArg(argIndex); + if (!Arg) + return true; + + return checkFormatExpr(FS, startSpecifier, specifierLen, Arg); } bool @@ -2788,6 +2798,9 @@ bool CheckScanfHandler::HandleScanfSpecifier( // Check that the argument type matches the format specifier. const Expr *Ex = getDataArg(argIndex); + if (!Ex) + return true; + const analyze_scanf::ScanfArgTypeResult &ATR = FS.getArgType(S.Context); if (ATR.isValid() && !ATR.matchesType(S.Context, Ex->getType())) { ScanfSpecifier fixedFS = FS; diff --git a/test/SemaObjC/format-strings-objc.m b/test/SemaObjC/format-strings-objc.m index 043cb5d8d20871926a068277db931cb2533b8cee..c6f26e53b8ee9a79f0404fa8d4d263e79e66fc48 100644 --- a/test/SemaObjC/format-strings-objc.m +++ b/test/SemaObjC/format-strings-objc.m @@ -210,3 +210,20 @@ void test_nonBuiltinCFStrings() { CFStringCreateWithFormat(__CFStringMakeConstantString("%@"), 1); // expected-warning{{format specifies type 'id' but the argument has type 'int'}} } + +// Don't crash on an invalid argument expression. +// <rdar://problem/11890818> +@interface NSDictionary : NSObject +- (id)objectForKeyedSubscript:(id)key; +@end + +void testInvalidFormatArgument(NSDictionary *dict) { + NSLog(@"no specifiers", dict[CFSTR("abc")]); // expected-error{{indexing expression is invalid because subscript type 'CFStringRef' (aka 'const struct __CFString *') is not an integral or objective-C pointer type}} + NSLog(@"%@", dict[CFSTR("abc")]); // expected-error{{indexing expression is invalid because subscript type 'CFStringRef' (aka 'const struct __CFString *') is not an integral or objective-C pointer type}} + NSLog(@"%@ %@", dict[CFSTR("abc")]); // expected-error{{indexing expression is invalid because subscript type 'CFStringRef' (aka 'const struct __CFString *') is not an integral or objective-C pointer type}} + + [Foo fooWithFormat:@"no specifiers", dict[CFSTR("abc")]]; // expected-error{{indexing expression is invalid because subscript type 'CFStringRef' (aka 'const struct __CFString *') is not an integral or objective-C pointer type}} + [Foo fooWithFormat:@"%@", dict[CFSTR("abc")]]; // expected-error{{indexing expression is invalid because subscript type 'CFStringRef' (aka 'const struct __CFString *') is not an integral or objective-C pointer type}} + [Foo fooWithFormat:@"%@ %@", dict[CFSTR("abc")]]; // expected-error{{indexing expression is invalid because subscript type 'CFStringRef' (aka 'const struct __CFString *') is not an integral or objective-C pointer type}} expected-warning{{more '%' conversions than data arguments}} +} +