1314fbfa1STim Northover //== PrintfFormatString.cpp - Analysis of printf format strings --*- C++ -*-==// 2314fbfa1STim Northover // 32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information. 52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6314fbfa1STim Northover // 7314fbfa1STim Northover //===----------------------------------------------------------------------===// 8314fbfa1STim Northover // 9314fbfa1STim Northover // Handling of format string in printf and friends. The structure of format 10314fbfa1STim Northover // strings for fprintf() are described in C99 7.19.6.1. 11314fbfa1STim Northover // 12314fbfa1STim Northover //===----------------------------------------------------------------------===// 13314fbfa1STim Northover 147314aea5SDaniel Kiss #include "FormatStringParsing.h" 15314fbfa1STim Northover #include "clang/AST/FormatString.h" 16314fbfa1STim Northover #include "clang/AST/OSLog.h" 17314fbfa1STim Northover #include "clang/Basic/TargetInfo.h" 187314aea5SDaniel Kiss #include "llvm/Support/Regex.h" 19314fbfa1STim Northover 20314fbfa1STim Northover using clang::analyze_format_string::ArgType; 21314fbfa1STim Northover using clang::analyze_format_string::FormatStringHandler; 22314fbfa1STim Northover using clang::analyze_format_string::LengthModifier; 23314fbfa1STim Northover using clang::analyze_format_string::OptionalAmount; 24314fbfa1STim Northover using clang::analyze_format_string::ConversionSpecifier; 25314fbfa1STim Northover using clang::analyze_printf::PrintfSpecifier; 26314fbfa1STim Northover 27314fbfa1STim Northover using namespace clang; 28314fbfa1STim Northover 29314fbfa1STim Northover typedef clang::analyze_format_string::SpecifierResult<PrintfSpecifier> 30314fbfa1STim Northover PrintfSpecifierResult; 31314fbfa1STim Northover 32314fbfa1STim Northover //===----------------------------------------------------------------------===// 33314fbfa1STim Northover // Methods for parsing format strings. 34314fbfa1STim Northover //===----------------------------------------------------------------------===// 35314fbfa1STim Northover 36314fbfa1STim Northover using analyze_format_string::ParseNonPositionAmount; 37314fbfa1STim Northover 38314fbfa1STim Northover static bool ParsePrecision(FormatStringHandler &H, PrintfSpecifier &FS, 39314fbfa1STim Northover const char *Start, const char *&Beg, const char *E, 40314fbfa1STim Northover unsigned *argIndex) { 41314fbfa1STim Northover if (argIndex) { 42314fbfa1STim Northover FS.setPrecision(ParseNonPositionAmount(Beg, E, *argIndex)); 43314fbfa1STim Northover } else { 44314fbfa1STim Northover const OptionalAmount Amt = ParsePositionAmount(H, Start, Beg, E, 45314fbfa1STim Northover analyze_format_string::PrecisionPos); 46314fbfa1STim Northover if (Amt.isInvalid()) 47314fbfa1STim Northover return true; 48314fbfa1STim Northover FS.setPrecision(Amt); 49314fbfa1STim Northover } 50314fbfa1STim Northover return false; 51314fbfa1STim Northover } 52314fbfa1STim Northover 53314fbfa1STim Northover static bool ParseObjCFlags(FormatStringHandler &H, PrintfSpecifier &FS, 54314fbfa1STim Northover const char *FlagBeg, const char *E, bool Warn) { 55314fbfa1STim Northover StringRef Flag(FlagBeg, E - FlagBeg); 56314fbfa1STim Northover // Currently there is only one flag. 57314fbfa1STim Northover if (Flag == "tt") { 58314fbfa1STim Northover FS.setHasObjCTechnicalTerm(FlagBeg); 59314fbfa1STim Northover return false; 60314fbfa1STim Northover } 61314fbfa1STim Northover // Handle either the case of no flag or an invalid flag. 62314fbfa1STim Northover if (Warn) { 63314fbfa1STim Northover if (Flag == "") 64314fbfa1STim Northover H.HandleEmptyObjCModifierFlag(FlagBeg, E - FlagBeg); 65314fbfa1STim Northover else 66314fbfa1STim Northover H.HandleInvalidObjCModifierFlag(FlagBeg, E - FlagBeg); 67314fbfa1STim Northover } 68314fbfa1STim Northover return true; 69314fbfa1STim Northover } 70314fbfa1STim Northover 71314fbfa1STim Northover static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H, 72314fbfa1STim Northover const char *&Beg, 73314fbfa1STim Northover const char *E, 74314fbfa1STim Northover unsigned &argIndex, 75314fbfa1STim Northover const LangOptions &LO, 76314fbfa1STim Northover const TargetInfo &Target, 77314fbfa1STim Northover bool Warn, 78314fbfa1STim Northover bool isFreeBSDKPrintf) { 79314fbfa1STim Northover 80314fbfa1STim Northover using namespace clang::analyze_format_string; 81314fbfa1STim Northover using namespace clang::analyze_printf; 82314fbfa1STim Northover 83314fbfa1STim Northover const char *I = Beg; 84314fbfa1STim Northover const char *Start = nullptr; 85314fbfa1STim Northover UpdateOnReturn <const char*> UpdateBeg(Beg, I); 86314fbfa1STim Northover 87314fbfa1STim Northover // Look for a '%' character that indicates the start of a format specifier. 88314fbfa1STim Northover for ( ; I != E ; ++I) { 89314fbfa1STim Northover char c = *I; 90314fbfa1STim Northover if (c == '\0') { 91314fbfa1STim Northover // Detect spurious null characters, which are likely errors. 92314fbfa1STim Northover H.HandleNullChar(I); 93314fbfa1STim Northover return true; 94314fbfa1STim Northover } 95314fbfa1STim Northover if (c == '%') { 96314fbfa1STim Northover Start = I++; // Record the start of the format specifier. 97314fbfa1STim Northover break; 98314fbfa1STim Northover } 99314fbfa1STim Northover } 100314fbfa1STim Northover 101314fbfa1STim Northover // No format specifier found? 102314fbfa1STim Northover if (!Start) 103314fbfa1STim Northover return false; 104314fbfa1STim Northover 105314fbfa1STim Northover if (I == E) { 106314fbfa1STim Northover // No more characters left? 107314fbfa1STim Northover if (Warn) 108314fbfa1STim Northover H.HandleIncompleteSpecifier(Start, E - Start); 109314fbfa1STim Northover return true; 110314fbfa1STim Northover } 111314fbfa1STim Northover 112314fbfa1STim Northover PrintfSpecifier FS; 113314fbfa1STim Northover if (ParseArgPosition(H, FS, Start, I, E)) 114314fbfa1STim Northover return true; 115314fbfa1STim Northover 116314fbfa1STim Northover if (I == E) { 117314fbfa1STim Northover // No more characters left? 118314fbfa1STim Northover if (Warn) 119314fbfa1STim Northover H.HandleIncompleteSpecifier(Start, E - Start); 120314fbfa1STim Northover return true; 121314fbfa1STim Northover } 122314fbfa1STim Northover 123314fbfa1STim Northover if (*I == '{') { 124314fbfa1STim Northover ++I; 125314fbfa1STim Northover unsigned char PrivacyFlags = 0; 126314fbfa1STim Northover StringRef MatchedStr; 127314fbfa1STim Northover 128314fbfa1STim Northover do { 129314fbfa1STim Northover StringRef Str(I, E - I); 130d572cf49SAkira Hatanaka std::string Match = "^[[:space:]]*" 131d572cf49SAkira Hatanaka "(private|public|sensitive|mask\\.[^[:space:],}]*)" 132fb1e4465SAkira Hatanaka "[[:space:]]*(,|})"; 133314fbfa1STim Northover llvm::Regex R(Match); 134314fbfa1STim Northover SmallVector<StringRef, 2> Matches; 135314fbfa1STim Northover 136314fbfa1STim Northover if (R.match(Str, &Matches)) { 137314fbfa1STim Northover MatchedStr = Matches[1]; 138314fbfa1STim Northover I += Matches[0].size(); 139314fbfa1STim Northover 140314fbfa1STim Northover // Set the privacy flag if the privacy annotation in the 141314fbfa1STim Northover // comma-delimited segment is at least as strict as the privacy 142314fbfa1STim Northover // annotations in previous comma-delimited segments. 143d572cf49SAkira Hatanaka if (MatchedStr.startswith("mask")) { 144d572cf49SAkira Hatanaka StringRef MaskType = MatchedStr.substr(sizeof("mask.") - 1); 145d572cf49SAkira Hatanaka unsigned Size = MaskType.size(); 146d572cf49SAkira Hatanaka if (Warn && (Size == 0 || Size > 8)) 147d572cf49SAkira Hatanaka H.handleInvalidMaskType(MaskType); 148d572cf49SAkira Hatanaka FS.setMaskType(MaskType); 149d572cf49SAkira Hatanaka } else if (MatchedStr.equals("sensitive")) 150fb1e4465SAkira Hatanaka PrivacyFlags = clang::analyze_os_log::OSLogBufferItem::IsSensitive; 151fb1e4465SAkira Hatanaka else if (PrivacyFlags != 152fb1e4465SAkira Hatanaka clang::analyze_os_log::OSLogBufferItem::IsSensitive && 153fb1e4465SAkira Hatanaka MatchedStr.equals("private")) 154314fbfa1STim Northover PrivacyFlags = clang::analyze_os_log::OSLogBufferItem::IsPrivate; 155314fbfa1STim Northover else if (PrivacyFlags == 0 && MatchedStr.equals("public")) 156314fbfa1STim Northover PrivacyFlags = clang::analyze_os_log::OSLogBufferItem::IsPublic; 157314fbfa1STim Northover } else { 158314fbfa1STim Northover size_t CommaOrBracePos = 159314fbfa1STim Northover Str.find_if([](char c) { return c == ',' || c == '}'; }); 160314fbfa1STim Northover 161314fbfa1STim Northover if (CommaOrBracePos == StringRef::npos) { 162314fbfa1STim Northover // Neither a comma nor the closing brace was found. 163314fbfa1STim Northover if (Warn) 164314fbfa1STim Northover H.HandleIncompleteSpecifier(Start, E - Start); 165314fbfa1STim Northover return true; 166314fbfa1STim Northover } 167314fbfa1STim Northover 168314fbfa1STim Northover I += CommaOrBracePos + 1; 169314fbfa1STim Northover } 170314fbfa1STim Northover // Continue until the closing brace is found. 171314fbfa1STim Northover } while (*(I - 1) == ','); 172314fbfa1STim Northover 173314fbfa1STim Northover // Set the privacy flag. 174314fbfa1STim Northover switch (PrivacyFlags) { 175314fbfa1STim Northover case 0: 176314fbfa1STim Northover break; 177314fbfa1STim Northover case clang::analyze_os_log::OSLogBufferItem::IsPrivate: 178314fbfa1STim Northover FS.setIsPrivate(MatchedStr.data()); 179314fbfa1STim Northover break; 180314fbfa1STim Northover case clang::analyze_os_log::OSLogBufferItem::IsPublic: 181314fbfa1STim Northover FS.setIsPublic(MatchedStr.data()); 182314fbfa1STim Northover break; 183fb1e4465SAkira Hatanaka case clang::analyze_os_log::OSLogBufferItem::IsSensitive: 184fb1e4465SAkira Hatanaka FS.setIsSensitive(MatchedStr.data()); 185fb1e4465SAkira Hatanaka break; 186314fbfa1STim Northover default: 187314fbfa1STim Northover llvm_unreachable("Unexpected privacy flag value"); 188314fbfa1STim Northover } 189314fbfa1STim Northover } 190314fbfa1STim Northover 191314fbfa1STim Northover // Look for flags (if any). 192314fbfa1STim Northover bool hasMore = true; 193314fbfa1STim Northover for ( ; I != E; ++I) { 194314fbfa1STim Northover switch (*I) { 195314fbfa1STim Northover default: hasMore = false; break; 196314fbfa1STim Northover case '\'': 197314fbfa1STim Northover // FIXME: POSIX specific. Always accept? 198314fbfa1STim Northover FS.setHasThousandsGrouping(I); 199314fbfa1STim Northover break; 200314fbfa1STim Northover case '-': FS.setIsLeftJustified(I); break; 201314fbfa1STim Northover case '+': FS.setHasPlusPrefix(I); break; 202314fbfa1STim Northover case ' ': FS.setHasSpacePrefix(I); break; 203314fbfa1STim Northover case '#': FS.setHasAlternativeForm(I); break; 204314fbfa1STim Northover case '0': FS.setHasLeadingZeros(I); break; 205314fbfa1STim Northover } 206314fbfa1STim Northover if (!hasMore) 207314fbfa1STim Northover break; 208314fbfa1STim Northover } 209314fbfa1STim Northover 210314fbfa1STim Northover if (I == E) { 211314fbfa1STim Northover // No more characters left? 212314fbfa1STim Northover if (Warn) 213314fbfa1STim Northover H.HandleIncompleteSpecifier(Start, E - Start); 214314fbfa1STim Northover return true; 215314fbfa1STim Northover } 216314fbfa1STim Northover 217314fbfa1STim Northover // Look for the field width (if any). 218314fbfa1STim Northover if (ParseFieldWidth(H, FS, Start, I, E, 219314fbfa1STim Northover FS.usesPositionalArg() ? nullptr : &argIndex)) 220314fbfa1STim Northover return true; 221314fbfa1STim Northover 222314fbfa1STim Northover if (I == E) { 223314fbfa1STim Northover // No more characters left? 224314fbfa1STim Northover if (Warn) 225314fbfa1STim Northover H.HandleIncompleteSpecifier(Start, E - Start); 226314fbfa1STim Northover return true; 227314fbfa1STim Northover } 228314fbfa1STim Northover 229314fbfa1STim Northover // Look for the precision (if any). 230314fbfa1STim Northover if (*I == '.') { 231314fbfa1STim Northover ++I; 232314fbfa1STim Northover if (I == E) { 233314fbfa1STim Northover if (Warn) 234314fbfa1STim Northover H.HandleIncompleteSpecifier(Start, E - Start); 235314fbfa1STim Northover return true; 236314fbfa1STim Northover } 237314fbfa1STim Northover 238314fbfa1STim Northover if (ParsePrecision(H, FS, Start, I, E, 239314fbfa1STim Northover FS.usesPositionalArg() ? nullptr : &argIndex)) 240314fbfa1STim Northover return true; 241314fbfa1STim Northover 242314fbfa1STim Northover if (I == E) { 243314fbfa1STim Northover // No more characters left? 244314fbfa1STim Northover if (Warn) 245314fbfa1STim Northover H.HandleIncompleteSpecifier(Start, E - Start); 246314fbfa1STim Northover return true; 247314fbfa1STim Northover } 248314fbfa1STim Northover } 249314fbfa1STim Northover 2500ff50d49SMatt Arsenault if (ParseVectorModifier(H, FS, I, E, LO)) 2510ff50d49SMatt Arsenault return true; 2520ff50d49SMatt Arsenault 253314fbfa1STim Northover // Look for the length modifier. 254314fbfa1STim Northover if (ParseLengthModifier(FS, I, E, LO) && I == E) { 255314fbfa1STim Northover // No more characters left? 256314fbfa1STim Northover if (Warn) 257314fbfa1STim Northover H.HandleIncompleteSpecifier(Start, E - Start); 258314fbfa1STim Northover return true; 259314fbfa1STim Northover } 260314fbfa1STim Northover 261314fbfa1STim Northover // Look for the Objective-C modifier flags, if any. 262314fbfa1STim Northover // We parse these here, even if they don't apply to 263314fbfa1STim Northover // the conversion specifier, and then emit an error 264314fbfa1STim Northover // later if the conversion specifier isn't '@'. This 265314fbfa1STim Northover // enables better recovery, and we don't know if 266314fbfa1STim Northover // these flags are applicable until later. 267314fbfa1STim Northover const char *ObjCModifierFlagsStart = nullptr, 268314fbfa1STim Northover *ObjCModifierFlagsEnd = nullptr; 269314fbfa1STim Northover if (*I == '[') { 270314fbfa1STim Northover ObjCModifierFlagsStart = I; 271314fbfa1STim Northover ++I; 272314fbfa1STim Northover auto flagStart = I; 273314fbfa1STim Northover for (;; ++I) { 274314fbfa1STim Northover ObjCModifierFlagsEnd = I; 275314fbfa1STim Northover if (I == E) { 276314fbfa1STim Northover if (Warn) 277314fbfa1STim Northover H.HandleIncompleteSpecifier(Start, E - Start); 278314fbfa1STim Northover return true; 279314fbfa1STim Northover } 280314fbfa1STim Northover // Did we find the closing ']'? 281314fbfa1STim Northover if (*I == ']') { 282314fbfa1STim Northover if (ParseObjCFlags(H, FS, flagStart, I, Warn)) 283314fbfa1STim Northover return true; 284314fbfa1STim Northover ++I; 285314fbfa1STim Northover break; 286314fbfa1STim Northover } 287314fbfa1STim Northover // There are no separators defined yet for multiple 288314fbfa1STim Northover // Objective-C modifier flags. When those are 289314fbfa1STim Northover // defined, this is the place to check. 290314fbfa1STim Northover } 291314fbfa1STim Northover } 292314fbfa1STim Northover 293314fbfa1STim Northover if (*I == '\0') { 294314fbfa1STim Northover // Detect spurious null characters, which are likely errors. 295314fbfa1STim Northover H.HandleNullChar(I); 296314fbfa1STim Northover return true; 297314fbfa1STim Northover } 298314fbfa1STim Northover 299314fbfa1STim Northover // Finally, look for the conversion specifier. 300314fbfa1STim Northover const char *conversionPosition = I++; 301314fbfa1STim Northover ConversionSpecifier::Kind k = ConversionSpecifier::InvalidSpecifier; 302314fbfa1STim Northover switch (*conversionPosition) { 303314fbfa1STim Northover default: 304314fbfa1STim Northover break; 305314fbfa1STim Northover // C99: 7.19.6.1 (section 8). 306314fbfa1STim Northover case '%': k = ConversionSpecifier::PercentArg; break; 307314fbfa1STim Northover case 'A': k = ConversionSpecifier::AArg; break; 308314fbfa1STim Northover case 'E': k = ConversionSpecifier::EArg; break; 309314fbfa1STim Northover case 'F': k = ConversionSpecifier::FArg; break; 310314fbfa1STim Northover case 'G': k = ConversionSpecifier::GArg; break; 311314fbfa1STim Northover case 'X': k = ConversionSpecifier::XArg; break; 312314fbfa1STim Northover case 'a': k = ConversionSpecifier::aArg; break; 313314fbfa1STim Northover case 'c': k = ConversionSpecifier::cArg; break; 314314fbfa1STim Northover case 'd': k = ConversionSpecifier::dArg; break; 315314fbfa1STim Northover case 'e': k = ConversionSpecifier::eArg; break; 316314fbfa1STim Northover case 'f': k = ConversionSpecifier::fArg; break; 317314fbfa1STim Northover case 'g': k = ConversionSpecifier::gArg; break; 318314fbfa1STim Northover case 'i': k = ConversionSpecifier::iArg; break; 31958fc8082SMatt Arsenault case 'n': 32058fc8082SMatt Arsenault // Not handled, but reserved in OpenCL. 32158fc8082SMatt Arsenault if (!LO.OpenCL) 32258fc8082SMatt Arsenault k = ConversionSpecifier::nArg; 32358fc8082SMatt Arsenault break; 324314fbfa1STim Northover case 'o': k = ConversionSpecifier::oArg; break; 325314fbfa1STim Northover case 'p': k = ConversionSpecifier::pArg; break; 326314fbfa1STim Northover case 's': k = ConversionSpecifier::sArg; break; 327314fbfa1STim Northover case 'u': k = ConversionSpecifier::uArg; break; 328314fbfa1STim Northover case 'x': k = ConversionSpecifier::xArg; break; 329314fbfa1STim Northover // POSIX specific. 330314fbfa1STim Northover case 'C': k = ConversionSpecifier::CArg; break; 331314fbfa1STim Northover case 'S': k = ConversionSpecifier::SArg; break; 332314fbfa1STim Northover // Apple extension for os_log 333314fbfa1STim Northover case 'P': 334314fbfa1STim Northover k = ConversionSpecifier::PArg; 335314fbfa1STim Northover break; 336314fbfa1STim Northover // Objective-C. 337314fbfa1STim Northover case '@': k = ConversionSpecifier::ObjCObjArg; break; 338314fbfa1STim Northover // Glibc specific. 339314fbfa1STim Northover case 'm': k = ConversionSpecifier::PrintErrno; break; 340314fbfa1STim Northover // FreeBSD kernel specific. 341314fbfa1STim Northover case 'b': 342314fbfa1STim Northover if (isFreeBSDKPrintf) 343314fbfa1STim Northover k = ConversionSpecifier::FreeBSDbArg; // int followed by char * 344314fbfa1STim Northover break; 345314fbfa1STim Northover case 'r': 346314fbfa1STim Northover if (isFreeBSDKPrintf) 347314fbfa1STim Northover k = ConversionSpecifier::FreeBSDrArg; // int 348314fbfa1STim Northover break; 349314fbfa1STim Northover case 'y': 350314fbfa1STim Northover if (isFreeBSDKPrintf) 351314fbfa1STim Northover k = ConversionSpecifier::FreeBSDyArg; // int 352314fbfa1STim Northover break; 353314fbfa1STim Northover // Apple-specific. 354314fbfa1STim Northover case 'D': 355314fbfa1STim Northover if (isFreeBSDKPrintf) 356314fbfa1STim Northover k = ConversionSpecifier::FreeBSDDArg; // void * followed by char * 357314fbfa1STim Northover else if (Target.getTriple().isOSDarwin()) 358314fbfa1STim Northover k = ConversionSpecifier::DArg; 359314fbfa1STim Northover break; 360314fbfa1STim Northover case 'O': 361314fbfa1STim Northover if (Target.getTriple().isOSDarwin()) 362314fbfa1STim Northover k = ConversionSpecifier::OArg; 363314fbfa1STim Northover break; 364314fbfa1STim Northover case 'U': 365314fbfa1STim Northover if (Target.getTriple().isOSDarwin()) 366314fbfa1STim Northover k = ConversionSpecifier::UArg; 367314fbfa1STim Northover break; 368314fbfa1STim Northover // MS specific. 369314fbfa1STim Northover case 'Z': 370314fbfa1STim Northover if (Target.getTriple().isOSMSVCRT()) 371314fbfa1STim Northover k = ConversionSpecifier::ZArg; 372e19dc613SMatt Arsenault break; 373314fbfa1STim Northover } 374314fbfa1STim Northover 375314fbfa1STim Northover // Check to see if we used the Objective-C modifier flags with 376314fbfa1STim Northover // a conversion specifier other than '@'. 377314fbfa1STim Northover if (k != ConversionSpecifier::ObjCObjArg && 378314fbfa1STim Northover k != ConversionSpecifier::InvalidSpecifier && 379314fbfa1STim Northover ObjCModifierFlagsStart) { 380314fbfa1STim Northover H.HandleObjCFlagsWithNonObjCConversion(ObjCModifierFlagsStart, 381314fbfa1STim Northover ObjCModifierFlagsEnd + 1, 382314fbfa1STim Northover conversionPosition); 383314fbfa1STim Northover return true; 384314fbfa1STim Northover } 385314fbfa1STim Northover 386314fbfa1STim Northover PrintfConversionSpecifier CS(conversionPosition, k); 387314fbfa1STim Northover FS.setConversionSpecifier(CS); 388314fbfa1STim Northover if (CS.consumesDataArgument() && !FS.usesPositionalArg()) 389314fbfa1STim Northover FS.setArgIndex(argIndex++); 390314fbfa1STim Northover // FreeBSD kernel specific. 391314fbfa1STim Northover if (k == ConversionSpecifier::FreeBSDbArg || 392314fbfa1STim Northover k == ConversionSpecifier::FreeBSDDArg) 393314fbfa1STim Northover argIndex++; 394314fbfa1STim Northover 395314fbfa1STim Northover if (k == ConversionSpecifier::InvalidSpecifier) { 396314fbfa1STim Northover unsigned Len = I - Start; 397314fbfa1STim Northover if (ParseUTF8InvalidSpecifier(Start, E, Len)) { 398314fbfa1STim Northover CS.setEndScanList(Start + Len); 399314fbfa1STim Northover FS.setConversionSpecifier(CS); 400314fbfa1STim Northover } 401314fbfa1STim Northover // Assume the conversion takes one argument. 402314fbfa1STim Northover return !H.HandleInvalidPrintfConversionSpecifier(FS, Start, Len); 403314fbfa1STim Northover } 404314fbfa1STim Northover return PrintfSpecifierResult(Start, FS); 405314fbfa1STim Northover } 406314fbfa1STim Northover 407314fbfa1STim Northover bool clang::analyze_format_string::ParsePrintfString(FormatStringHandler &H, 408314fbfa1STim Northover const char *I, 409314fbfa1STim Northover const char *E, 410314fbfa1STim Northover const LangOptions &LO, 411314fbfa1STim Northover const TargetInfo &Target, 412314fbfa1STim Northover bool isFreeBSDKPrintf) { 413314fbfa1STim Northover 414314fbfa1STim Northover unsigned argIndex = 0; 415314fbfa1STim Northover 416314fbfa1STim Northover // Keep looking for a format specifier until we have exhausted the string. 417314fbfa1STim Northover while (I != E) { 418314fbfa1STim Northover const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(H, I, E, argIndex, 419314fbfa1STim Northover LO, Target, true, 420314fbfa1STim Northover isFreeBSDKPrintf); 421314fbfa1STim Northover // Did a fail-stop error of any kind occur when parsing the specifier? 422314fbfa1STim Northover // If so, don't do any more processing. 423314fbfa1STim Northover if (FSR.shouldStop()) 424314fbfa1STim Northover return true; 425314fbfa1STim Northover // Did we exhaust the string or encounter an error that 426314fbfa1STim Northover // we can recover from? 427314fbfa1STim Northover if (!FSR.hasValue()) 428314fbfa1STim Northover continue; 429314fbfa1STim Northover // We have a format specifier. Pass it to the callback. 430314fbfa1STim Northover if (!H.HandlePrintfSpecifier(FSR.getValue(), FSR.getStart(), 431*cd4e600fSAlex Brachet I - FSR.getStart(), Target)) 432314fbfa1STim Northover return true; 433314fbfa1STim Northover } 434314fbfa1STim Northover assert(I == E && "Format string not exhausted"); 435314fbfa1STim Northover return false; 436314fbfa1STim Northover } 437314fbfa1STim Northover 438314fbfa1STim Northover bool clang::analyze_format_string::ParseFormatStringHasSArg(const char *I, 439314fbfa1STim Northover const char *E, 440314fbfa1STim Northover const LangOptions &LO, 441314fbfa1STim Northover const TargetInfo &Target) { 442314fbfa1STim Northover 443314fbfa1STim Northover unsigned argIndex = 0; 444314fbfa1STim Northover 445314fbfa1STim Northover // Keep looking for a %s format specifier until we have exhausted the string. 446314fbfa1STim Northover FormatStringHandler H; 447314fbfa1STim Northover while (I != E) { 448314fbfa1STim Northover const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(H, I, E, argIndex, 449314fbfa1STim Northover LO, Target, false, 450314fbfa1STim Northover false); 451314fbfa1STim Northover // Did a fail-stop error of any kind occur when parsing the specifier? 452314fbfa1STim Northover // If so, don't do any more processing. 453314fbfa1STim Northover if (FSR.shouldStop()) 454314fbfa1STim Northover return false; 455314fbfa1STim Northover // Did we exhaust the string or encounter an error that 456314fbfa1STim Northover // we can recover from? 457314fbfa1STim Northover if (!FSR.hasValue()) 458314fbfa1STim Northover continue; 459314fbfa1STim Northover const analyze_printf::PrintfSpecifier &FS = FSR.getValue(); 460314fbfa1STim Northover // Return true if this a %s format specifier. 461314fbfa1STim Northover if (FS.getConversionSpecifier().getKind() == ConversionSpecifier::Kind::sArg) 462314fbfa1STim Northover return true; 463314fbfa1STim Northover } 464314fbfa1STim Northover return false; 465314fbfa1STim Northover } 466314fbfa1STim Northover 467aa385569SErik Pilkington bool clang::analyze_format_string::parseFormatStringHasFormattingSpecifiers( 468aa385569SErik Pilkington const char *Begin, const char *End, const LangOptions &LO, 469aa385569SErik Pilkington const TargetInfo &Target) { 470aa385569SErik Pilkington unsigned ArgIndex = 0; 471aa385569SErik Pilkington // Keep looking for a formatting specifier until we have exhausted the string. 472aa385569SErik Pilkington FormatStringHandler H; 473aa385569SErik Pilkington while (Begin != End) { 474aa385569SErik Pilkington const PrintfSpecifierResult &FSR = 475aa385569SErik Pilkington ParsePrintfSpecifier(H, Begin, End, ArgIndex, LO, Target, false, false); 476aa385569SErik Pilkington if (FSR.shouldStop()) 477aa385569SErik Pilkington break; 478aa385569SErik Pilkington if (FSR.hasValue()) 479aa385569SErik Pilkington return true; 480aa385569SErik Pilkington } 481aa385569SErik Pilkington return false; 482aa385569SErik Pilkington } 483aa385569SErik Pilkington 484314fbfa1STim Northover //===----------------------------------------------------------------------===// 485314fbfa1STim Northover // Methods on PrintfSpecifier. 486314fbfa1STim Northover //===----------------------------------------------------------------------===// 487314fbfa1STim Northover 4880ff50d49SMatt Arsenault ArgType PrintfSpecifier::getScalarArgType(ASTContext &Ctx, 489314fbfa1STim Northover bool IsObjCLiteral) const { 490314fbfa1STim Northover if (CS.getKind() == ConversionSpecifier::cArg) 491314fbfa1STim Northover switch (LM.getKind()) { 492314fbfa1STim Northover case LengthModifier::None: 493314fbfa1STim Northover return Ctx.IntTy; 494314fbfa1STim Northover case LengthModifier::AsLong: 495314fbfa1STim Northover case LengthModifier::AsWide: 496314fbfa1STim Northover return ArgType(ArgType::WIntTy, "wint_t"); 497314fbfa1STim Northover case LengthModifier::AsShort: 498314fbfa1STim Northover if (Ctx.getTargetInfo().getTriple().isOSMSVCRT()) 499314fbfa1STim Northover return Ctx.IntTy; 500314fbfa1STim Northover LLVM_FALLTHROUGH; 501314fbfa1STim Northover default: 502314fbfa1STim Northover return ArgType::Invalid(); 503314fbfa1STim Northover } 504314fbfa1STim Northover 505314fbfa1STim Northover if (CS.isIntArg()) 506314fbfa1STim Northover switch (LM.getKind()) { 507314fbfa1STim Northover case LengthModifier::AsLongDouble: 508314fbfa1STim Northover // GNU extension. 509314fbfa1STim Northover return Ctx.LongLongTy; 510314fbfa1STim Northover case LengthModifier::None: 51158fc8082SMatt Arsenault case LengthModifier::AsShortLong: 512314fbfa1STim Northover return Ctx.IntTy; 513314fbfa1STim Northover case LengthModifier::AsInt32: 514314fbfa1STim Northover return ArgType(Ctx.IntTy, "__int32"); 51558fc8082SMatt Arsenault case LengthModifier::AsChar: 51658fc8082SMatt Arsenault return ArgType::AnyCharTy; 517314fbfa1STim Northover case LengthModifier::AsShort: return Ctx.ShortTy; 518314fbfa1STim Northover case LengthModifier::AsLong: return Ctx.LongTy; 519314fbfa1STim Northover case LengthModifier::AsLongLong: 520314fbfa1STim Northover case LengthModifier::AsQuad: 521314fbfa1STim Northover return Ctx.LongLongTy; 522314fbfa1STim Northover case LengthModifier::AsInt64: 523314fbfa1STim Northover return ArgType(Ctx.LongLongTy, "__int64"); 524314fbfa1STim Northover case LengthModifier::AsIntMax: 525314fbfa1STim Northover return ArgType(Ctx.getIntMaxType(), "intmax_t"); 526314fbfa1STim Northover case LengthModifier::AsSizeT: 527314fbfa1STim Northover return ArgType::makeSizeT(ArgType(Ctx.getSignedSizeType(), "ssize_t")); 528314fbfa1STim Northover case LengthModifier::AsInt3264: 529314fbfa1STim Northover return Ctx.getTargetInfo().getTriple().isArch64Bit() 530314fbfa1STim Northover ? ArgType(Ctx.LongLongTy, "__int64") 531314fbfa1STim Northover : ArgType(Ctx.IntTy, "__int32"); 532314fbfa1STim Northover case LengthModifier::AsPtrDiff: 533314fbfa1STim Northover return ArgType::makePtrdiffT( 534314fbfa1STim Northover ArgType(Ctx.getPointerDiffType(), "ptrdiff_t")); 535314fbfa1STim Northover case LengthModifier::AsAllocate: 536314fbfa1STim Northover case LengthModifier::AsMAllocate: 537314fbfa1STim Northover case LengthModifier::AsWide: 538314fbfa1STim Northover return ArgType::Invalid(); 539314fbfa1STim Northover } 540314fbfa1STim Northover 541314fbfa1STim Northover if (CS.isUIntArg()) 542314fbfa1STim Northover switch (LM.getKind()) { 543314fbfa1STim Northover case LengthModifier::AsLongDouble: 544314fbfa1STim Northover // GNU extension. 545314fbfa1STim Northover return Ctx.UnsignedLongLongTy; 546314fbfa1STim Northover case LengthModifier::None: 54758fc8082SMatt Arsenault case LengthModifier::AsShortLong: 548314fbfa1STim Northover return Ctx.UnsignedIntTy; 549314fbfa1STim Northover case LengthModifier::AsInt32: 550314fbfa1STim Northover return ArgType(Ctx.UnsignedIntTy, "unsigned __int32"); 551314fbfa1STim Northover case LengthModifier::AsChar: return Ctx.UnsignedCharTy; 552314fbfa1STim Northover case LengthModifier::AsShort: return Ctx.UnsignedShortTy; 553314fbfa1STim Northover case LengthModifier::AsLong: return Ctx.UnsignedLongTy; 554314fbfa1STim Northover case LengthModifier::AsLongLong: 555314fbfa1STim Northover case LengthModifier::AsQuad: 556314fbfa1STim Northover return Ctx.UnsignedLongLongTy; 557314fbfa1STim Northover case LengthModifier::AsInt64: 558314fbfa1STim Northover return ArgType(Ctx.UnsignedLongLongTy, "unsigned __int64"); 559314fbfa1STim Northover case LengthModifier::AsIntMax: 560314fbfa1STim Northover return ArgType(Ctx.getUIntMaxType(), "uintmax_t"); 561314fbfa1STim Northover case LengthModifier::AsSizeT: 562314fbfa1STim Northover return ArgType::makeSizeT(ArgType(Ctx.getSizeType(), "size_t")); 563314fbfa1STim Northover case LengthModifier::AsInt3264: 564314fbfa1STim Northover return Ctx.getTargetInfo().getTriple().isArch64Bit() 565314fbfa1STim Northover ? ArgType(Ctx.UnsignedLongLongTy, "unsigned __int64") 566314fbfa1STim Northover : ArgType(Ctx.UnsignedIntTy, "unsigned __int32"); 567314fbfa1STim Northover case LengthModifier::AsPtrDiff: 568314fbfa1STim Northover return ArgType::makePtrdiffT( 569314fbfa1STim Northover ArgType(Ctx.getUnsignedPointerDiffType(), "unsigned ptrdiff_t")); 570314fbfa1STim Northover case LengthModifier::AsAllocate: 571314fbfa1STim Northover case LengthModifier::AsMAllocate: 572314fbfa1STim Northover case LengthModifier::AsWide: 573314fbfa1STim Northover return ArgType::Invalid(); 574314fbfa1STim Northover } 575314fbfa1STim Northover 576314fbfa1STim Northover if (CS.isDoubleArg()) { 57758fc8082SMatt Arsenault if (!VectorNumElts.isInvalid()) { 57858fc8082SMatt Arsenault switch (LM.getKind()) { 57958fc8082SMatt Arsenault case LengthModifier::AsShort: 58058fc8082SMatt Arsenault return Ctx.HalfTy; 58158fc8082SMatt Arsenault case LengthModifier::AsShortLong: 58258fc8082SMatt Arsenault return Ctx.FloatTy; 58358fc8082SMatt Arsenault case LengthModifier::AsLong: 58458fc8082SMatt Arsenault default: 58558fc8082SMatt Arsenault return Ctx.DoubleTy; 58658fc8082SMatt Arsenault } 58758fc8082SMatt Arsenault } 58858fc8082SMatt Arsenault 589314fbfa1STim Northover if (LM.getKind() == LengthModifier::AsLongDouble) 590314fbfa1STim Northover return Ctx.LongDoubleTy; 591314fbfa1STim Northover return Ctx.DoubleTy; 592314fbfa1STim Northover } 593314fbfa1STim Northover 594314fbfa1STim Northover if (CS.getKind() == ConversionSpecifier::nArg) { 595314fbfa1STim Northover switch (LM.getKind()) { 596314fbfa1STim Northover case LengthModifier::None: 597314fbfa1STim Northover return ArgType::PtrTo(Ctx.IntTy); 598314fbfa1STim Northover case LengthModifier::AsChar: 599314fbfa1STim Northover return ArgType::PtrTo(Ctx.SignedCharTy); 600314fbfa1STim Northover case LengthModifier::AsShort: 601314fbfa1STim Northover return ArgType::PtrTo(Ctx.ShortTy); 602314fbfa1STim Northover case LengthModifier::AsLong: 603314fbfa1STim Northover return ArgType::PtrTo(Ctx.LongTy); 604314fbfa1STim Northover case LengthModifier::AsLongLong: 605314fbfa1STim Northover case LengthModifier::AsQuad: 606314fbfa1STim Northover return ArgType::PtrTo(Ctx.LongLongTy); 607314fbfa1STim Northover case LengthModifier::AsIntMax: 608314fbfa1STim Northover return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t")); 609314fbfa1STim Northover case LengthModifier::AsSizeT: 610314fbfa1STim Northover return ArgType::PtrTo(ArgType(Ctx.getSignedSizeType(), "ssize_t")); 611314fbfa1STim Northover case LengthModifier::AsPtrDiff: 612314fbfa1STim Northover return ArgType::PtrTo(ArgType(Ctx.getPointerDiffType(), "ptrdiff_t")); 613314fbfa1STim Northover case LengthModifier::AsLongDouble: 614314fbfa1STim Northover return ArgType(); // FIXME: Is this a known extension? 615314fbfa1STim Northover case LengthModifier::AsAllocate: 616314fbfa1STim Northover case LengthModifier::AsMAllocate: 617314fbfa1STim Northover case LengthModifier::AsInt32: 618314fbfa1STim Northover case LengthModifier::AsInt3264: 619314fbfa1STim Northover case LengthModifier::AsInt64: 620314fbfa1STim Northover case LengthModifier::AsWide: 621314fbfa1STim Northover return ArgType::Invalid(); 62258fc8082SMatt Arsenault case LengthModifier::AsShortLong: 62358fc8082SMatt Arsenault llvm_unreachable("only used for OpenCL which doesn not handle nArg"); 624314fbfa1STim Northover } 625314fbfa1STim Northover } 626314fbfa1STim Northover 627314fbfa1STim Northover switch (CS.getKind()) { 628314fbfa1STim Northover case ConversionSpecifier::sArg: 629314fbfa1STim Northover if (LM.getKind() == LengthModifier::AsWideChar) { 630314fbfa1STim Northover if (IsObjCLiteral) 631314fbfa1STim Northover return ArgType(Ctx.getPointerType(Ctx.UnsignedShortTy.withConst()), 632314fbfa1STim Northover "const unichar *"); 633314fbfa1STim Northover return ArgType(ArgType::WCStrTy, "wchar_t *"); 634314fbfa1STim Northover } 635314fbfa1STim Northover if (LM.getKind() == LengthModifier::AsWide) 636314fbfa1STim Northover return ArgType(ArgType::WCStrTy, "wchar_t *"); 637314fbfa1STim Northover return ArgType::CStrTy; 638314fbfa1STim Northover case ConversionSpecifier::SArg: 639314fbfa1STim Northover if (IsObjCLiteral) 640314fbfa1STim Northover return ArgType(Ctx.getPointerType(Ctx.UnsignedShortTy.withConst()), 641314fbfa1STim Northover "const unichar *"); 642314fbfa1STim Northover if (Ctx.getTargetInfo().getTriple().isOSMSVCRT() && 643314fbfa1STim Northover LM.getKind() == LengthModifier::AsShort) 644314fbfa1STim Northover return ArgType::CStrTy; 645314fbfa1STim Northover return ArgType(ArgType::WCStrTy, "wchar_t *"); 646314fbfa1STim Northover case ConversionSpecifier::CArg: 647314fbfa1STim Northover if (IsObjCLiteral) 648314fbfa1STim Northover return ArgType(Ctx.UnsignedShortTy, "unichar"); 649314fbfa1STim Northover if (Ctx.getTargetInfo().getTriple().isOSMSVCRT() && 650314fbfa1STim Northover LM.getKind() == LengthModifier::AsShort) 651314fbfa1STim Northover return Ctx.IntTy; 652314fbfa1STim Northover return ArgType(Ctx.WideCharTy, "wchar_t"); 653314fbfa1STim Northover case ConversionSpecifier::pArg: 654314fbfa1STim Northover case ConversionSpecifier::PArg: 655314fbfa1STim Northover return ArgType::CPointerTy; 656314fbfa1STim Northover case ConversionSpecifier::ObjCObjArg: 657314fbfa1STim Northover return ArgType::ObjCPointerTy; 658314fbfa1STim Northover default: 659314fbfa1STim Northover break; 660314fbfa1STim Northover } 661314fbfa1STim Northover 662314fbfa1STim Northover // FIXME: Handle other cases. 663314fbfa1STim Northover return ArgType(); 664314fbfa1STim Northover } 665314fbfa1STim Northover 6660ff50d49SMatt Arsenault 6670ff50d49SMatt Arsenault ArgType PrintfSpecifier::getArgType(ASTContext &Ctx, 6680ff50d49SMatt Arsenault bool IsObjCLiteral) const { 6690ff50d49SMatt Arsenault const PrintfConversionSpecifier &CS = getConversionSpecifier(); 6700ff50d49SMatt Arsenault 6710ff50d49SMatt Arsenault if (!CS.consumesDataArgument()) 6720ff50d49SMatt Arsenault return ArgType::Invalid(); 6730ff50d49SMatt Arsenault 6740ff50d49SMatt Arsenault ArgType ScalarTy = getScalarArgType(Ctx, IsObjCLiteral); 6750ff50d49SMatt Arsenault if (!ScalarTy.isValid() || VectorNumElts.isInvalid()) 6760ff50d49SMatt Arsenault return ScalarTy; 6770ff50d49SMatt Arsenault 6780ff50d49SMatt Arsenault return ScalarTy.makeVectorType(Ctx, VectorNumElts.getConstantAmount()); 6790ff50d49SMatt Arsenault } 6800ff50d49SMatt Arsenault 681314fbfa1STim Northover bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt, 682314fbfa1STim Northover ASTContext &Ctx, bool IsObjCLiteral) { 683314fbfa1STim Northover // %n is different from other conversion specifiers; don't try to fix it. 684314fbfa1STim Northover if (CS.getKind() == ConversionSpecifier::nArg) 685314fbfa1STim Northover return false; 686314fbfa1STim Northover 687314fbfa1STim Northover // Handle Objective-C objects first. Note that while the '%@' specifier will 688314fbfa1STim Northover // not warn for structure pointer or void pointer arguments (because that's 689314fbfa1STim Northover // how CoreFoundation objects are implemented), we only show a fixit for '%@' 690314fbfa1STim Northover // if we know it's an object (block, id, class, or __attribute__((NSObject))). 691314fbfa1STim Northover if (QT->isObjCRetainableType()) { 692314fbfa1STim Northover if (!IsObjCLiteral) 693314fbfa1STim Northover return false; 694314fbfa1STim Northover 695314fbfa1STim Northover CS.setKind(ConversionSpecifier::ObjCObjArg); 696314fbfa1STim Northover 697314fbfa1STim Northover // Disable irrelevant flags 698314fbfa1STim Northover HasThousandsGrouping = false; 699314fbfa1STim Northover HasPlusPrefix = false; 700314fbfa1STim Northover HasSpacePrefix = false; 701314fbfa1STim Northover HasAlternativeForm = false; 702314fbfa1STim Northover HasLeadingZeroes = false; 703314fbfa1STim Northover Precision.setHowSpecified(OptionalAmount::NotSpecified); 704314fbfa1STim Northover LM.setKind(LengthModifier::None); 705314fbfa1STim Northover 706314fbfa1STim Northover return true; 707314fbfa1STim Northover } 708314fbfa1STim Northover 709314fbfa1STim Northover // Handle strings next (char *, wchar_t *) 710314fbfa1STim Northover if (QT->isPointerType() && (QT->getPointeeType()->isAnyCharacterType())) { 711314fbfa1STim Northover CS.setKind(ConversionSpecifier::sArg); 712314fbfa1STim Northover 713314fbfa1STim Northover // Disable irrelevant flags 71440446663SKazu Hirata HasAlternativeForm = false; 71540446663SKazu Hirata HasLeadingZeroes = false; 716314fbfa1STim Northover 717314fbfa1STim Northover // Set the long length modifier for wide characters 718314fbfa1STim Northover if (QT->getPointeeType()->isWideCharType()) 719314fbfa1STim Northover LM.setKind(LengthModifier::AsWideChar); 720314fbfa1STim Northover else 721314fbfa1STim Northover LM.setKind(LengthModifier::None); 722314fbfa1STim Northover 723314fbfa1STim Northover return true; 724314fbfa1STim Northover } 725314fbfa1STim Northover 726314fbfa1STim Northover // If it's an enum, get its underlying type. 727314fbfa1STim Northover if (const EnumType *ETy = QT->getAs<EnumType>()) 728314fbfa1STim Northover QT = ETy->getDecl()->getIntegerType(); 729314fbfa1STim Northover 730314fbfa1STim Northover const BuiltinType *BT = QT->getAs<BuiltinType>(); 7310ff50d49SMatt Arsenault if (!BT) { 7320ff50d49SMatt Arsenault const VectorType *VT = QT->getAs<VectorType>(); 7330ff50d49SMatt Arsenault if (VT) { 7340ff50d49SMatt Arsenault QT = VT->getElementType(); 7350ff50d49SMatt Arsenault BT = QT->getAs<BuiltinType>(); 7360ff50d49SMatt Arsenault VectorNumElts = OptionalAmount(VT->getNumElements()); 7370ff50d49SMatt Arsenault } 7380ff50d49SMatt Arsenault } 7390ff50d49SMatt Arsenault 7400ff50d49SMatt Arsenault // We can only work with builtin types. 741314fbfa1STim Northover if (!BT) 742314fbfa1STim Northover return false; 743314fbfa1STim Northover 744314fbfa1STim Northover // Set length modifier 745314fbfa1STim Northover switch (BT->getKind()) { 746314fbfa1STim Northover case BuiltinType::Bool: 747314fbfa1STim Northover case BuiltinType::WChar_U: 748314fbfa1STim Northover case BuiltinType::WChar_S: 749314fbfa1STim Northover case BuiltinType::Char8: // FIXME: Treat like 'char'? 750314fbfa1STim Northover case BuiltinType::Char16: 751314fbfa1STim Northover case BuiltinType::Char32: 752314fbfa1STim Northover case BuiltinType::UInt128: 753314fbfa1STim Northover case BuiltinType::Int128: 754314fbfa1STim Northover case BuiltinType::Half: 755ecd682bbSTies Stuij case BuiltinType::BFloat16: 756314fbfa1STim Northover case BuiltinType::Float16: 757314fbfa1STim Northover case BuiltinType::Float128: 758fae0dfa6SQiu Chaofan case BuiltinType::Ibm128: 759314fbfa1STim Northover case BuiltinType::ShortAccum: 760314fbfa1STim Northover case BuiltinType::Accum: 761314fbfa1STim Northover case BuiltinType::LongAccum: 762314fbfa1STim Northover case BuiltinType::UShortAccum: 763314fbfa1STim Northover case BuiltinType::UAccum: 764314fbfa1STim Northover case BuiltinType::ULongAccum: 765314fbfa1STim Northover case BuiltinType::ShortFract: 766314fbfa1STim Northover case BuiltinType::Fract: 767314fbfa1STim Northover case BuiltinType::LongFract: 768314fbfa1STim Northover case BuiltinType::UShortFract: 769314fbfa1STim Northover case BuiltinType::UFract: 770314fbfa1STim Northover case BuiltinType::ULongFract: 771314fbfa1STim Northover case BuiltinType::SatShortAccum: 772314fbfa1STim Northover case BuiltinType::SatAccum: 773314fbfa1STim Northover case BuiltinType::SatLongAccum: 774314fbfa1STim Northover case BuiltinType::SatUShortAccum: 775314fbfa1STim Northover case BuiltinType::SatUAccum: 776314fbfa1STim Northover case BuiltinType::SatULongAccum: 777314fbfa1STim Northover case BuiltinType::SatShortFract: 778314fbfa1STim Northover case BuiltinType::SatFract: 779314fbfa1STim Northover case BuiltinType::SatLongFract: 780314fbfa1STim Northover case BuiltinType::SatUShortFract: 781314fbfa1STim Northover case BuiltinType::SatUFract: 782314fbfa1STim Northover case BuiltinType::SatULongFract: 783314fbfa1STim Northover // Various types which are non-trivial to correct. 784314fbfa1STim Northover return false; 785314fbfa1STim Northover 786314fbfa1STim Northover #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \ 787314fbfa1STim Northover case BuiltinType::Id: 788314fbfa1STim Northover #include "clang/Basic/OpenCLImageTypes.def" 7893fee3518SAndrew Savonichev #define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \ 7903fee3518SAndrew Savonichev case BuiltinType::Id: 7913fee3518SAndrew Savonichev #include "clang/Basic/OpenCLExtensionTypes.def" 792eb485fbcSRichard Sandiford #define SVE_TYPE(Name, Id, SingletonId) \ 793eb485fbcSRichard Sandiford case BuiltinType::Id: 794eb485fbcSRichard Sandiford #include "clang/Basic/AArch64SVEACLETypes.def" 79557d83c3aSBaptiste Saleil #define PPC_VECTOR_TYPE(Name, Id, Size) \ 79640dd4d52SBaptiste Saleil case BuiltinType::Id: 79740dd4d52SBaptiste Saleil #include "clang/Basic/PPCTypes.def" 798766ee109SHsiangkai Wang #define RVV_TYPE(Name, Id, SingletonId) case BuiltinType::Id: 799766ee109SHsiangkai Wang #include "clang/Basic/RISCVVTypes.def" 800314fbfa1STim Northover #define SIGNED_TYPE(Id, SingletonId) 801314fbfa1STim Northover #define UNSIGNED_TYPE(Id, SingletonId) 802314fbfa1STim Northover #define FLOATING_TYPE(Id, SingletonId) 803314fbfa1STim Northover #define BUILTIN_TYPE(Id, SingletonId) \ 804314fbfa1STim Northover case BuiltinType::Id: 805314fbfa1STim Northover #include "clang/AST/BuiltinTypes.def" 806314fbfa1STim Northover // Misc other stuff which doesn't make sense here. 807314fbfa1STim Northover return false; 808314fbfa1STim Northover 809314fbfa1STim Northover case BuiltinType::UInt: 810314fbfa1STim Northover case BuiltinType::Int: 811314fbfa1STim Northover case BuiltinType::Float: 81258fc8082SMatt Arsenault LM.setKind(VectorNumElts.isInvalid() ? 81358fc8082SMatt Arsenault LengthModifier::None : LengthModifier::AsShortLong); 814314fbfa1STim Northover break; 81558fc8082SMatt Arsenault case BuiltinType::Double: 81658fc8082SMatt Arsenault LM.setKind(VectorNumElts.isInvalid() ? 81758fc8082SMatt Arsenault LengthModifier::None : LengthModifier::AsLong); 81858fc8082SMatt Arsenault break; 819314fbfa1STim Northover case BuiltinType::Char_U: 820314fbfa1STim Northover case BuiltinType::UChar: 821314fbfa1STim Northover case BuiltinType::Char_S: 822314fbfa1STim Northover case BuiltinType::SChar: 823314fbfa1STim Northover LM.setKind(LengthModifier::AsChar); 824314fbfa1STim Northover break; 825314fbfa1STim Northover 826314fbfa1STim Northover case BuiltinType::Short: 827314fbfa1STim Northover case BuiltinType::UShort: 828314fbfa1STim Northover LM.setKind(LengthModifier::AsShort); 829314fbfa1STim Northover break; 830314fbfa1STim Northover 831314fbfa1STim Northover case BuiltinType::Long: 832314fbfa1STim Northover case BuiltinType::ULong: 833314fbfa1STim Northover LM.setKind(LengthModifier::AsLong); 834314fbfa1STim Northover break; 835314fbfa1STim Northover 836314fbfa1STim Northover case BuiltinType::LongLong: 837314fbfa1STim Northover case BuiltinType::ULongLong: 838314fbfa1STim Northover LM.setKind(LengthModifier::AsLongLong); 839314fbfa1STim Northover break; 840314fbfa1STim Northover 841314fbfa1STim Northover case BuiltinType::LongDouble: 842314fbfa1STim Northover LM.setKind(LengthModifier::AsLongDouble); 843314fbfa1STim Northover break; 844314fbfa1STim Northover } 845314fbfa1STim Northover 846314fbfa1STim Northover // Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers in C99. 847314fbfa1STim Northover if (isa<TypedefType>(QT) && (LangOpt.C99 || LangOpt.CPlusPlus11)) 848314fbfa1STim Northover namedTypeToLengthModifier(QT, LM); 849314fbfa1STim Northover 850314fbfa1STim Northover // If fixing the length modifier was enough, we might be done. 85158fc8082SMatt Arsenault if (hasValidLengthModifier(Ctx.getTargetInfo(), LangOpt)) { 852314fbfa1STim Northover // If we're going to offer a fix anyway, make sure the sign matches. 853314fbfa1STim Northover switch (CS.getKind()) { 854314fbfa1STim Northover case ConversionSpecifier::uArg: 855314fbfa1STim Northover case ConversionSpecifier::UArg: 856314fbfa1STim Northover if (QT->isSignedIntegerType()) 857314fbfa1STim Northover CS.setKind(clang::analyze_format_string::ConversionSpecifier::dArg); 858314fbfa1STim Northover break; 859314fbfa1STim Northover case ConversionSpecifier::dArg: 860314fbfa1STim Northover case ConversionSpecifier::DArg: 861314fbfa1STim Northover case ConversionSpecifier::iArg: 862314fbfa1STim Northover if (QT->isUnsignedIntegerType() && !HasPlusPrefix) 863314fbfa1STim Northover CS.setKind(clang::analyze_format_string::ConversionSpecifier::uArg); 864314fbfa1STim Northover break; 865314fbfa1STim Northover default: 866314fbfa1STim Northover // Other specifiers do not have signed/unsigned variants. 867314fbfa1STim Northover break; 868314fbfa1STim Northover } 869314fbfa1STim Northover 870314fbfa1STim Northover const analyze_printf::ArgType &ATR = getArgType(Ctx, IsObjCLiteral); 871314fbfa1STim Northover if (ATR.isValid() && ATR.matchesType(Ctx, QT)) 872314fbfa1STim Northover return true; 873314fbfa1STim Northover } 874314fbfa1STim Northover 875314fbfa1STim Northover // Set conversion specifier and disable any flags which do not apply to it. 876314fbfa1STim Northover // Let typedefs to char fall through to int, as %c is silly for uint8_t. 877314fbfa1STim Northover if (!isa<TypedefType>(QT) && QT->isCharType()) { 878314fbfa1STim Northover CS.setKind(ConversionSpecifier::cArg); 879314fbfa1STim Northover LM.setKind(LengthModifier::None); 880314fbfa1STim Northover Precision.setHowSpecified(OptionalAmount::NotSpecified); 88140446663SKazu Hirata HasAlternativeForm = false; 88240446663SKazu Hirata HasLeadingZeroes = false; 88340446663SKazu Hirata HasPlusPrefix = false; 884314fbfa1STim Northover } 885314fbfa1STim Northover // Test for Floating type first as LongDouble can pass isUnsignedIntegerType 886314fbfa1STim Northover else if (QT->isRealFloatingType()) { 887314fbfa1STim Northover CS.setKind(ConversionSpecifier::fArg); 888314fbfa1STim Northover } 889314fbfa1STim Northover else if (QT->isSignedIntegerType()) { 890314fbfa1STim Northover CS.setKind(ConversionSpecifier::dArg); 89140446663SKazu Hirata HasAlternativeForm = false; 892314fbfa1STim Northover } 893314fbfa1STim Northover else if (QT->isUnsignedIntegerType()) { 894314fbfa1STim Northover CS.setKind(ConversionSpecifier::uArg); 89540446663SKazu Hirata HasAlternativeForm = false; 89640446663SKazu Hirata HasPlusPrefix = false; 897314fbfa1STim Northover } else { 898314fbfa1STim Northover llvm_unreachable("Unexpected type"); 899314fbfa1STim Northover } 900314fbfa1STim Northover 901314fbfa1STim Northover return true; 902314fbfa1STim Northover } 903314fbfa1STim Northover 904314fbfa1STim Northover void PrintfSpecifier::toString(raw_ostream &os) const { 905314fbfa1STim Northover // Whilst some features have no defined order, we are using the order 906314fbfa1STim Northover // appearing in the C99 standard (ISO/IEC 9899:1999 (E) 7.19.6.1) 907314fbfa1STim Northover os << "%"; 908314fbfa1STim Northover 909314fbfa1STim Northover // Positional args 910314fbfa1STim Northover if (usesPositionalArg()) { 911314fbfa1STim Northover os << getPositionalArgIndex() << "$"; 912314fbfa1STim Northover } 913314fbfa1STim Northover 914314fbfa1STim Northover // Conversion flags 915314fbfa1STim Northover if (IsLeftJustified) os << "-"; 916314fbfa1STim Northover if (HasPlusPrefix) os << "+"; 917314fbfa1STim Northover if (HasSpacePrefix) os << " "; 918314fbfa1STim Northover if (HasAlternativeForm) os << "#"; 919314fbfa1STim Northover if (HasLeadingZeroes) os << "0"; 920314fbfa1STim Northover 921314fbfa1STim Northover // Minimum field width 922314fbfa1STim Northover FieldWidth.toString(os); 923314fbfa1STim Northover // Precision 924314fbfa1STim Northover Precision.toString(os); 9250ff50d49SMatt Arsenault 9260ff50d49SMatt Arsenault // Vector modifier 9270ff50d49SMatt Arsenault if (!VectorNumElts.isInvalid()) 9280ff50d49SMatt Arsenault os << 'v' << VectorNumElts.getConstantAmount(); 9290ff50d49SMatt Arsenault 930314fbfa1STim Northover // Length modifier 931314fbfa1STim Northover os << LM.toString(); 932314fbfa1STim Northover // Conversion specifier 933314fbfa1STim Northover os << CS.toString(); 934314fbfa1STim Northover } 935314fbfa1STim Northover 936314fbfa1STim Northover bool PrintfSpecifier::hasValidPlusPrefix() const { 937314fbfa1STim Northover if (!HasPlusPrefix) 938314fbfa1STim Northover return true; 939314fbfa1STim Northover 940314fbfa1STim Northover // The plus prefix only makes sense for signed conversions 941314fbfa1STim Northover switch (CS.getKind()) { 942314fbfa1STim Northover case ConversionSpecifier::dArg: 943314fbfa1STim Northover case ConversionSpecifier::DArg: 944314fbfa1STim Northover case ConversionSpecifier::iArg: 945314fbfa1STim Northover case ConversionSpecifier::fArg: 946314fbfa1STim Northover case ConversionSpecifier::FArg: 947314fbfa1STim Northover case ConversionSpecifier::eArg: 948314fbfa1STim Northover case ConversionSpecifier::EArg: 949314fbfa1STim Northover case ConversionSpecifier::gArg: 950314fbfa1STim Northover case ConversionSpecifier::GArg: 951314fbfa1STim Northover case ConversionSpecifier::aArg: 952314fbfa1STim Northover case ConversionSpecifier::AArg: 953314fbfa1STim Northover case ConversionSpecifier::FreeBSDrArg: 954314fbfa1STim Northover case ConversionSpecifier::FreeBSDyArg: 955314fbfa1STim Northover return true; 956314fbfa1STim Northover 957314fbfa1STim Northover default: 958314fbfa1STim Northover return false; 959314fbfa1STim Northover } 960314fbfa1STim Northover } 961314fbfa1STim Northover 962314fbfa1STim Northover bool PrintfSpecifier::hasValidAlternativeForm() const { 963314fbfa1STim Northover if (!HasAlternativeForm) 964314fbfa1STim Northover return true; 965314fbfa1STim Northover 966314fbfa1STim Northover // Alternate form flag only valid with the oxXaAeEfFgG conversions 967314fbfa1STim Northover switch (CS.getKind()) { 968314fbfa1STim Northover case ConversionSpecifier::oArg: 969314fbfa1STim Northover case ConversionSpecifier::OArg: 970314fbfa1STim Northover case ConversionSpecifier::xArg: 971314fbfa1STim Northover case ConversionSpecifier::XArg: 972314fbfa1STim Northover case ConversionSpecifier::aArg: 973314fbfa1STim Northover case ConversionSpecifier::AArg: 974314fbfa1STim Northover case ConversionSpecifier::eArg: 975314fbfa1STim Northover case ConversionSpecifier::EArg: 976314fbfa1STim Northover case ConversionSpecifier::fArg: 977314fbfa1STim Northover case ConversionSpecifier::FArg: 978314fbfa1STim Northover case ConversionSpecifier::gArg: 979314fbfa1STim Northover case ConversionSpecifier::GArg: 980314fbfa1STim Northover case ConversionSpecifier::FreeBSDrArg: 981314fbfa1STim Northover case ConversionSpecifier::FreeBSDyArg: 982314fbfa1STim Northover return true; 983314fbfa1STim Northover 984314fbfa1STim Northover default: 985314fbfa1STim Northover return false; 986314fbfa1STim Northover } 987314fbfa1STim Northover } 988314fbfa1STim Northover 989314fbfa1STim Northover bool PrintfSpecifier::hasValidLeadingZeros() const { 990314fbfa1STim Northover if (!HasLeadingZeroes) 991314fbfa1STim Northover return true; 992314fbfa1STim Northover 993314fbfa1STim Northover // Leading zeroes flag only valid with the diouxXaAeEfFgG conversions 994314fbfa1STim Northover switch (CS.getKind()) { 995314fbfa1STim Northover case ConversionSpecifier::dArg: 996314fbfa1STim Northover case ConversionSpecifier::DArg: 997314fbfa1STim Northover case ConversionSpecifier::iArg: 998314fbfa1STim Northover case ConversionSpecifier::oArg: 999314fbfa1STim Northover case ConversionSpecifier::OArg: 1000314fbfa1STim Northover case ConversionSpecifier::uArg: 1001314fbfa1STim Northover case ConversionSpecifier::UArg: 1002314fbfa1STim Northover case ConversionSpecifier::xArg: 1003314fbfa1STim Northover case ConversionSpecifier::XArg: 1004314fbfa1STim Northover case ConversionSpecifier::aArg: 1005314fbfa1STim Northover case ConversionSpecifier::AArg: 1006314fbfa1STim Northover case ConversionSpecifier::eArg: 1007314fbfa1STim Northover case ConversionSpecifier::EArg: 1008314fbfa1STim Northover case ConversionSpecifier::fArg: 1009314fbfa1STim Northover case ConversionSpecifier::FArg: 1010314fbfa1STim Northover case ConversionSpecifier::gArg: 1011314fbfa1STim Northover case ConversionSpecifier::GArg: 1012314fbfa1STim Northover case ConversionSpecifier::FreeBSDrArg: 1013314fbfa1STim Northover case ConversionSpecifier::FreeBSDyArg: 1014314fbfa1STim Northover return true; 1015314fbfa1STim Northover 1016314fbfa1STim Northover default: 1017314fbfa1STim Northover return false; 1018314fbfa1STim Northover } 1019314fbfa1STim Northover } 1020314fbfa1STim Northover 1021314fbfa1STim Northover bool PrintfSpecifier::hasValidSpacePrefix() const { 1022314fbfa1STim Northover if (!HasSpacePrefix) 1023314fbfa1STim Northover return true; 1024314fbfa1STim Northover 1025314fbfa1STim Northover // The space prefix only makes sense for signed conversions 1026314fbfa1STim Northover switch (CS.getKind()) { 1027314fbfa1STim Northover case ConversionSpecifier::dArg: 1028314fbfa1STim Northover case ConversionSpecifier::DArg: 1029314fbfa1STim Northover case ConversionSpecifier::iArg: 1030314fbfa1STim Northover case ConversionSpecifier::fArg: 1031314fbfa1STim Northover case ConversionSpecifier::FArg: 1032314fbfa1STim Northover case ConversionSpecifier::eArg: 1033314fbfa1STim Northover case ConversionSpecifier::EArg: 1034314fbfa1STim Northover case ConversionSpecifier::gArg: 1035314fbfa1STim Northover case ConversionSpecifier::GArg: 1036314fbfa1STim Northover case ConversionSpecifier::aArg: 1037314fbfa1STim Northover case ConversionSpecifier::AArg: 1038314fbfa1STim Northover case ConversionSpecifier::FreeBSDrArg: 1039314fbfa1STim Northover case ConversionSpecifier::FreeBSDyArg: 1040314fbfa1STim Northover return true; 1041314fbfa1STim Northover 1042314fbfa1STim Northover default: 1043314fbfa1STim Northover return false; 1044314fbfa1STim Northover } 1045314fbfa1STim Northover } 1046314fbfa1STim Northover 1047314fbfa1STim Northover bool PrintfSpecifier::hasValidLeftJustified() const { 1048314fbfa1STim Northover if (!IsLeftJustified) 1049314fbfa1STim Northover return true; 1050314fbfa1STim Northover 1051314fbfa1STim Northover // The left justified flag is valid for all conversions except n 1052314fbfa1STim Northover switch (CS.getKind()) { 1053314fbfa1STim Northover case ConversionSpecifier::nArg: 1054314fbfa1STim Northover return false; 1055314fbfa1STim Northover 1056314fbfa1STim Northover default: 1057314fbfa1STim Northover return true; 1058314fbfa1STim Northover } 1059314fbfa1STim Northover } 1060314fbfa1STim Northover 1061314fbfa1STim Northover bool PrintfSpecifier::hasValidThousandsGroupingPrefix() const { 1062314fbfa1STim Northover if (!HasThousandsGrouping) 1063314fbfa1STim Northover return true; 1064314fbfa1STim Northover 1065314fbfa1STim Northover switch (CS.getKind()) { 1066314fbfa1STim Northover case ConversionSpecifier::dArg: 1067314fbfa1STim Northover case ConversionSpecifier::DArg: 1068314fbfa1STim Northover case ConversionSpecifier::iArg: 1069314fbfa1STim Northover case ConversionSpecifier::uArg: 1070314fbfa1STim Northover case ConversionSpecifier::UArg: 1071314fbfa1STim Northover case ConversionSpecifier::fArg: 1072314fbfa1STim Northover case ConversionSpecifier::FArg: 1073314fbfa1STim Northover case ConversionSpecifier::gArg: 1074314fbfa1STim Northover case ConversionSpecifier::GArg: 1075314fbfa1STim Northover return true; 1076314fbfa1STim Northover default: 1077314fbfa1STim Northover return false; 1078314fbfa1STim Northover } 1079314fbfa1STim Northover } 1080314fbfa1STim Northover 1081314fbfa1STim Northover bool PrintfSpecifier::hasValidPrecision() const { 1082314fbfa1STim Northover if (Precision.getHowSpecified() == OptionalAmount::NotSpecified) 1083314fbfa1STim Northover return true; 1084314fbfa1STim Northover 1085314fbfa1STim Northover // Precision is only valid with the diouxXaAeEfFgGsP conversions 1086314fbfa1STim Northover switch (CS.getKind()) { 1087314fbfa1STim Northover case ConversionSpecifier::dArg: 1088314fbfa1STim Northover case ConversionSpecifier::DArg: 1089314fbfa1STim Northover case ConversionSpecifier::iArg: 1090314fbfa1STim Northover case ConversionSpecifier::oArg: 1091314fbfa1STim Northover case ConversionSpecifier::OArg: 1092314fbfa1STim Northover case ConversionSpecifier::uArg: 1093314fbfa1STim Northover case ConversionSpecifier::UArg: 1094314fbfa1STim Northover case ConversionSpecifier::xArg: 1095314fbfa1STim Northover case ConversionSpecifier::XArg: 1096314fbfa1STim Northover case ConversionSpecifier::aArg: 1097314fbfa1STim Northover case ConversionSpecifier::AArg: 1098314fbfa1STim Northover case ConversionSpecifier::eArg: 1099314fbfa1STim Northover case ConversionSpecifier::EArg: 1100314fbfa1STim Northover case ConversionSpecifier::fArg: 1101314fbfa1STim Northover case ConversionSpecifier::FArg: 1102314fbfa1STim Northover case ConversionSpecifier::gArg: 1103314fbfa1STim Northover case ConversionSpecifier::GArg: 1104314fbfa1STim Northover case ConversionSpecifier::sArg: 1105314fbfa1STim Northover case ConversionSpecifier::FreeBSDrArg: 1106314fbfa1STim Northover case ConversionSpecifier::FreeBSDyArg: 1107314fbfa1STim Northover case ConversionSpecifier::PArg: 1108314fbfa1STim Northover return true; 1109314fbfa1STim Northover 1110314fbfa1STim Northover default: 1111314fbfa1STim Northover return false; 1112314fbfa1STim Northover } 1113314fbfa1STim Northover } 1114314fbfa1STim Northover bool PrintfSpecifier::hasValidFieldWidth() const { 1115314fbfa1STim Northover if (FieldWidth.getHowSpecified() == OptionalAmount::NotSpecified) 1116314fbfa1STim Northover return true; 1117314fbfa1STim Northover 1118314fbfa1STim Northover // The field width is valid for all conversions except n 1119314fbfa1STim Northover switch (CS.getKind()) { 1120314fbfa1STim Northover case ConversionSpecifier::nArg: 1121314fbfa1STim Northover return false; 1122314fbfa1STim Northover 1123314fbfa1STim Northover default: 1124314fbfa1STim Northover return true; 1125314fbfa1STim Northover } 1126314fbfa1STim Northover } 1127