PrintfFormatString.cpp revision d2dcece5882215e92a80bff8a7b7fd2fd81d7086
18f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek//= PrintfFormatStrings.cpp - Analysis of printf format strings --*- C++ -*-==// 28f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek// 38f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek// The LLVM Compiler Infrastructure 48f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek// 58f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek// This file is distributed under the University of Illinois Open Source 68f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek// License. See LICENSE.TXT for details. 78f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek// 88f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek//===----------------------------------------------------------------------===// 98f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek// 108f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek// Handling of format string in printf and friends. The structure of format 118f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek// strings for fprintf() are described in C99 7.19.6.1. 128f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek// 138f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek//===----------------------------------------------------------------------===// 148f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek 158f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek#include "clang/Analysis/Analyses/PrintfFormatString.h" 168f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek 178f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenekusing namespace clang; 18d2dcece5882215e92a80bff8a7b7fd2fd81d7086Ted Kremenekusing namespace analyze_printf; 198f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek 208f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremeneknamespace { 218f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenekclass FormatSpecifierResult { 228f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek FormatSpecifier FS; 238f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek const char *Start; 248f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek bool HasError; 258f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenekpublic: 268f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek FormatSpecifierResult(bool err = false) 278f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek : Start(0), HasError(err) {} 288f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek FormatSpecifierResult(const char *start, 29d2dcece5882215e92a80bff8a7b7fd2fd81d7086Ted Kremenek const FormatSpecifier &fs) 308f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek : FS(fs), Start(start), HasError(false) {} 318f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek 328f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek 338f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek const char *getStart() const { return Start; } 348f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek bool hasError() const { return HasError; } 358f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek bool hasValue() const { return Start != 0; } 368f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek const FormatSpecifier &getValue() const { 378f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek assert(hasValue()); 388f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek return FS; 398f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek } 40d2dcece5882215e92a80bff8a7b7fd2fd81d7086Ted Kremenek const FormatSpecifier &getValue() { return FS; } 418f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek}; 428f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek} // end anonymous namespace 438f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek 448f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenektemplate <typename T> 458f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenekclass UpdateOnReturn { 468f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek T &ValueToUpdate; 478f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek const T &ValueToCopy; 488f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenekpublic: 498f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek UpdateOnReturn(T &valueToUpdate, const T &valueToCopy) 508f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek : ValueToUpdate(valueToUpdate), ValueToCopy(valueToCopy) {} 518f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek 528f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek ~UpdateOnReturn() { 538f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek ValueToUpdate = ValueToCopy; 548f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek } 558f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek}; 568f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek 578f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenekstatic OptionalAmount ParseAmount(const char *&Beg, const char *E) { 588f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek const char *I = Beg; 598f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek UpdateOnReturn <const char*> UpdateBeg(Beg, I); 608f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek 618f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek bool foundDigits = false; 628f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek unsigned accumulator = 0; 638f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek 648f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek for ( ; I != E; ++I) { 658f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek char c = *I; 668f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek if (c >= '0' && c <= '9') { 678f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek foundDigits = true; 688f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek accumulator += (accumulator * 10) + (c - '0'); 698f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek continue; 708f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek } 718f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek 728f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek if (foundDigits) 738f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek return OptionalAmount(accumulator); 748f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek 758f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek if (c == '*') 768f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek return OptionalAmount(OptionalAmount::Arg); 778f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek 788f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek break; 798f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek } 808f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek 818f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek return OptionalAmount(); 828f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek} 838f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek 84d2dcece5882215e92a80bff8a7b7fd2fd81d7086Ted Kremenekstatic FormatSpecifierResult ParseFormatSpecifier(FormatStringHandler &H, 858f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek const char *&Beg, const char *E) { 868f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek 878f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek const char *I = Beg; 88c7ae51a3cd9460db8280e8623c90614f246e46d2Ted Kremenek const char *Start = 0; 898f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek UpdateOnReturn <const char*> UpdateBeg(Beg, I); 908f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek 918f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek // Look for a '%' character that indicates the start of a format specifier. 928f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek while (I != E) { 938f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek char c = *I; 948f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek ++I; 958f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek if (c == '\0') { 968f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek // Detect spurious null characters, which are likely errors. 978f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek H.HandleNullChar(I); 988f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek return true; 998f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek } 1008f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek if (c == '%') { 1018f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek Start = I; // Record the start of the format specifier. 1028f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek break; 1038f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek } 1048f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek } 1058f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek 1068f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek // No format specifier found? 1078f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek if (!Start) 1088f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek return false; 1098f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek 1108f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek if (I == E) { 1118f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek // No more characters left? 1128f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek H.HandleIncompleteFormatSpecifier(Start, E); 1138f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek return true; 1148f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek } 1158f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek 1168f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek FormatSpecifier FS; 1178f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek 1188f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek // Look for flags (if any). 1198f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek bool hasMore = true; 1208f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek for ( ; I != E; ++I) { 1218f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek switch (*I) { 1228f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek default: hasMore = false; break; 1238f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek case '-': FS.setIsLeftJustified(); break; 1248f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek case '+': FS.setHasPlusPrefix(); break; 1258f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek case ' ': FS.setHasSpacePrefix(); break; 1268f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek case '#': FS.setHasAlternativeForm(); break; 1278f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek case '0': FS.setHasLeadingZeros(); break; 1288f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek } 1298f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek if (!hasMore) 1308f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek break; 1318f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek } 1328f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek 1338f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek if (I == E) { 1348f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek // No more characters left? 1358f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek H.HandleIncompleteFormatSpecifier(Start, E); 1368f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek return true; 1378f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek } 1388f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek 1398f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek // Look for the field width (if any). 1408f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek FS.setFieldWidth(ParseAmount(I, E)); 1418f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek 1428f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek if (I == E) { 1438f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek // No more characters left? 1448f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek H.HandleIncompleteFormatSpecifier(Start, E); 1458f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek return true; 1468f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek } 1478f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek 1488f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek // Look for the precision (if any). 1498f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek if (*I == '.') { 1508f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek const char *startPrecision = I++; 1518f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek if (I == E) { 1528f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek H.HandleIncompletePrecision(I - 1); 1538f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek return true; 1548f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek } 1558f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek 1568f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek FS.setPrecision(ParseAmount(I, E)); 1578f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek 1588f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek if (I == E) { 1598f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek // No more characters left? 1608f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek H.HandleIncompletePrecision(startPrecision); 1618f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek return true; 1628f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek } 1638f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek } 1648f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek 1658f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek // Look for the length modifier. 1668f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek LengthModifier lm = None; 1678f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek switch (*I) { 1688f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek default: 1698f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek break; 1708f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek case 'h': 1718f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek ++I; 1728f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek lm = (I != E && *I == 'h') ? ++I, AsChar : AsShort; 1738f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek break; 1748f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek case 'l': 1758f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek ++I; 1768f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek lm = (I != E && *I == 'l') ? ++I, AsLongLong : AsLong; 1778f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek break; 1788f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek case 'j': lm = AsIntMax; ++I; break; 1798f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek case 'z': lm = AsSizeT; ++I; break; 1808f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek case 't': lm = AsPtrDiff; ++I; break; 1818f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek case 'L': lm = AsLongDouble; ++I; break; 1828f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek } 1838f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek FS.setLengthModifier(lm); 1848f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek 1858f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek if (I == E) { 1868f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek // No more characters left? 1878f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek H.HandleIncompleteFormatSpecifier(Start, E); 1888f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek return true; 1898f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek } 1908f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek 1918f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek // Finally, look for the conversion specifier. 1928f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek ConversionSpecifier::Kind cs; 1938f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek switch (*I) { 1948f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek default: 1958f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek H.HandleInvalidConversionSpecifier(I); 196c7cbb9bf8e0bf8c3191ef0b782ec198c433d2a4eTed Kremenek return true; 197c7cbb9bf8e0bf8c3191ef0b782ec198c433d2a4eTed Kremenek // C99: 7.19.6.1 (section 8). 198c7ae51a3cd9460db8280e8623c90614f246e46d2Ted Kremenek case 'd': cs = ConversionSpecifier::dArg; break; 199c7ae51a3cd9460db8280e8623c90614f246e46d2Ted Kremenek case 'i': cs = ConversionSpecifier::iArg; break; 200c7ae51a3cd9460db8280e8623c90614f246e46d2Ted Kremenek case 'o': cs = ConversionSpecifier::oArg; break; 201c7ae51a3cd9460db8280e8623c90614f246e46d2Ted Kremenek case 'u': cs = ConversionSpecifier::uArg; break; 202c7ae51a3cd9460db8280e8623c90614f246e46d2Ted Kremenek case 'x': cs = ConversionSpecifier::xArg; break; 203c7ae51a3cd9460db8280e8623c90614f246e46d2Ted Kremenek case 'X': cs = ConversionSpecifier::XArg; break; 204c7ae51a3cd9460db8280e8623c90614f246e46d2Ted Kremenek case 'f': cs = ConversionSpecifier::fArg; break; 205c7ae51a3cd9460db8280e8623c90614f246e46d2Ted Kremenek case 'F': cs = ConversionSpecifier::FArg; break; 206c7ae51a3cd9460db8280e8623c90614f246e46d2Ted Kremenek case 'e': cs = ConversionSpecifier::eArg; break; 207c7ae51a3cd9460db8280e8623c90614f246e46d2Ted Kremenek case 'E': cs = ConversionSpecifier::EArg; break; 208c7ae51a3cd9460db8280e8623c90614f246e46d2Ted Kremenek case 'g': cs = ConversionSpecifier::gArg; break; 209c7ae51a3cd9460db8280e8623c90614f246e46d2Ted Kremenek case 'G': cs = ConversionSpecifier::GArg; break; 210c7ae51a3cd9460db8280e8623c90614f246e46d2Ted Kremenek case 'a': cs = ConversionSpecifier::aArg; break; 211c7ae51a3cd9460db8280e8623c90614f246e46d2Ted Kremenek case 'A': cs = ConversionSpecifier::AArg; break; 212c7ae51a3cd9460db8280e8623c90614f246e46d2Ted Kremenek case 'c': cs = ConversionSpecifier::IntAsCharArg; break; 213c7ae51a3cd9460db8280e8623c90614f246e46d2Ted Kremenek case 's': cs = ConversionSpecifier::CStrArg; break; 214c7ae51a3cd9460db8280e8623c90614f246e46d2Ted Kremenek case 'p': cs = ConversionSpecifier::VoidPtrArg; break; 215c7ae51a3cd9460db8280e8623c90614f246e46d2Ted Kremenek case 'n': cs = ConversionSpecifier::OutIntPtrArg; break; 216c7cbb9bf8e0bf8c3191ef0b782ec198c433d2a4eTed Kremenek case '%': cs = ConversionSpecifier::PercentArg; break; 217c7cbb9bf8e0bf8c3191ef0b782ec198c433d2a4eTed Kremenek // Objective-C. 218c7cbb9bf8e0bf8c3191ef0b782ec198c433d2a4eTed Kremenek case '@': cs = ConversionSpecifier::ObjCObjArg; break; 2198f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek } 2208f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek FS.setConversionSpecifier(cs); 2218f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek return FormatSpecifierResult(Start, FS); 2228f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek} 2238f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek 2248f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenekbool ParseFormatSring(FormatStringHandler &H, const char *I, const char *E) { 2258f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek // Keep looking for a format specifier until we have exhausted the string. 2268f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek while (I != E) { 2278f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek const FormatSpecifierResult &FSR = ParseFormatSpecifier(H, I, E); 2288f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek // Did an error of any kind occur when parsing the specifier? If so, 2298f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek // don't do any more processing. 2308f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek if (FSR.hasError()) 2318f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek return true;; 2328f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek // Done processing the string? 2338f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek if (!FSR.hasValue()) 2348f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek break; 2358f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek // We have a format specifier. Pass it to the callback. 236d5f2096e266b7905df660b7839e69e9ed6ba9018Ted Kremenek if (!H.HandleFormatSpecifier(FSR.getValue(), FSR.getStart(), I)) 237d5f2096e266b7905df660b7839e69e9ed6ba9018Ted Kremenek return false; 2388f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek } 2398f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek assert(I == E && "Format string not exhausted"); 2408f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek return false; 2418f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek} 2428f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek 2438f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted KremenekFormatStringHandler::~FormatStringHandler() {} 244