PrintfFormatString.cpp revision 826a3457f737f1fc45a22954fd1bfde38160c165
1826a3457f737f1fc45a22954fd1bfde38160c165Ted Kremenek//== PrintfFormatString.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 15826a3457f737f1fc45a22954fd1bfde38160c165Ted Kremenek#include "clang/Analysis/Analyses/FormatString.h" 16826a3457f737f1fc45a22954fd1bfde38160c165Ted Kremenek#include "FormatStringParsing.h" 178f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek 18826a3457f737f1fc45a22954fd1bfde38160c165Ted Kremenekusing clang::analyze_format_string::ArgTypeResult; 19826a3457f737f1fc45a22954fd1bfde38160c165Ted Kremenekusing clang::analyze_format_string::FormatStringHandler; 20826a3457f737f1fc45a22954fd1bfde38160c165Ted Kremenekusing clang::analyze_format_string::LengthModifier; 21826a3457f737f1fc45a22954fd1bfde38160c165Ted Kremenekusing clang::analyze_format_string::OptionalAmount; 223bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Careusing clang::analyze_printf::ConversionSpecifier; 23826a3457f737f1fc45a22954fd1bfde38160c165Ted Kremenekusing clang::analyze_printf::PrintfSpecifier; 24efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek 25808015a18bd97781ce437831a95a92fdfc8d5136Ted Kremenekusing namespace clang; 268f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek 27826a3457f737f1fc45a22954fd1bfde38160c165Ted Kremenektypedef clang::analyze_format_string::SpecifierResult<PrintfSpecifier> 28826a3457f737f1fc45a22954fd1bfde38160c165Ted Kremenek PrintfSpecifierResult; 294e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek 304e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek//===----------------------------------------------------------------------===// 314e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek// Methods for parsing format strings. 324e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek//===----------------------------------------------------------------------===// 338f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek 34826a3457f737f1fc45a22954fd1bfde38160c165Ted Kremenekusing analyze_format_string::ParseNonPositionAmount; 35efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek 36826a3457f737f1fc45a22954fd1bfde38160c165Ted Kremenekstatic bool ParsePrecision(FormatStringHandler &H, PrintfSpecifier &FS, 37efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek const char *Start, const char *&Beg, const char *E, 38efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek unsigned *argIndex) { 39efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek if (argIndex) { 40efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek FS.setPrecision(ParseNonPositionAmount(Beg, E, *argIndex)); 41efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek } 42efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek else { 43efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek const OptionalAmount Amt = ParsePositionAmount(H, Start, Beg, E, 44826a3457f737f1fc45a22954fd1bfde38160c165Ted Kremenek analyze_format_string::PrecisionPos); 45efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek if (Amt.isInvalid()) 46efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek return true; 47efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek FS.setPrecision(Amt); 48efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek } 49efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek return false; 50efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek} 51efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek 52826a3457f737f1fc45a22954fd1bfde38160c165Ted Kremenekstatic PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H, 5374d56a168966ff015824279a24aaf566180ed97dTed Kremenek const char *&Beg, 547f70dc85d5055c19c8003f43a59135de211ad1b9Ted Kremenek const char *E, 557f70dc85d5055c19c8003f43a59135de211ad1b9Ted Kremenek unsigned &argIndex) { 564e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek 574b220fae2f525fda39685ddfa7759950db1185e2Ted Kremenek using namespace clang::analyze_printf; 584e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek 598f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek const char *I = Beg; 60c7ae51a3cd9460db8280e8623c90614f246e46d2Ted Kremenek const char *Start = 0; 618f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek UpdateOnReturn <const char*> UpdateBeg(Beg, I); 628f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek 638f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek // Look for a '%' character that indicates the start of a format specifier. 64e729acbba75903f42e79e72e46cdebe3f4c35521Ted Kremenek for ( ; I != E ; ++I) { 658f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek char c = *I; 668f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek if (c == '\0') { 678f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek // Detect spurious null characters, which are likely errors. 688f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek H.HandleNullChar(I); 698f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek return true; 708f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek } 718f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek if (c == '%') { 72e729acbba75903f42e79e72e46cdebe3f4c35521Ted Kremenek Start = I++; // Record the start of the format specifier. 738f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek break; 748f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek } 758f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek } 764e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek 778f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek // No format specifier found? 788f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek if (!Start) 798f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek return false; 804e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek 818f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek if (I == E) { 828f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek // No more characters left? 83826a3457f737f1fc45a22954fd1bfde38160c165Ted Kremenek H.HandleIncompleteSpecifier(Start, E - Start); 848f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek return true; 858f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek } 864e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek 87826a3457f737f1fc45a22954fd1bfde38160c165Ted Kremenek PrintfSpecifier FS; 88efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek if (ParseArgPosition(H, FS, Start, I, E)) 89efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek return true; 90efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek 91efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek if (I == E) { 92efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek // No more characters left? 93826a3457f737f1fc45a22954fd1bfde38160c165Ted Kremenek H.HandleIncompleteSpecifier(Start, E - Start); 94efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek return true; 95efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek } 964e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek 978f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek // Look for flags (if any). 988f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek bool hasMore = true; 998f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek for ( ; I != E; ++I) { 1008f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek switch (*I) { 1018f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek default: hasMore = false; break; 102e4ee9663168dfb2b4122c768091e30217328c9faTom Care case '-': FS.setIsLeftJustified(I); break; 103e4ee9663168dfb2b4122c768091e30217328c9faTom Care case '+': FS.setHasPlusPrefix(I); break; 104e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ' ': FS.setHasSpacePrefix(I); break; 105e4ee9663168dfb2b4122c768091e30217328c9faTom Care case '#': FS.setHasAlternativeForm(I); break; 106e4ee9663168dfb2b4122c768091e30217328c9faTom Care case '0': FS.setHasLeadingZeros(I); break; 1078f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek } 1088f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek if (!hasMore) 1098f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek break; 1104e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek } 1118f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek 1128f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek if (I == E) { 1138f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek // No more characters left? 114826a3457f737f1fc45a22954fd1bfde38160c165Ted Kremenek H.HandleIncompleteSpecifier(Start, E - Start); 1158f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek return true; 1168f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek } 1174e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek 1188f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek // Look for the field width (if any). 119efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek if (ParseFieldWidth(H, FS, Start, I, E, 120efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek FS.usesPositionalArg() ? 0 : &argIndex)) 121efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek return true; 1224e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek 1238f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek if (I == E) { 1248f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek // No more characters left? 125826a3457f737f1fc45a22954fd1bfde38160c165Ted Kremenek H.HandleIncompleteSpecifier(Start, E - Start); 1268f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek return true; 1274e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek } 1284e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek 1294e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek // Look for the precision (if any). 1308f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek if (*I == '.') { 131808015a18bd97781ce437831a95a92fdfc8d5136Ted Kremenek ++I; 1328f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek if (I == E) { 133826a3457f737f1fc45a22954fd1bfde38160c165Ted Kremenek H.HandleIncompleteSpecifier(Start, E - Start); 1348f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek return true; 1358f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek } 1364e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek 137efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek if (ParsePrecision(H, FS, Start, I, E, 138efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek FS.usesPositionalArg() ? 0 : &argIndex)) 139efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek return true; 1408f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek 1418f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek if (I == E) { 1428f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek // No more characters left? 143826a3457f737f1fc45a22954fd1bfde38160c165Ted Kremenek H.HandleIncompleteSpecifier(Start, E - Start); 1448f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek return true; 1458f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek } 1468f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek } 1478f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek 1488f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek // Look for the length modifier. 149826a3457f737f1fc45a22954fd1bfde38160c165Ted Kremenek if (ParseLengthModifier(FS, I, E) && I == E) { 1508f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek // No more characters left? 151826a3457f737f1fc45a22954fd1bfde38160c165Ted Kremenek H.HandleIncompleteSpecifier(Start, E - Start); 1528f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek return true; 1538f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek } 154df17f9d95ba03ba41d8d39ccb688a4eb2ee00e9aTed Kremenek 1554dcb18ff9d92c66c78077ac5cae4b83af37292e4Ted Kremenek if (*I == '\0') { 156df17f9d95ba03ba41d8d39ccb688a4eb2ee00e9aTed Kremenek // Detect spurious null characters, which are likely errors. 157df17f9d95ba03ba41d8d39ccb688a4eb2ee00e9aTed Kremenek H.HandleNullChar(I); 158df17f9d95ba03ba41d8d39ccb688a4eb2ee00e9aTed Kremenek return true; 1594dcb18ff9d92c66c78077ac5cae4b83af37292e4Ted Kremenek } 1604e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek 1618f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek // Finally, look for the conversion specifier. 162a8d8fec7876666d90bb2a144d3b832b2d89a088aTed Kremenek const char *conversionPosition = I++; 16326ac2e07b46bfb4d4f00752c96481c0a98c79c69Ted Kremenek ConversionSpecifier::Kind k = ConversionSpecifier::InvalidSpecifier; 164a8d8fec7876666d90bb2a144d3b832b2d89a088aTed Kremenek switch (*conversionPosition) { 1658f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek default: 16626ac2e07b46bfb4d4f00752c96481c0a98c79c69Ted Kremenek break; 167c7cbb9bf8e0bf8c3191ef0b782ec198c433d2a4eTed Kremenek // C99: 7.19.6.1 (section 8). 16887260c7eabf88eb2009ba2ba20150cd897483241Ted Kremenek case '%': k = ConversionSpecifier::PercentArg; break; 16987260c7eabf88eb2009ba2ba20150cd897483241Ted Kremenek case 'A': k = ConversionSpecifier::AArg; break; 170a8d8fec7876666d90bb2a144d3b832b2d89a088aTed Kremenek case 'E': k = ConversionSpecifier::EArg; break; 17187260c7eabf88eb2009ba2ba20150cd897483241Ted Kremenek case 'F': k = ConversionSpecifier::FArg; break; 172a8d8fec7876666d90bb2a144d3b832b2d89a088aTed Kremenek case 'G': k = ConversionSpecifier::GArg; break; 17387260c7eabf88eb2009ba2ba20150cd897483241Ted Kremenek case 'X': k = ConversionSpecifier::XArg; break; 174a8d8fec7876666d90bb2a144d3b832b2d89a088aTed Kremenek case 'a': k = ConversionSpecifier::aArg; break; 175a8d8fec7876666d90bb2a144d3b832b2d89a088aTed Kremenek case 'c': k = ConversionSpecifier::IntAsCharArg; break; 17687260c7eabf88eb2009ba2ba20150cd897483241Ted Kremenek case 'd': k = ConversionSpecifier::dArg; break; 17787260c7eabf88eb2009ba2ba20150cd897483241Ted Kremenek case 'e': k = ConversionSpecifier::eArg; break; 17887260c7eabf88eb2009ba2ba20150cd897483241Ted Kremenek case 'f': k = ConversionSpecifier::fArg; break; 17987260c7eabf88eb2009ba2ba20150cd897483241Ted Kremenek case 'g': k = ConversionSpecifier::gArg; break; 18087260c7eabf88eb2009ba2ba20150cd897483241Ted Kremenek case 'i': k = ConversionSpecifier::iArg; break; 181a8d8fec7876666d90bb2a144d3b832b2d89a088aTed Kremenek case 'n': k = ConversionSpecifier::OutIntPtrArg; break; 18287260c7eabf88eb2009ba2ba20150cd897483241Ted Kremenek case 'o': k = ConversionSpecifier::oArg; break; 18387260c7eabf88eb2009ba2ba20150cd897483241Ted Kremenek case 'p': k = ConversionSpecifier::VoidPtrArg; break; 18487260c7eabf88eb2009ba2ba20150cd897483241Ted Kremenek case 's': k = ConversionSpecifier::CStrArg; break; 18587260c7eabf88eb2009ba2ba20150cd897483241Ted Kremenek case 'u': k = ConversionSpecifier::uArg; break; 18687260c7eabf88eb2009ba2ba20150cd897483241Ted Kremenek case 'x': k = ConversionSpecifier::xArg; break; 18787260c7eabf88eb2009ba2ba20150cd897483241Ted Kremenek // Mac OS X (unicode) specific 18887260c7eabf88eb2009ba2ba20150cd897483241Ted Kremenek case 'C': k = ConversionSpecifier::CArg; break; 18987260c7eabf88eb2009ba2ba20150cd897483241Ted Kremenek case 'S': k = ConversionSpecifier::UnicodeStrArg; break; 190c7cbb9bf8e0bf8c3191ef0b782ec198c433d2a4eTed Kremenek // Objective-C. 1914dcb18ff9d92c66c78077ac5cae4b83af37292e4Ted Kremenek case '@': k = ConversionSpecifier::ObjCObjArg; break; 192df17f9d95ba03ba41d8d39ccb688a4eb2ee00e9aTed Kremenek // Glibc specific. 1934dcb18ff9d92c66c78077ac5cae4b83af37292e4Ted Kremenek case 'm': k = ConversionSpecifier::PrintErrno; break; 1948f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek } 1957f70dc85d5055c19c8003f43a59135de211ad1b9Ted Kremenek ConversionSpecifier CS(conversionPosition, k); 1967f70dc85d5055c19c8003f43a59135de211ad1b9Ted Kremenek FS.setConversionSpecifier(CS); 197efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek if (CS.consumesDataArgument() && !FS.usesPositionalArg()) 1987f70dc85d5055c19c8003f43a59135de211ad1b9Ted Kremenek FS.setArgIndex(argIndex++); 19926ac2e07b46bfb4d4f00752c96481c0a98c79c69Ted Kremenek 20026ac2e07b46bfb4d4f00752c96481c0a98c79c69Ted Kremenek if (k == ConversionSpecifier::InvalidSpecifier) { 2017f70dc85d5055c19c8003f43a59135de211ad1b9Ted Kremenek // Assume the conversion takes one argument. 202826a3457f737f1fc45a22954fd1bfde38160c165Ted Kremenek return !H.HandleInvalidPrintfConversionSpecifier(FS, Beg, I - Beg); 20326ac2e07b46bfb4d4f00752c96481c0a98c79c69Ted Kremenek } 204826a3457f737f1fc45a22954fd1bfde38160c165Ted Kremenek return PrintfSpecifierResult(Start, FS); 2058f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek} 2068f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek 207826a3457f737f1fc45a22954fd1bfde38160c165Ted Kremenekbool clang::analyze_format_string::ParsePrintfString(FormatStringHandler &H, 208826a3457f737f1fc45a22954fd1bfde38160c165Ted Kremenek const char *I, 209826a3457f737f1fc45a22954fd1bfde38160c165Ted Kremenek const char *E) { 2107f70dc85d5055c19c8003f43a59135de211ad1b9Ted Kremenek 2117f70dc85d5055c19c8003f43a59135de211ad1b9Ted Kremenek unsigned argIndex = 0; 2127f70dc85d5055c19c8003f43a59135de211ad1b9Ted Kremenek 2138f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek // Keep looking for a format specifier until we have exhausted the string. 2148f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek while (I != E) { 215826a3457f737f1fc45a22954fd1bfde38160c165Ted Kremenek const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(H, I, E, argIndex); 21626ac2e07b46bfb4d4f00752c96481c0a98c79c69Ted Kremenek // Did a fail-stop error of any kind occur when parsing the specifier? 21726ac2e07b46bfb4d4f00752c96481c0a98c79c69Ted Kremenek // If so, don't do any more processing. 21826ac2e07b46bfb4d4f00752c96481c0a98c79c69Ted Kremenek if (FSR.shouldStop()) 2198f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek return true;; 22026ac2e07b46bfb4d4f00752c96481c0a98c79c69Ted Kremenek // Did we exhaust the string or encounter an error that 22126ac2e07b46bfb4d4f00752c96481c0a98c79c69Ted Kremenek // we can recover from? 2228f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek if (!FSR.hasValue()) 22326ac2e07b46bfb4d4f00752c96481c0a98c79c69Ted Kremenek continue; 2248f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek // We have a format specifier. Pass it to the callback. 225826a3457f737f1fc45a22954fd1bfde38160c165Ted Kremenek if (!H.HandlePrintfSpecifier(FSR.getValue(), FSR.getStart(), 226a8d8fec7876666d90bb2a144d3b832b2d89a088aTed Kremenek I - FSR.getStart())) 2274dcb18ff9d92c66c78077ac5cae4b83af37292e4Ted Kremenek return true; 2284e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek } 2294e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek assert(I == E && "Format string not exhausted"); 2308f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek return false; 2318f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek} 2328f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek 2334e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek//===----------------------------------------------------------------------===// 2343bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care// Methods on ConversionSpecifier. 2353bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care//===----------------------------------------------------------------------===// 2363bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Careconst char *ConversionSpecifier::toString() const { 2373bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care switch (kind) { 2383bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care case dArg: return "d"; 2393bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care case iArg: return "i"; 2403bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care case oArg: return "o"; 2413bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care case uArg: return "u"; 2423bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care case xArg: return "x"; 2433bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care case XArg: return "X"; 2443bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care case fArg: return "f"; 2453bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care case FArg: return "F"; 2463bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care case eArg: return "e"; 2473bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care case EArg: return "E"; 2483bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care case gArg: return "g"; 2493bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care case GArg: return "G"; 2503bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care case aArg: return "a"; 2513bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care case AArg: return "A"; 2523bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care case IntAsCharArg: return "c"; 2533bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care case CStrArg: return "s"; 2543bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care case VoidPtrArg: return "p"; 2553bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care case OutIntPtrArg: return "n"; 2563bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care case PercentArg: return "%"; 2573bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care case InvalidSpecifier: return NULL; 2583bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care 2593bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care // MacOS X unicode extensions. 2603bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care case CArg: return "C"; 2613bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care case UnicodeStrArg: return "S"; 2623bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care 2633bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care // Objective-C specific specifiers. 2643bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care case ObjCObjArg: return "@"; 2653bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care 2663bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care // GlibC specific specifiers. 2673bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care case PrintErrno: return "m"; 2683bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care } 2693bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care return NULL; 2703bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care} 2713bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care 2723bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care//===----------------------------------------------------------------------===// 273826a3457f737f1fc45a22954fd1bfde38160c165Ted Kremenek// Methods on PrintfSpecifier. 27433567d2feb3e52fac6e0b46d5b3d137fc8467fb0Ted Kremenek//===----------------------------------------------------------------------===// 27533567d2feb3e52fac6e0b46d5b3d137fc8467fb0Ted Kremenek 276826a3457f737f1fc45a22954fd1bfde38160c165Ted KremenekArgTypeResult PrintfSpecifier::getArgType(ASTContext &Ctx) const { 27733567d2feb3e52fac6e0b46d5b3d137fc8467fb0Ted Kremenek if (!CS.consumesDataArgument()) 27833567d2feb3e52fac6e0b46d5b3d137fc8467fb0Ted Kremenek return ArgTypeResult::Invalid(); 2794e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek 28033567d2feb3e52fac6e0b46d5b3d137fc8467fb0Ted Kremenek if (CS.isIntArg()) 2813bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care switch (LM.getKind()) { 2823bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care case LengthModifier::AsLongDouble: 28333567d2feb3e52fac6e0b46d5b3d137fc8467fb0Ted Kremenek return ArgTypeResult::Invalid(); 2843bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care case LengthModifier::None: return Ctx.IntTy; 2853bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care case LengthModifier::AsChar: return Ctx.SignedCharTy; 2863bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care case LengthModifier::AsShort: return Ctx.ShortTy; 2873bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care case LengthModifier::AsLong: return Ctx.LongTy; 2883bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care case LengthModifier::AsLongLong: return Ctx.LongLongTy; 2893bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care case LengthModifier::AsIntMax: 29033567d2feb3e52fac6e0b46d5b3d137fc8467fb0Ted Kremenek // FIXME: Return unknown for now. 29133567d2feb3e52fac6e0b46d5b3d137fc8467fb0Ted Kremenek return ArgTypeResult(); 2923bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care case LengthModifier::AsSizeT: return Ctx.getSizeType(); 2933bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care case LengthModifier::AsPtrDiff: return Ctx.getPointerDiffType(); 29433567d2feb3e52fac6e0b46d5b3d137fc8467fb0Ted Kremenek } 29533567d2feb3e52fac6e0b46d5b3d137fc8467fb0Ted Kremenek 29633567d2feb3e52fac6e0b46d5b3d137fc8467fb0Ted Kremenek if (CS.isUIntArg()) 2973bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care switch (LM.getKind()) { 2983bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care case LengthModifier::AsLongDouble: 29933567d2feb3e52fac6e0b46d5b3d137fc8467fb0Ted Kremenek return ArgTypeResult::Invalid(); 3003bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care case LengthModifier::None: return Ctx.UnsignedIntTy; 3013bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care case LengthModifier::AsChar: return Ctx.UnsignedCharTy; 3023bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care case LengthModifier::AsShort: return Ctx.UnsignedShortTy; 3033bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care case LengthModifier::AsLong: return Ctx.UnsignedLongTy; 3043bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care case LengthModifier::AsLongLong: return Ctx.UnsignedLongLongTy; 3053bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care case LengthModifier::AsIntMax: 30633567d2feb3e52fac6e0b46d5b3d137fc8467fb0Ted Kremenek // FIXME: Return unknown for now. 30733567d2feb3e52fac6e0b46d5b3d137fc8467fb0Ted Kremenek return ArgTypeResult(); 3083bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care case LengthModifier::AsSizeT: 30933567d2feb3e52fac6e0b46d5b3d137fc8467fb0Ted Kremenek // FIXME: How to get the corresponding unsigned 31033567d2feb3e52fac6e0b46d5b3d137fc8467fb0Ted Kremenek // version of size_t? 31133567d2feb3e52fac6e0b46d5b3d137fc8467fb0Ted Kremenek return ArgTypeResult(); 3123bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care case LengthModifier::AsPtrDiff: 31333567d2feb3e52fac6e0b46d5b3d137fc8467fb0Ted Kremenek // FIXME: How to get the corresponding unsigned 31433567d2feb3e52fac6e0b46d5b3d137fc8467fb0Ted Kremenek // version of ptrdiff_t? 31533567d2feb3e52fac6e0b46d5b3d137fc8467fb0Ted Kremenek return ArgTypeResult(); 31633567d2feb3e52fac6e0b46d5b3d137fc8467fb0Ted Kremenek } 3174e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek 318f911eba72e6d7275e5cfdb79ab23fb2aa9cc01d0Ted Kremenek if (CS.isDoubleArg()) { 3193bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care if (LM.getKind() == LengthModifier::AsLongDouble) 320f911eba72e6d7275e5cfdb79ab23fb2aa9cc01d0Ted Kremenek return Ctx.LongDoubleTy; 321c9a89fec60a20eb3269caa95eca048d45ab215adTed Kremenek return Ctx.DoubleTy; 322f911eba72e6d7275e5cfdb79ab23fb2aa9cc01d0Ted Kremenek } 3237f70dc85d5055c19c8003f43a59135de211ad1b9Ted Kremenek 32487260c7eabf88eb2009ba2ba20150cd897483241Ted Kremenek switch (CS.getKind()) { 32587260c7eabf88eb2009ba2ba20150cd897483241Ted Kremenek case ConversionSpecifier::CStrArg: 3263bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care return ArgTypeResult(LM.getKind() == LengthModifier::AsWideChar ? 3273bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care ArgTypeResult::WCStrTy : ArgTypeResult::CStrTy); 32887260c7eabf88eb2009ba2ba20150cd897483241Ted Kremenek case ConversionSpecifier::UnicodeStrArg: 32987260c7eabf88eb2009ba2ba20150cd897483241Ted Kremenek // FIXME: This appears to be Mac OS X specific. 33087260c7eabf88eb2009ba2ba20150cd897483241Ted Kremenek return ArgTypeResult::WCStrTy; 33187260c7eabf88eb2009ba2ba20150cd897483241Ted Kremenek case ConversionSpecifier::CArg: 3327f70dc85d5055c19c8003f43a59135de211ad1b9Ted Kremenek return Ctx.WCharTy; 33313927a431dd733336cfd664bf0840747a71b0a43Ted Kremenek case ConversionSpecifier::VoidPtrArg: 33413927a431dd733336cfd664bf0840747a71b0a43Ted Kremenek return ArgTypeResult::CPointerTy; 33587260c7eabf88eb2009ba2ba20150cd897483241Ted Kremenek default: 33687260c7eabf88eb2009ba2ba20150cd897483241Ted Kremenek break; 33787260c7eabf88eb2009ba2ba20150cd897483241Ted Kremenek } 3387f70dc85d5055c19c8003f43a59135de211ad1b9Ted Kremenek 33933567d2feb3e52fac6e0b46d5b3d137fc8467fb0Ted Kremenek // FIXME: Handle other cases. 34040888ada6022cfd4ab2a7c07ab276639860ffc5aTed Kremenek return ArgTypeResult(); 34133567d2feb3e52fac6e0b46d5b3d137fc8467fb0Ted Kremenek} 34233567d2feb3e52fac6e0b46d5b3d137fc8467fb0Ted Kremenek 343826a3457f737f1fc45a22954fd1bfde38160c165Ted Kremenekbool PrintfSpecifier::fixType(QualType QT) { 3443bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care // Handle strings first (char *, wchar_t *) 3453bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care if (QT->isPointerType() && (QT->getPointeeType()->isAnyCharacterType())) { 3463bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care CS.setKind(ConversionSpecifier::CStrArg); 3473bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care 348876e994957472eda4b40136d4e1d6e08e2be338fTom Care // Disable irrelevant flags 349876e994957472eda4b40136d4e1d6e08e2be338fTom Care HasAlternativeForm = 0; 350876e994957472eda4b40136d4e1d6e08e2be338fTom Care HasLeadingZeroes = 0; 351876e994957472eda4b40136d4e1d6e08e2be338fTom Care 3523bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care // Set the long length modifier for wide characters 3533bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care if (QT->getPointeeType()->isWideCharType()) 3543bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care LM.setKind(LengthModifier::AsWideChar); 3553bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care 3563bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care return true; 3573bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care } 3583bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care 3593bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care // We can only work with builtin types. 3603bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care if (!QT->isBuiltinType()) 3613bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care return false; 3623bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care 3633bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care // Everything else should be a base type 3643bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care const BuiltinType *BT = QT->getAs<BuiltinType>(); 365876e994957472eda4b40136d4e1d6e08e2be338fTom Care 3663bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care // Set length modifier 3673bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care switch (BT->getKind()) { 3683bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care default: 369876e994957472eda4b40136d4e1d6e08e2be338fTom Care // The rest of the conversions are either optional or for non-builtin types 370876e994957472eda4b40136d4e1d6e08e2be338fTom Care LM.setKind(LengthModifier::None); 3713bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care break; 372876e994957472eda4b40136d4e1d6e08e2be338fTom Care 3733bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care case BuiltinType::WChar: 3743bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care case BuiltinType::Long: 3753bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care case BuiltinType::ULong: 3763bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care LM.setKind(LengthModifier::AsLong); 3773bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care break; 3783bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care 3793bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care case BuiltinType::LongLong: 3803bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care case BuiltinType::ULongLong: 3813bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care LM.setKind(LengthModifier::AsLongLong); 3823bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care break; 3833bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care 3843bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care case BuiltinType::LongDouble: 3853bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care LM.setKind(LengthModifier::AsLongDouble); 3863bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care break; 3873bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care } 3883bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care 3893bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care // Set conversion specifier and disable any flags which do not apply to it. 3903bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care if (QT->isAnyCharacterType()) { 3913bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care CS.setKind(ConversionSpecifier::IntAsCharArg); 3923bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care Precision.setHowSpecified(OptionalAmount::NotSpecified); 3933bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care HasAlternativeForm = 0; 3943bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care HasLeadingZeroes = 0; 395e4ee9663168dfb2b4122c768091e30217328c9faTom Care HasPlusPrefix = 0; 3963bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care } 3973bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care // Test for Floating type first as LongDouble can pass isUnsignedIntegerType 3980c293ea13d452c1a47a05ada5a5ee9acc69c66ccDouglas Gregor else if (QT->isRealFloatingType()) { 3993bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care CS.setKind(ConversionSpecifier::fArg); 4003bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care } 4013bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care else if (QT->isPointerType()) { 4023bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care CS.setKind(ConversionSpecifier::VoidPtrArg); 4033bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care Precision.setHowSpecified(OptionalAmount::NotSpecified); 4043bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care HasAlternativeForm = 0; 4053bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care HasLeadingZeroes = 0; 406e4ee9663168dfb2b4122c768091e30217328c9faTom Care HasPlusPrefix = 0; 4073bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care } 4083bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care else if (QT->isSignedIntegerType()) { 4093bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care CS.setKind(ConversionSpecifier::dArg); 4103bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care HasAlternativeForm = 0; 4113bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care } 412c8c4b4088cf0b3afeda425b25fa7c77d3873b12cDouglas Gregor else if (QT->isUnsignedIntegerType()) { 4133bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care CS.setKind(ConversionSpecifier::uArg); 4143bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care HasAlternativeForm = 0; 415e4ee9663168dfb2b4122c768091e30217328c9faTom Care HasPlusPrefix = 0; 4163bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care } 4173bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care else { 4183bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care return false; 4193bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care } 4203bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care 4213bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care return true; 4223bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care} 4233bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care 424826a3457f737f1fc45a22954fd1bfde38160c165Ted Kremenekvoid PrintfSpecifier::toString(llvm::raw_ostream &os) const { 4253bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care // Whilst some features have no defined order, we are using the order 426826a3457f737f1fc45a22954fd1bfde38160c165Ted Kremenek // appearing in the C99 standard (ISO/IEC 9899:1999 (E) ¤7.19.6.1) 4273bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care os << "%"; 4283bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care 4293bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care // Positional args 4303bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care if (usesPositionalArg()) { 4313bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care os << getPositionalArgIndex() << "$"; 4323bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care } 4333bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care 4343bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care // Conversion flags 4353bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care if (IsLeftJustified) os << "-"; 4363bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care if (HasPlusPrefix) os << "+"; 4373bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care if (HasSpacePrefix) os << " "; 4383bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care if (HasAlternativeForm) os << "#"; 4393bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care if (HasLeadingZeroes) os << "0"; 4403bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care 4413bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care // Minimum field width 4423bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care FieldWidth.toString(os); 4433bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care // Precision 4443bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care Precision.toString(os); 4453bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care // Length modifier 4463bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care os << LM.toString(); 4473bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care // Conversion specifier 4483bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care os << CS.toString(); 4493bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care} 450e4ee9663168dfb2b4122c768091e30217328c9faTom Care 451826a3457f737f1fc45a22954fd1bfde38160c165Ted Kremenekbool PrintfSpecifier::hasValidPlusPrefix() const { 452e4ee9663168dfb2b4122c768091e30217328c9faTom Care if (!HasPlusPrefix) 453e4ee9663168dfb2b4122c768091e30217328c9faTom Care return true; 454e4ee9663168dfb2b4122c768091e30217328c9faTom Care 455e4ee9663168dfb2b4122c768091e30217328c9faTom Care // The plus prefix only makes sense for signed conversions 456e4ee9663168dfb2b4122c768091e30217328c9faTom Care switch (CS.getKind()) { 457e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::dArg: 458e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::iArg: 459e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::fArg: 460e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::FArg: 461e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::eArg: 462e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::EArg: 463e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::gArg: 464e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::GArg: 465e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::aArg: 466e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::AArg: 467e4ee9663168dfb2b4122c768091e30217328c9faTom Care return true; 468e4ee9663168dfb2b4122c768091e30217328c9faTom Care 469e4ee9663168dfb2b4122c768091e30217328c9faTom Care default: 470e4ee9663168dfb2b4122c768091e30217328c9faTom Care return false; 471e4ee9663168dfb2b4122c768091e30217328c9faTom Care } 472e4ee9663168dfb2b4122c768091e30217328c9faTom Care} 473e4ee9663168dfb2b4122c768091e30217328c9faTom Care 474826a3457f737f1fc45a22954fd1bfde38160c165Ted Kremenekbool PrintfSpecifier::hasValidAlternativeForm() const { 475e4ee9663168dfb2b4122c768091e30217328c9faTom Care if (!HasAlternativeForm) 476e4ee9663168dfb2b4122c768091e30217328c9faTom Care return true; 477e4ee9663168dfb2b4122c768091e30217328c9faTom Care 478e4ee9663168dfb2b4122c768091e30217328c9faTom Care // Alternate form flag only valid with the oxaAeEfFgG conversions 479e4ee9663168dfb2b4122c768091e30217328c9faTom Care switch (CS.getKind()) { 480e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::oArg: 481e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::xArg: 482e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::aArg: 483e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::AArg: 484e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::eArg: 485e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::EArg: 486e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::fArg: 487e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::FArg: 488e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::gArg: 489e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::GArg: 490e4ee9663168dfb2b4122c768091e30217328c9faTom Care return true; 491e4ee9663168dfb2b4122c768091e30217328c9faTom Care 492e4ee9663168dfb2b4122c768091e30217328c9faTom Care default: 493e4ee9663168dfb2b4122c768091e30217328c9faTom Care return false; 494e4ee9663168dfb2b4122c768091e30217328c9faTom Care } 495e4ee9663168dfb2b4122c768091e30217328c9faTom Care} 496e4ee9663168dfb2b4122c768091e30217328c9faTom Care 497826a3457f737f1fc45a22954fd1bfde38160c165Ted Kremenekbool PrintfSpecifier::hasValidLeadingZeros() const { 498e4ee9663168dfb2b4122c768091e30217328c9faTom Care if (!HasLeadingZeroes) 499e4ee9663168dfb2b4122c768091e30217328c9faTom Care return true; 500e4ee9663168dfb2b4122c768091e30217328c9faTom Care 501e4ee9663168dfb2b4122c768091e30217328c9faTom Care // Leading zeroes flag only valid with the diouxXaAeEfFgG conversions 502e4ee9663168dfb2b4122c768091e30217328c9faTom Care switch (CS.getKind()) { 503e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::dArg: 504e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::iArg: 505e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::oArg: 506e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::uArg: 507e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::xArg: 508e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::XArg: 509e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::aArg: 510e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::AArg: 511e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::eArg: 512e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::EArg: 513e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::fArg: 514e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::FArg: 515e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::gArg: 516e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::GArg: 517e4ee9663168dfb2b4122c768091e30217328c9faTom Care return true; 518e4ee9663168dfb2b4122c768091e30217328c9faTom Care 519e4ee9663168dfb2b4122c768091e30217328c9faTom Care default: 520e4ee9663168dfb2b4122c768091e30217328c9faTom Care return false; 521e4ee9663168dfb2b4122c768091e30217328c9faTom Care } 522e4ee9663168dfb2b4122c768091e30217328c9faTom Care} 523e4ee9663168dfb2b4122c768091e30217328c9faTom Care 524826a3457f737f1fc45a22954fd1bfde38160c165Ted Kremenekbool PrintfSpecifier::hasValidSpacePrefix() const { 525e4ee9663168dfb2b4122c768091e30217328c9faTom Care if (!HasSpacePrefix) 526e4ee9663168dfb2b4122c768091e30217328c9faTom Care return true; 527e4ee9663168dfb2b4122c768091e30217328c9faTom Care 528e4ee9663168dfb2b4122c768091e30217328c9faTom Care // The space prefix only makes sense for signed conversions 529e4ee9663168dfb2b4122c768091e30217328c9faTom Care switch (CS.getKind()) { 530e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::dArg: 531e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::iArg: 532e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::fArg: 533e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::FArg: 534e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::eArg: 535e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::EArg: 536e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::gArg: 537e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::GArg: 538e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::aArg: 539e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::AArg: 540e4ee9663168dfb2b4122c768091e30217328c9faTom Care return true; 541e4ee9663168dfb2b4122c768091e30217328c9faTom Care 542e4ee9663168dfb2b4122c768091e30217328c9faTom Care default: 543e4ee9663168dfb2b4122c768091e30217328c9faTom Care return false; 544e4ee9663168dfb2b4122c768091e30217328c9faTom Care } 545e4ee9663168dfb2b4122c768091e30217328c9faTom Care} 546e4ee9663168dfb2b4122c768091e30217328c9faTom Care 547826a3457f737f1fc45a22954fd1bfde38160c165Ted Kremenekbool PrintfSpecifier::hasValidLeftJustified() const { 548e4ee9663168dfb2b4122c768091e30217328c9faTom Care if (!IsLeftJustified) 549e4ee9663168dfb2b4122c768091e30217328c9faTom Care return true; 550e4ee9663168dfb2b4122c768091e30217328c9faTom Care 551e4ee9663168dfb2b4122c768091e30217328c9faTom Care // The left justified flag is valid for all conversions except n 552e4ee9663168dfb2b4122c768091e30217328c9faTom Care switch (CS.getKind()) { 553e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::OutIntPtrArg: 554e4ee9663168dfb2b4122c768091e30217328c9faTom Care return false; 555e4ee9663168dfb2b4122c768091e30217328c9faTom Care 556e4ee9663168dfb2b4122c768091e30217328c9faTom Care default: 557e4ee9663168dfb2b4122c768091e30217328c9faTom Care return true; 558e4ee9663168dfb2b4122c768091e30217328c9faTom Care } 559e4ee9663168dfb2b4122c768091e30217328c9faTom Care} 560e4ee9663168dfb2b4122c768091e30217328c9faTom Care 561826a3457f737f1fc45a22954fd1bfde38160c165Ted Kremenekbool PrintfSpecifier::hasValidLengthModifier() const { 562e4ee9663168dfb2b4122c768091e30217328c9faTom Care switch (LM.getKind()) { 563e4ee9663168dfb2b4122c768091e30217328c9faTom Care case LengthModifier::None: 564e4ee9663168dfb2b4122c768091e30217328c9faTom Care return true; 565e4ee9663168dfb2b4122c768091e30217328c9faTom Care 566e4ee9663168dfb2b4122c768091e30217328c9faTom Care // Handle most integer flags 567e4ee9663168dfb2b4122c768091e30217328c9faTom Care case LengthModifier::AsChar: 568e4ee9663168dfb2b4122c768091e30217328c9faTom Care case LengthModifier::AsShort: 569e4ee9663168dfb2b4122c768091e30217328c9faTom Care case LengthModifier::AsLongLong: 570e4ee9663168dfb2b4122c768091e30217328c9faTom Care case LengthModifier::AsIntMax: 571e4ee9663168dfb2b4122c768091e30217328c9faTom Care case LengthModifier::AsSizeT: 572e4ee9663168dfb2b4122c768091e30217328c9faTom Care case LengthModifier::AsPtrDiff: 573e4ee9663168dfb2b4122c768091e30217328c9faTom Care switch (CS.getKind()) { 574e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::dArg: 575e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::iArg: 576e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::oArg: 577e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::uArg: 578e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::xArg: 579e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::XArg: 580e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::OutIntPtrArg: 581e4ee9663168dfb2b4122c768091e30217328c9faTom Care return true; 582e4ee9663168dfb2b4122c768091e30217328c9faTom Care default: 583e4ee9663168dfb2b4122c768091e30217328c9faTom Care return false; 584e4ee9663168dfb2b4122c768091e30217328c9faTom Care } 585e4ee9663168dfb2b4122c768091e30217328c9faTom Care 586e4ee9663168dfb2b4122c768091e30217328c9faTom Care // Handle 'l' flag 587e4ee9663168dfb2b4122c768091e30217328c9faTom Care case LengthModifier::AsLong: 588e4ee9663168dfb2b4122c768091e30217328c9faTom Care switch (CS.getKind()) { 589e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::dArg: 590e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::iArg: 591e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::oArg: 592e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::uArg: 593e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::xArg: 594e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::XArg: 595e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::aArg: 596e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::AArg: 597e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::fArg: 598e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::FArg: 599e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::eArg: 600e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::EArg: 601e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::gArg: 602e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::GArg: 603e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::OutIntPtrArg: 604e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::IntAsCharArg: 605e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::CStrArg: 606e4ee9663168dfb2b4122c768091e30217328c9faTom Care return true; 607e4ee9663168dfb2b4122c768091e30217328c9faTom Care default: 608e4ee9663168dfb2b4122c768091e30217328c9faTom Care return false; 609e4ee9663168dfb2b4122c768091e30217328c9faTom Care } 610e4ee9663168dfb2b4122c768091e30217328c9faTom Care 611e4ee9663168dfb2b4122c768091e30217328c9faTom Care case LengthModifier::AsLongDouble: 612e4ee9663168dfb2b4122c768091e30217328c9faTom Care switch (CS.getKind()) { 613e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::aArg: 614e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::AArg: 615e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::fArg: 616e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::FArg: 617e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::eArg: 618e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::EArg: 619e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::gArg: 620e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::GArg: 621e4ee9663168dfb2b4122c768091e30217328c9faTom Care return true; 622e4ee9663168dfb2b4122c768091e30217328c9faTom Care default: 623e4ee9663168dfb2b4122c768091e30217328c9faTom Care return false; 624e4ee9663168dfb2b4122c768091e30217328c9faTom Care } 625e4ee9663168dfb2b4122c768091e30217328c9faTom Care } 626e4ee9663168dfb2b4122c768091e30217328c9faTom Care return false; 627e4ee9663168dfb2b4122c768091e30217328c9faTom Care} 628e4ee9663168dfb2b4122c768091e30217328c9faTom Care 629826a3457f737f1fc45a22954fd1bfde38160c165Ted Kremenekbool PrintfSpecifier::hasValidPrecision() const { 630e4ee9663168dfb2b4122c768091e30217328c9faTom Care if (Precision.getHowSpecified() == OptionalAmount::NotSpecified) 631e4ee9663168dfb2b4122c768091e30217328c9faTom Care return true; 632e4ee9663168dfb2b4122c768091e30217328c9faTom Care 633e4ee9663168dfb2b4122c768091e30217328c9faTom Care // Precision is only valid with the diouxXaAeEfFgGs conversions 634e4ee9663168dfb2b4122c768091e30217328c9faTom Care switch (CS.getKind()) { 635e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::dArg: 636e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::iArg: 637e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::oArg: 638e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::uArg: 639e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::xArg: 640e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::XArg: 641e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::aArg: 642e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::AArg: 643e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::eArg: 644e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::EArg: 645e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::fArg: 646e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::FArg: 647e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::gArg: 648e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::GArg: 649e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::CStrArg: 650e4ee9663168dfb2b4122c768091e30217328c9faTom Care return true; 651e4ee9663168dfb2b4122c768091e30217328c9faTom Care 652e4ee9663168dfb2b4122c768091e30217328c9faTom Care default: 653e4ee9663168dfb2b4122c768091e30217328c9faTom Care return false; 654e4ee9663168dfb2b4122c768091e30217328c9faTom Care } 655e4ee9663168dfb2b4122c768091e30217328c9faTom Care} 656826a3457f737f1fc45a22954fd1bfde38160c165Ted Kremenekbool PrintfSpecifier::hasValidFieldWidth() const { 657e4ee9663168dfb2b4122c768091e30217328c9faTom Care if (FieldWidth.getHowSpecified() == OptionalAmount::NotSpecified) 658e4ee9663168dfb2b4122c768091e30217328c9faTom Care return true; 659e4ee9663168dfb2b4122c768091e30217328c9faTom Care 660e4ee9663168dfb2b4122c768091e30217328c9faTom Care // The field width is valid for all conversions except n 661e4ee9663168dfb2b4122c768091e30217328c9faTom Care switch (CS.getKind()) { 662e4ee9663168dfb2b4122c768091e30217328c9faTom Care case ConversionSpecifier::OutIntPtrArg: 663e4ee9663168dfb2b4122c768091e30217328c9faTom Care return false; 664e4ee9663168dfb2b4122c768091e30217328c9faTom Care 665e4ee9663168dfb2b4122c768091e30217328c9faTom Care default: 666e4ee9663168dfb2b4122c768091e30217328c9faTom Care return true; 667e4ee9663168dfb2b4122c768091e30217328c9faTom Care } 668e4ee9663168dfb2b4122c768091e30217328c9faTom Care} 669