1222 lines · cpp
1//== PrintfFormatString.cpp - Analysis of printf format strings --*- C++ -*-==//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// Handling of format string in printf and friends. The structure of format10// strings for fprintf() are described in C99 7.19.6.1.11//12//===----------------------------------------------------------------------===//13 14#include "FormatStringParsing.h"15#include "clang/AST/FormatString.h"16#include "clang/AST/OSLog.h"17#include "clang/Basic/TargetInfo.h"18#include "llvm/Support/Regex.h"19 20using clang::analyze_format_string::ArgType;21using clang::analyze_format_string::FormatStringHandler;22using clang::analyze_format_string::LengthModifier;23using clang::analyze_format_string::OptionalAmount;24using clang::analyze_format_string::ConversionSpecifier;25using clang::analyze_printf::PrintfSpecifier;26 27using namespace clang;28 29typedef clang::analyze_format_string::SpecifierResult<PrintfSpecifier>30 PrintfSpecifierResult;31 32//===----------------------------------------------------------------------===//33// Methods for parsing format strings.34//===----------------------------------------------------------------------===//35 36using analyze_format_string::ParseNonPositionAmount;37 38static bool ParsePrecision(FormatStringHandler &H, PrintfSpecifier &FS,39 const char *Start, const char *&Beg, const char *E,40 unsigned *argIndex) {41 if (argIndex) {42 FS.setPrecision(ParseNonPositionAmount(Beg, E, *argIndex));43 } else {44 const OptionalAmount Amt = ParsePositionAmount(H, Start, Beg, E,45 analyze_format_string::PrecisionPos);46 if (Amt.isInvalid())47 return true;48 FS.setPrecision(Amt);49 }50 return false;51}52 53static bool ParseObjCFlags(FormatStringHandler &H, PrintfSpecifier &FS,54 const char *FlagBeg, const char *E, bool Warn) {55 StringRef Flag(FlagBeg, E - FlagBeg);56 // Currently there is only one flag.57 if (Flag == "tt") {58 FS.setHasObjCTechnicalTerm(FlagBeg);59 return false;60 }61 // Handle either the case of no flag or an invalid flag.62 if (Warn) {63 if (Flag == "")64 H.HandleEmptyObjCModifierFlag(FlagBeg, E - FlagBeg);65 else66 H.HandleInvalidObjCModifierFlag(FlagBeg, E - FlagBeg);67 }68 return true;69}70 71static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H,72 const char *&Beg,73 const char *E,74 unsigned &argIndex,75 const LangOptions &LO,76 const TargetInfo &Target,77 bool Warn,78 bool isFreeBSDKPrintf) {79 80 using namespace clang::analyze_format_string;81 using namespace clang::analyze_printf;82 83 const char *I = Beg;84 const char *Start = nullptr;85 UpdateOnReturn <const char*> UpdateBeg(Beg, I);86 87 // Look for a '%' character that indicates the start of a format specifier.88 for ( ; I != E ; ++I) {89 char c = *I;90 if (c == '\0') {91 // Detect spurious null characters, which are likely errors.92 H.HandleNullChar(I);93 return true;94 }95 if (c == '%') {96 Start = I++; // Record the start of the format specifier.97 break;98 }99 }100 101 // No format specifier found?102 if (!Start)103 return false;104 105 if (I == E) {106 // No more characters left?107 if (Warn)108 H.HandleIncompleteSpecifier(Start, E - Start);109 return true;110 }111 112 PrintfSpecifier FS;113 if (ParseArgPosition(H, FS, Start, I, E))114 return true;115 116 if (I == E) {117 // No more characters left?118 if (Warn)119 H.HandleIncompleteSpecifier(Start, E - Start);120 return true;121 }122 123 if (*I == '{') {124 ++I;125 unsigned char PrivacyFlags = 0;126 StringRef MatchedStr;127 128 do {129 StringRef Str(I, E - I);130 std::string Match = "^[[:space:]]*"131 "(private|public|sensitive|mask\\.[^[:space:],}]*)"132 "[[:space:]]*(,|})";133 llvm::Regex R(Match);134 SmallVector<StringRef, 2> Matches;135 136 if (R.match(Str, &Matches)) {137 MatchedStr = Matches[1];138 I += Matches[0].size();139 140 // Set the privacy flag if the privacy annotation in the141 // comma-delimited segment is at least as strict as the privacy142 // annotations in previous comma-delimited segments.143 if (MatchedStr.starts_with("mask")) {144 StringRef MaskType = MatchedStr.substr(sizeof("mask.") - 1);145 unsigned Size = MaskType.size();146 if (Warn && (Size == 0 || Size > 8))147 H.handleInvalidMaskType(MaskType);148 FS.setMaskType(MaskType);149 } else if (MatchedStr == "sensitive")150 PrivacyFlags = clang::analyze_os_log::OSLogBufferItem::IsSensitive;151 else if (PrivacyFlags !=152 clang::analyze_os_log::OSLogBufferItem::IsSensitive &&153 MatchedStr == "private")154 PrivacyFlags = clang::analyze_os_log::OSLogBufferItem::IsPrivate;155 else if (PrivacyFlags == 0 && MatchedStr == "public")156 PrivacyFlags = clang::analyze_os_log::OSLogBufferItem::IsPublic;157 } else {158 size_t CommaOrBracePos =159 Str.find_if([](char c) { return c == ',' || c == '}'; });160 161 if (CommaOrBracePos == StringRef::npos) {162 // Neither a comma nor the closing brace was found.163 if (Warn)164 H.HandleIncompleteSpecifier(Start, E - Start);165 return true;166 }167 168 I += CommaOrBracePos + 1;169 }170 // Continue until the closing brace is found.171 } while (*(I - 1) == ',');172 173 // Set the privacy flag.174 switch (PrivacyFlags) {175 case 0:176 break;177 case clang::analyze_os_log::OSLogBufferItem::IsPrivate:178 FS.setIsPrivate(MatchedStr.data());179 break;180 case clang::analyze_os_log::OSLogBufferItem::IsPublic:181 FS.setIsPublic(MatchedStr.data());182 break;183 case clang::analyze_os_log::OSLogBufferItem::IsSensitive:184 FS.setIsSensitive(MatchedStr.data());185 break;186 default:187 llvm_unreachable("Unexpected privacy flag value");188 }189 }190 191 // Look for flags (if any).192 bool hasMore = true;193 for ( ; I != E; ++I) {194 switch (*I) {195 default: hasMore = false; break;196 case '\'':197 // FIXME: POSIX specific. Always accept?198 FS.setHasThousandsGrouping(I);199 break;200 case '-': FS.setIsLeftJustified(I); break;201 case '+': FS.setHasPlusPrefix(I); break;202 case ' ': FS.setHasSpacePrefix(I); break;203 case '#': FS.setHasAlternativeForm(I); break;204 case '0': FS.setHasLeadingZeros(I); break;205 }206 if (!hasMore)207 break;208 }209 210 if (I == E) {211 // No more characters left?212 if (Warn)213 H.HandleIncompleteSpecifier(Start, E - Start);214 return true;215 }216 217 // Look for the field width (if any).218 if (ParseFieldWidth(H, FS, Start, I, E,219 FS.usesPositionalArg() ? nullptr : &argIndex))220 return true;221 222 if (I == E) {223 // No more characters left?224 if (Warn)225 H.HandleIncompleteSpecifier(Start, E - Start);226 return true;227 }228 229 // Look for the precision (if any).230 if (*I == '.') {231 ++I;232 if (I == E) {233 if (Warn)234 H.HandleIncompleteSpecifier(Start, E - Start);235 return true;236 }237 238 if (ParsePrecision(H, FS, Start, I, E,239 FS.usesPositionalArg() ? nullptr : &argIndex))240 return true;241 242 if (I == E) {243 // No more characters left?244 if (Warn)245 H.HandleIncompleteSpecifier(Start, E - Start);246 return true;247 }248 }249 250 if (ParseVectorModifier(H, FS, I, E, LO))251 return true;252 253 // Look for the length modifier.254 if (ParseLengthModifier(FS, I, E, LO) && I == E) {255 // No more characters left?256 if (Warn)257 H.HandleIncompleteSpecifier(Start, E - Start);258 return true;259 }260 261 // Look for the Objective-C modifier flags, if any.262 // We parse these here, even if they don't apply to263 // the conversion specifier, and then emit an error264 // later if the conversion specifier isn't '@'. This265 // enables better recovery, and we don't know if266 // these flags are applicable until later.267 const char *ObjCModifierFlagsStart = nullptr,268 *ObjCModifierFlagsEnd = nullptr;269 if (*I == '[') {270 ObjCModifierFlagsStart = I;271 ++I;272 auto flagStart = I;273 for (;; ++I) {274 ObjCModifierFlagsEnd = I;275 if (I == E) {276 if (Warn)277 H.HandleIncompleteSpecifier(Start, E - Start);278 return true;279 }280 // Did we find the closing ']'?281 if (*I == ']') {282 if (ParseObjCFlags(H, FS, flagStart, I, Warn))283 return true;284 ++I;285 break;286 }287 // There are no separators defined yet for multiple288 // Objective-C modifier flags. When those are289 // defined, this is the place to check.290 }291 }292 293 if (*I == '\0') {294 // Detect spurious null characters, which are likely errors.295 H.HandleNullChar(I);296 return true;297 }298 299 // Finally, look for the conversion specifier.300 const char *conversionPosition = I++;301 ConversionSpecifier::Kind k = ConversionSpecifier::InvalidSpecifier;302 switch (*conversionPosition) {303 default:304 break;305 // C99: 7.19.6.1 (section 8).306 case '%': k = ConversionSpecifier::PercentArg; break;307 case 'A': k = ConversionSpecifier::AArg; break;308 case 'E': k = ConversionSpecifier::EArg; break;309 case 'F': k = ConversionSpecifier::FArg; break;310 case 'G': k = ConversionSpecifier::GArg; break;311 case 'X': k = ConversionSpecifier::XArg; break;312 case 'a': k = ConversionSpecifier::aArg; break;313 case 'c': k = ConversionSpecifier::cArg; break;314 case 'd': k = ConversionSpecifier::dArg; break;315 case 'e': k = ConversionSpecifier::eArg; break;316 case 'f': k = ConversionSpecifier::fArg; break;317 case 'g': k = ConversionSpecifier::gArg; break;318 case 'i': k = ConversionSpecifier::iArg; break;319 case 'n':320 // Not handled, but reserved in OpenCL.321 if (!LO.OpenCL)322 k = ConversionSpecifier::nArg;323 break;324 case 'o': k = ConversionSpecifier::oArg; break;325 case 'p': k = ConversionSpecifier::pArg; break;326 case 's': k = ConversionSpecifier::sArg; break;327 case 'u': k = ConversionSpecifier::uArg; break;328 case 'x': k = ConversionSpecifier::xArg; break;329 // C23.330 case 'b':331 if (isFreeBSDKPrintf)332 k = ConversionSpecifier::FreeBSDbArg; // int followed by char *333 else334 k = ConversionSpecifier::bArg;335 break;336 case 'B': k = ConversionSpecifier::BArg; break;337 // POSIX specific.338 case 'C': k = ConversionSpecifier::CArg; break;339 case 'S': k = ConversionSpecifier::SArg; break;340 // Apple extension for os_log341 case 'P':342 k = ConversionSpecifier::PArg;343 break;344 // Objective-C.345 case '@': k = ConversionSpecifier::ObjCObjArg; break;346 // Glibc specific.347 case 'm': k = ConversionSpecifier::PrintErrno; break;348 case 'r':349 if (isFreeBSDKPrintf)350 k = ConversionSpecifier::FreeBSDrArg; // int351 else if (LO.FixedPoint)352 k = ConversionSpecifier::rArg;353 break;354 case 'y':355 if (isFreeBSDKPrintf)356 k = ConversionSpecifier::FreeBSDyArg; // int357 break;358 // Apple-specific.359 case 'D':360 if (isFreeBSDKPrintf)361 k = ConversionSpecifier::FreeBSDDArg; // void * followed by char *362 else if (Target.getTriple().isOSDarwin())363 k = ConversionSpecifier::DArg;364 break;365 case 'O':366 if (Target.getTriple().isOSDarwin())367 k = ConversionSpecifier::OArg;368 break;369 case 'U':370 if (Target.getTriple().isOSDarwin())371 k = ConversionSpecifier::UArg;372 break;373 // MS specific.374 case 'Z':375 if (Target.getTriple().isOSMSVCRT())376 k = ConversionSpecifier::ZArg;377 break;378 // ISO/IEC TR 18037 (fixed-point) specific.379 // NOTE: 'r' is handled up above since FreeBSD also supports %r.380 case 'k':381 if (LO.FixedPoint)382 k = ConversionSpecifier::kArg;383 break;384 case 'K':385 if (LO.FixedPoint)386 k = ConversionSpecifier::KArg;387 break;388 case 'R':389 if (LO.FixedPoint)390 k = ConversionSpecifier::RArg;391 break;392 }393 394 // Check to see if we used the Objective-C modifier flags with395 // a conversion specifier other than '@'.396 if (k != ConversionSpecifier::ObjCObjArg &&397 k != ConversionSpecifier::InvalidSpecifier &&398 ObjCModifierFlagsStart) {399 H.HandleObjCFlagsWithNonObjCConversion(ObjCModifierFlagsStart,400 ObjCModifierFlagsEnd + 1,401 conversionPosition);402 return true;403 }404 405 PrintfConversionSpecifier CS(conversionPosition, k);406 FS.setConversionSpecifier(CS);407 if (CS.consumesDataArgument() && !FS.usesPositionalArg())408 FS.setArgIndex(argIndex++);409 // FreeBSD kernel specific.410 if (k == ConversionSpecifier::FreeBSDbArg ||411 k == ConversionSpecifier::FreeBSDDArg)412 argIndex++;413 414 if (k == ConversionSpecifier::InvalidSpecifier) {415 unsigned Len = I - Start;416 if (ParseUTF8InvalidSpecifier(Start, E, Len)) {417 CS.setEndScanList(Start + Len);418 FS.setConversionSpecifier(CS);419 }420 // Assume the conversion takes one argument.421 return !H.HandleInvalidPrintfConversionSpecifier(FS, Start, Len);422 }423 return PrintfSpecifierResult(Start, FS);424}425 426bool clang::analyze_format_string::ParsePrintfString(FormatStringHandler &H,427 const char *I,428 const char *E,429 const LangOptions &LO,430 const TargetInfo &Target,431 bool isFreeBSDKPrintf) {432 433 unsigned argIndex = 0;434 435 // Keep looking for a format specifier until we have exhausted the string.436 while (I != E) {437 const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(H, I, E, argIndex,438 LO, Target, true,439 isFreeBSDKPrintf);440 // Did a fail-stop error of any kind occur when parsing the specifier?441 // If so, don't do any more processing.442 if (FSR.shouldStop())443 return true;444 // Did we exhaust the string or encounter an error that445 // we can recover from?446 if (!FSR.hasValue())447 continue;448 // We have a format specifier. Pass it to the callback.449 if (!H.HandlePrintfSpecifier(FSR.getValue(), FSR.getStart(),450 I - FSR.getStart(), Target))451 return true;452 }453 assert(I == E && "Format string not exhausted");454 return false;455}456 457bool clang::analyze_format_string::ParseFormatStringHasSArg(const char *I,458 const char *E,459 const LangOptions &LO,460 const TargetInfo &Target) {461 462 unsigned argIndex = 0;463 464 // Keep looking for a %s format specifier until we have exhausted the string.465 FormatStringHandler H;466 while (I != E) {467 const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(H, I, E, argIndex,468 LO, Target, false,469 false);470 // Did a fail-stop error of any kind occur when parsing the specifier?471 // If so, don't do any more processing.472 if (FSR.shouldStop())473 return false;474 // Did we exhaust the string or encounter an error that475 // we can recover from?476 if (!FSR.hasValue())477 continue;478 const analyze_printf::PrintfSpecifier &FS = FSR.getValue();479 // Return true if this a %s format specifier.480 if (FS.getConversionSpecifier().getKind() == ConversionSpecifier::Kind::sArg)481 return true;482 }483 return false;484}485 486bool clang::analyze_format_string::parseFormatStringHasFormattingSpecifiers(487 const char *Begin, const char *End, const LangOptions &LO,488 const TargetInfo &Target) {489 unsigned ArgIndex = 0;490 // Keep looking for a formatting specifier until we have exhausted the string.491 FormatStringHandler H;492 while (Begin != End) {493 const PrintfSpecifierResult &FSR =494 ParsePrintfSpecifier(H, Begin, End, ArgIndex, LO, Target, false, false);495 if (FSR.shouldStop())496 break;497 if (FSR.hasValue())498 return true;499 }500 return false;501}502 503//===----------------------------------------------------------------------===//504// Methods on PrintfSpecifier.505//===----------------------------------------------------------------------===//506 507ArgType PrintfSpecifier::getScalarArgType(ASTContext &Ctx,508 bool IsObjCLiteral) const {509 if (CS.getKind() == ConversionSpecifier::cArg)510 switch (LM.getKind()) {511 case LengthModifier::None:512 return Ctx.IntTy;513 case LengthModifier::AsLong:514 case LengthModifier::AsWide:515 return ArgType(ArgType::WIntTy, "wint_t");516 case LengthModifier::AsShort:517 if (Ctx.getTargetInfo().getTriple().isOSMSVCRT())518 return Ctx.IntTy;519 [[fallthrough]];520 default:521 return ArgType::Invalid();522 }523 524 if (CS.isIntArg())525 switch (LM.getKind()) {526 case LengthModifier::AsLongDouble:527 // GNU extension.528 return Ctx.LongLongTy;529 case LengthModifier::None:530 case LengthModifier::AsShortLong:531 return Ctx.IntTy;532 case LengthModifier::AsInt32:533 return ArgType(Ctx.IntTy, "__int32");534 case LengthModifier::AsChar:535 return ArgType::AnyCharTy;536 case LengthModifier::AsShort: return Ctx.ShortTy;537 case LengthModifier::AsLong: return Ctx.LongTy;538 case LengthModifier::AsLongLong:539 case LengthModifier::AsQuad:540 return Ctx.LongLongTy;541 case LengthModifier::AsInt64:542 return ArgType(Ctx.LongLongTy, "__int64");543 case LengthModifier::AsIntMax:544 return ArgType(Ctx.getIntMaxType(), "intmax_t");545 case LengthModifier::AsSizeT:546 return ArgType::makeSizeT(547 ArgType(Ctx.getSignedSizeType(), "signed size_t"));548 case LengthModifier::AsInt3264:549 return Ctx.getTargetInfo().getTriple().isArch64Bit()550 ? ArgType(Ctx.LongLongTy, "__int64")551 : ArgType(Ctx.IntTy, "__int32");552 case LengthModifier::AsPtrDiff:553 return ArgType::makePtrdiffT(554 ArgType(Ctx.getPointerDiffType(), "ptrdiff_t"));555 case LengthModifier::AsAllocate:556 case LengthModifier::AsMAllocate:557 case LengthModifier::AsWide:558 return ArgType::Invalid();559 }560 561 if (CS.isUIntArg())562 switch (LM.getKind()) {563 case LengthModifier::AsLongDouble:564 // GNU extension.565 return Ctx.UnsignedLongLongTy;566 case LengthModifier::None:567 case LengthModifier::AsShortLong:568 return Ctx.UnsignedIntTy;569 case LengthModifier::AsInt32:570 return ArgType(Ctx.UnsignedIntTy, "unsigned __int32");571 case LengthModifier::AsChar: return Ctx.UnsignedCharTy;572 case LengthModifier::AsShort: return Ctx.UnsignedShortTy;573 case LengthModifier::AsLong: return Ctx.UnsignedLongTy;574 case LengthModifier::AsLongLong:575 case LengthModifier::AsQuad:576 return Ctx.UnsignedLongLongTy;577 case LengthModifier::AsInt64:578 return ArgType(Ctx.UnsignedLongLongTy, "unsigned __int64");579 case LengthModifier::AsIntMax:580 return ArgType(Ctx.getUIntMaxType(), "uintmax_t");581 case LengthModifier::AsSizeT:582 return ArgType::makeSizeT(ArgType(Ctx.getSizeType(), "size_t"));583 case LengthModifier::AsInt3264:584 return Ctx.getTargetInfo().getTriple().isArch64Bit()585 ? ArgType(Ctx.UnsignedLongLongTy, "unsigned __int64")586 : ArgType(Ctx.UnsignedIntTy, "unsigned __int32");587 case LengthModifier::AsPtrDiff:588 return ArgType::makePtrdiffT(589 ArgType(Ctx.getUnsignedPointerDiffType(), "unsigned ptrdiff_t"));590 case LengthModifier::AsAllocate:591 case LengthModifier::AsMAllocate:592 case LengthModifier::AsWide:593 return ArgType::Invalid();594 }595 596 if (CS.isDoubleArg()) {597 if (!VectorNumElts.isInvalid()) {598 switch (LM.getKind()) {599 case LengthModifier::AsShort:600 return Ctx.HalfTy;601 case LengthModifier::AsShortLong:602 return Ctx.FloatTy;603 case LengthModifier::AsLong:604 default:605 return Ctx.DoubleTy;606 }607 }608 609 if (LM.getKind() == LengthModifier::AsLongDouble)610 return Ctx.LongDoubleTy;611 return Ctx.DoubleTy;612 }613 614 if (CS.getKind() == ConversionSpecifier::nArg) {615 switch (LM.getKind()) {616 case LengthModifier::None:617 return ArgType::PtrTo(Ctx.IntTy);618 case LengthModifier::AsChar:619 return ArgType::PtrTo(Ctx.SignedCharTy);620 case LengthModifier::AsShort:621 return ArgType::PtrTo(Ctx.ShortTy);622 case LengthModifier::AsLong:623 return ArgType::PtrTo(Ctx.LongTy);624 case LengthModifier::AsLongLong:625 case LengthModifier::AsQuad:626 return ArgType::PtrTo(Ctx.LongLongTy);627 case LengthModifier::AsIntMax:628 return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t"));629 case LengthModifier::AsSizeT:630 return ArgType::PtrTo(ArgType::makeSizeT(631 ArgType(Ctx.getSignedSizeType(), "signed size_t")));632 case LengthModifier::AsPtrDiff:633 return ArgType::PtrTo(ArgType::makePtrdiffT(634 ArgType(Ctx.getPointerDiffType(), "ptrdiff_t")));635 case LengthModifier::AsLongDouble:636 return ArgType(); // FIXME: Is this a known extension?637 case LengthModifier::AsAllocate:638 case LengthModifier::AsMAllocate:639 case LengthModifier::AsInt32:640 case LengthModifier::AsInt3264:641 case LengthModifier::AsInt64:642 case LengthModifier::AsWide:643 return ArgType::Invalid();644 case LengthModifier::AsShortLong:645 llvm_unreachable("only used for OpenCL which doesn not handle nArg");646 }647 }648 649 if (CS.isFixedPointArg() && !Ctx.getLangOpts().FixedPoint)650 return ArgType::Invalid();651 652 switch (CS.getKind()) {653 case ConversionSpecifier::sArg:654 if (LM.getKind() == LengthModifier::AsWideChar) {655 if (IsObjCLiteral)656 return ArgType(Ctx.getPointerType(Ctx.UnsignedShortTy.withConst()),657 "const unichar *");658 return ArgType(ArgType::WCStrTy, "wchar_t *");659 }660 if (LM.getKind() == LengthModifier::AsWide)661 return ArgType(ArgType::WCStrTy, "wchar_t *");662 return ArgType::CStrTy;663 case ConversionSpecifier::SArg:664 if (IsObjCLiteral)665 return ArgType(Ctx.getPointerType(Ctx.UnsignedShortTy.withConst()),666 "const unichar *");667 if (Ctx.getTargetInfo().getTriple().isOSMSVCRT() &&668 LM.getKind() == LengthModifier::AsShort)669 return ArgType::CStrTy;670 return ArgType(ArgType::WCStrTy, "wchar_t *");671 case ConversionSpecifier::CArg:672 if (IsObjCLiteral)673 return ArgType(Ctx.UnsignedShortTy, "unichar");674 if (Ctx.getTargetInfo().getTriple().isOSMSVCRT() &&675 LM.getKind() == LengthModifier::AsShort)676 return Ctx.IntTy;677 return ArgType(Ctx.WideCharTy, "wchar_t");678 case ConversionSpecifier::pArg:679 case ConversionSpecifier::PArg:680 return ArgType::CPointerTy;681 case ConversionSpecifier::ObjCObjArg:682 return ArgType::ObjCPointerTy;683 case ConversionSpecifier::kArg:684 switch (LM.getKind()) {685 case LengthModifier::None:686 return Ctx.AccumTy;687 case LengthModifier::AsShort:688 return Ctx.ShortAccumTy;689 case LengthModifier::AsLong:690 return Ctx.LongAccumTy;691 default:692 return ArgType::Invalid();693 }694 case ConversionSpecifier::KArg:695 switch (LM.getKind()) {696 case LengthModifier::None:697 return Ctx.UnsignedAccumTy;698 case LengthModifier::AsShort:699 return Ctx.UnsignedShortAccumTy;700 case LengthModifier::AsLong:701 return Ctx.UnsignedLongAccumTy;702 default:703 return ArgType::Invalid();704 }705 case ConversionSpecifier::rArg:706 switch (LM.getKind()) {707 case LengthModifier::None:708 return Ctx.FractTy;709 case LengthModifier::AsShort:710 return Ctx.ShortFractTy;711 case LengthModifier::AsLong:712 return Ctx.LongFractTy;713 default:714 return ArgType::Invalid();715 }716 case ConversionSpecifier::RArg:717 switch (LM.getKind()) {718 case LengthModifier::None:719 return Ctx.UnsignedFractTy;720 case LengthModifier::AsShort:721 return Ctx.UnsignedShortFractTy;722 case LengthModifier::AsLong:723 return Ctx.UnsignedLongFractTy;724 default:725 return ArgType::Invalid();726 }727 default:728 break;729 }730 731 // FIXME: Handle other cases.732 return ArgType();733}734 735 736ArgType PrintfSpecifier::getArgType(ASTContext &Ctx,737 bool IsObjCLiteral) const {738 const PrintfConversionSpecifier &CS = getConversionSpecifier();739 740 if (!CS.consumesDataArgument())741 return ArgType::Invalid();742 743 ArgType ScalarTy = getScalarArgType(Ctx, IsObjCLiteral);744 if (!ScalarTy.isValid() || VectorNumElts.isInvalid())745 return ScalarTy;746 747 return ScalarTy.makeVectorType(Ctx, VectorNumElts.getConstantAmount());748}749 750bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt,751 ASTContext &Ctx, bool IsObjCLiteral) {752 // %n is different from other conversion specifiers; don't try to fix it.753 if (CS.getKind() == ConversionSpecifier::nArg)754 return false;755 756 // Handle Objective-C objects first. Note that while the '%@' specifier will757 // not warn for structure pointer or void pointer arguments (because that's758 // how CoreFoundation objects are implemented), we only show a fixit for '%@'759 // if we know it's an object (block, id, class, or __attribute__((NSObject))).760 if (QT->isObjCRetainableType()) {761 if (!IsObjCLiteral)762 return false;763 764 CS.setKind(ConversionSpecifier::ObjCObjArg);765 766 // Disable irrelevant flags767 HasThousandsGrouping = false;768 HasPlusPrefix = false;769 HasSpacePrefix = false;770 HasAlternativeForm = false;771 HasLeadingZeroes = false;772 Precision.setHowSpecified(OptionalAmount::NotSpecified);773 LM.setKind(LengthModifier::None);774 775 return true;776 }777 778 // Handle strings next (char *, wchar_t *)779 if (QT->isPointerType() && (QT->getPointeeType()->isAnyCharacterType())) {780 CS.setKind(ConversionSpecifier::sArg);781 782 // Disable irrelevant flags783 HasAlternativeForm = false;784 HasLeadingZeroes = false;785 786 // Set the long length modifier for wide characters787 if (QT->getPointeeType()->isWideCharType())788 LM.setKind(LengthModifier::AsWideChar);789 else790 LM.setKind(LengthModifier::None);791 792 return true;793 }794 795 // If it's an enum, get its underlying type.796 if (const auto *ED = QT->getAsEnumDecl())797 QT = ED->getIntegerType();798 799 const BuiltinType *BT = QT->getAs<BuiltinType>();800 if (!BT) {801 const VectorType *VT = QT->getAs<VectorType>();802 if (VT) {803 QT = VT->getElementType();804 BT = QT->getAs<BuiltinType>();805 VectorNumElts = OptionalAmount(VT->getNumElements());806 }807 }808 809 // We can only work with builtin types.810 if (!BT)811 return false;812 813 // Set length modifier814 switch (BT->getKind()) {815 case BuiltinType::Bool:816 case BuiltinType::WChar_U:817 case BuiltinType::WChar_S:818 case BuiltinType::Char8: // FIXME: Treat like 'char'?819 case BuiltinType::Char16:820 case BuiltinType::Char32:821 case BuiltinType::UInt128:822 case BuiltinType::Int128:823 case BuiltinType::Half:824 case BuiltinType::BFloat16:825 case BuiltinType::Float16:826 case BuiltinType::Float128:827 case BuiltinType::Ibm128:828 case BuiltinType::ShortAccum:829 case BuiltinType::Accum:830 case BuiltinType::LongAccum:831 case BuiltinType::UShortAccum:832 case BuiltinType::UAccum:833 case BuiltinType::ULongAccum:834 case BuiltinType::ShortFract:835 case BuiltinType::Fract:836 case BuiltinType::LongFract:837 case BuiltinType::UShortFract:838 case BuiltinType::UFract:839 case BuiltinType::ULongFract:840 case BuiltinType::SatShortAccum:841 case BuiltinType::SatAccum:842 case BuiltinType::SatLongAccum:843 case BuiltinType::SatUShortAccum:844 case BuiltinType::SatUAccum:845 case BuiltinType::SatULongAccum:846 case BuiltinType::SatShortFract:847 case BuiltinType::SatFract:848 case BuiltinType::SatLongFract:849 case BuiltinType::SatUShortFract:850 case BuiltinType::SatUFract:851 case BuiltinType::SatULongFract:852 // Various types which are non-trivial to correct.853 return false;854 855#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \856 case BuiltinType::Id:857#include "clang/Basic/OpenCLImageTypes.def"858#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \859 case BuiltinType::Id:860#include "clang/Basic/OpenCLExtensionTypes.def"861#define SVE_TYPE(Name, Id, SingletonId) \862 case BuiltinType::Id:863#include "clang/Basic/AArch64ACLETypes.def"864#define PPC_VECTOR_TYPE(Name, Id, Size) \865 case BuiltinType::Id:866#include "clang/Basic/PPCTypes.def"867#define RVV_TYPE(Name, Id, SingletonId) case BuiltinType::Id:868#include "clang/Basic/RISCVVTypes.def"869#define WASM_TYPE(Name, Id, SingletonId) case BuiltinType::Id:870#include "clang/Basic/WebAssemblyReferenceTypes.def"871#define AMDGPU_TYPE(Name, Id, SingletonId, Width, Align) case BuiltinType::Id:872#include "clang/Basic/AMDGPUTypes.def"873#define HLSL_INTANGIBLE_TYPE(Name, Id, SingletonId) case BuiltinType::Id:874#include "clang/Basic/HLSLIntangibleTypes.def"875#define SIGNED_TYPE(Id, SingletonId)876#define UNSIGNED_TYPE(Id, SingletonId)877#define FLOATING_TYPE(Id, SingletonId)878#define BUILTIN_TYPE(Id, SingletonId) \879 case BuiltinType::Id:880#include "clang/AST/BuiltinTypes.def"881 // Misc other stuff which doesn't make sense here.882 return false;883 884 case BuiltinType::UInt:885 case BuiltinType::Int:886 case BuiltinType::Float:887 LM.setKind(VectorNumElts.isInvalid() ?888 LengthModifier::None : LengthModifier::AsShortLong);889 break;890 case BuiltinType::Double:891 LM.setKind(VectorNumElts.isInvalid() ?892 LengthModifier::None : LengthModifier::AsLong);893 break;894 case BuiltinType::Char_U:895 case BuiltinType::UChar:896 case BuiltinType::Char_S:897 case BuiltinType::SChar:898 LM.setKind(LengthModifier::AsChar);899 break;900 901 case BuiltinType::Short:902 case BuiltinType::UShort:903 LM.setKind(LengthModifier::AsShort);904 break;905 906 case BuiltinType::Long:907 case BuiltinType::ULong:908 LM.setKind(LengthModifier::AsLong);909 break;910 911 case BuiltinType::LongLong:912 case BuiltinType::ULongLong:913 LM.setKind(LengthModifier::AsLongLong);914 break;915 916 case BuiltinType::LongDouble:917 LM.setKind(LengthModifier::AsLongDouble);918 break;919 }920 921 // Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers in C99.922 if (LangOpt.C99 || LangOpt.CPlusPlus11)923 namedTypeToLengthModifier(Ctx, QT, LM);924 925 // If fixing the length modifier was enough, we might be done.926 if (hasValidLengthModifier(Ctx.getTargetInfo(), LangOpt)) {927 // If we're going to offer a fix anyway, make sure the sign matches.928 switch (CS.getKind()) {929 case ConversionSpecifier::uArg:930 case ConversionSpecifier::UArg:931 if (QT->isSignedIntegerType())932 CS.setKind(clang::analyze_format_string::ConversionSpecifier::dArg);933 break;934 case ConversionSpecifier::dArg:935 case ConversionSpecifier::DArg:936 case ConversionSpecifier::iArg:937 if (QT->isUnsignedIntegerType() && !HasPlusPrefix)938 CS.setKind(clang::analyze_format_string::ConversionSpecifier::uArg);939 break;940 default:941 // Other specifiers do not have signed/unsigned variants.942 break;943 }944 945 const analyze_printf::ArgType &ATR = getArgType(Ctx, IsObjCLiteral);946 if (ATR.isValid() && ATR.matchesType(Ctx, QT))947 return true;948 }949 950 // Set conversion specifier and disable any flags which do not apply to it.951 // Let typedefs to char fall through to int, as %c is silly for uint8_t.952 if (!QT->getAs<TypedefType>() && QT->isCharType()) {953 CS.setKind(ConversionSpecifier::cArg);954 LM.setKind(LengthModifier::None);955 Precision.setHowSpecified(OptionalAmount::NotSpecified);956 HasAlternativeForm = false;957 HasLeadingZeroes = false;958 HasPlusPrefix = false;959 }960 // Test for Floating type first as LongDouble can pass isUnsignedIntegerType961 else if (QT->isRealFloatingType()) {962 CS.setKind(ConversionSpecifier::fArg);963 } else if (QT->isSignedIntegerType()) {964 CS.setKind(ConversionSpecifier::dArg);965 HasAlternativeForm = false;966 } else if (QT->isUnsignedIntegerType()) {967 CS.setKind(ConversionSpecifier::uArg);968 HasAlternativeForm = false;969 HasPlusPrefix = false;970 } else {971 llvm_unreachable("Unexpected type");972 }973 974 return true;975}976 977void PrintfSpecifier::toString(raw_ostream &os) const {978 // Whilst some features have no defined order, we are using the order979 // appearing in the C99 standard (ISO/IEC 9899:1999 (E) 7.19.6.1)980 os << "%";981 982 // Positional args983 if (usesPositionalArg()) {984 os << getPositionalArgIndex() << "$";985 }986 987 // Conversion flags988 if (IsLeftJustified) os << "-";989 if (HasPlusPrefix) os << "+";990 if (HasSpacePrefix) os << " ";991 if (HasAlternativeForm) os << "#";992 if (HasLeadingZeroes) os << "0";993 994 // Minimum field width995 FieldWidth.toString(os);996 // Precision997 Precision.toString(os);998 999 // Vector modifier1000 if (!VectorNumElts.isInvalid())1001 os << 'v' << VectorNumElts.getConstantAmount();1002 1003 // Length modifier1004 os << LM.toString();1005 // Conversion specifier1006 os << CS.toString();1007}1008 1009bool PrintfSpecifier::hasValidPlusPrefix() const {1010 if (!HasPlusPrefix)1011 return true;1012 1013 // The plus prefix only makes sense for signed conversions1014 switch (CS.getKind()) {1015 case ConversionSpecifier::dArg:1016 case ConversionSpecifier::DArg:1017 case ConversionSpecifier::iArg:1018 case ConversionSpecifier::fArg:1019 case ConversionSpecifier::FArg:1020 case ConversionSpecifier::eArg:1021 case ConversionSpecifier::EArg:1022 case ConversionSpecifier::gArg:1023 case ConversionSpecifier::GArg:1024 case ConversionSpecifier::aArg:1025 case ConversionSpecifier::AArg:1026 case ConversionSpecifier::FreeBSDrArg:1027 case ConversionSpecifier::FreeBSDyArg:1028 case ConversionSpecifier::rArg:1029 case ConversionSpecifier::kArg:1030 return true;1031 1032 default:1033 return false;1034 }1035}1036 1037bool PrintfSpecifier::hasValidAlternativeForm() const {1038 if (!HasAlternativeForm)1039 return true;1040 1041 // Alternate form flag only valid with the bBoxXaAeEfFgGrRkK conversions1042 switch (CS.getKind()) {1043 case ConversionSpecifier::bArg:1044 case ConversionSpecifier::BArg:1045 case ConversionSpecifier::oArg:1046 case ConversionSpecifier::OArg:1047 case ConversionSpecifier::xArg:1048 case ConversionSpecifier::XArg:1049 case ConversionSpecifier::aArg:1050 case ConversionSpecifier::AArg:1051 case ConversionSpecifier::eArg:1052 case ConversionSpecifier::EArg:1053 case ConversionSpecifier::fArg:1054 case ConversionSpecifier::FArg:1055 case ConversionSpecifier::gArg:1056 case ConversionSpecifier::GArg:1057 case ConversionSpecifier::FreeBSDrArg:1058 case ConversionSpecifier::FreeBSDyArg:1059 case ConversionSpecifier::rArg:1060 case ConversionSpecifier::RArg:1061 case ConversionSpecifier::kArg:1062 case ConversionSpecifier::KArg:1063 return true;1064 1065 default:1066 return false;1067 }1068}1069 1070bool PrintfSpecifier::hasValidLeadingZeros() const {1071 if (!HasLeadingZeroes)1072 return true;1073 1074 // Leading zeroes flag only valid with the bBdiouxXaAeEfFgGrRkK conversions1075 switch (CS.getKind()) {1076 case ConversionSpecifier::bArg:1077 case ConversionSpecifier::BArg:1078 case ConversionSpecifier::dArg:1079 case ConversionSpecifier::DArg:1080 case ConversionSpecifier::iArg:1081 case ConversionSpecifier::oArg:1082 case ConversionSpecifier::OArg:1083 case ConversionSpecifier::uArg:1084 case ConversionSpecifier::UArg:1085 case ConversionSpecifier::xArg:1086 case ConversionSpecifier::XArg:1087 case ConversionSpecifier::aArg:1088 case ConversionSpecifier::AArg:1089 case ConversionSpecifier::eArg:1090 case ConversionSpecifier::EArg:1091 case ConversionSpecifier::fArg:1092 case ConversionSpecifier::FArg:1093 case ConversionSpecifier::gArg:1094 case ConversionSpecifier::GArg:1095 case ConversionSpecifier::FreeBSDrArg:1096 case ConversionSpecifier::FreeBSDyArg:1097 case ConversionSpecifier::rArg:1098 case ConversionSpecifier::RArg:1099 case ConversionSpecifier::kArg:1100 case ConversionSpecifier::KArg:1101 return true;1102 1103 default:1104 return false;1105 }1106}1107 1108bool PrintfSpecifier::hasValidSpacePrefix() const {1109 if (!HasSpacePrefix)1110 return true;1111 1112 // The space prefix only makes sense for signed conversions1113 switch (CS.getKind()) {1114 case ConversionSpecifier::dArg:1115 case ConversionSpecifier::DArg:1116 case ConversionSpecifier::iArg:1117 case ConversionSpecifier::fArg:1118 case ConversionSpecifier::FArg:1119 case ConversionSpecifier::eArg:1120 case ConversionSpecifier::EArg:1121 case ConversionSpecifier::gArg:1122 case ConversionSpecifier::GArg:1123 case ConversionSpecifier::aArg:1124 case ConversionSpecifier::AArg:1125 case ConversionSpecifier::FreeBSDrArg:1126 case ConversionSpecifier::FreeBSDyArg:1127 case ConversionSpecifier::rArg:1128 case ConversionSpecifier::kArg:1129 return true;1130 1131 default:1132 return false;1133 }1134}1135 1136bool PrintfSpecifier::hasValidLeftJustified() const {1137 if (!IsLeftJustified)1138 return true;1139 1140 // The left justified flag is valid for all conversions except n1141 switch (CS.getKind()) {1142 case ConversionSpecifier::nArg:1143 return false;1144 1145 default:1146 return true;1147 }1148}1149 1150bool PrintfSpecifier::hasValidThousandsGroupingPrefix() const {1151 if (!HasThousandsGrouping)1152 return true;1153 1154 switch (CS.getKind()) {1155 case ConversionSpecifier::dArg:1156 case ConversionSpecifier::DArg:1157 case ConversionSpecifier::iArg:1158 case ConversionSpecifier::uArg:1159 case ConversionSpecifier::UArg:1160 case ConversionSpecifier::fArg:1161 case ConversionSpecifier::FArg:1162 case ConversionSpecifier::gArg:1163 case ConversionSpecifier::GArg:1164 return true;1165 default:1166 return false;1167 }1168}1169 1170bool PrintfSpecifier::hasValidPrecision() const {1171 if (Precision.getHowSpecified() == OptionalAmount::NotSpecified)1172 return true;1173 1174 // Precision is only valid with the bBdiouxXaAeEfFgGsPrRkK conversions1175 switch (CS.getKind()) {1176 case ConversionSpecifier::bArg:1177 case ConversionSpecifier::BArg:1178 case ConversionSpecifier::dArg:1179 case ConversionSpecifier::DArg:1180 case ConversionSpecifier::iArg:1181 case ConversionSpecifier::oArg:1182 case ConversionSpecifier::OArg:1183 case ConversionSpecifier::uArg:1184 case ConversionSpecifier::UArg:1185 case ConversionSpecifier::xArg:1186 case ConversionSpecifier::XArg:1187 case ConversionSpecifier::aArg:1188 case ConversionSpecifier::AArg:1189 case ConversionSpecifier::eArg:1190 case ConversionSpecifier::EArg:1191 case ConversionSpecifier::fArg:1192 case ConversionSpecifier::FArg:1193 case ConversionSpecifier::gArg:1194 case ConversionSpecifier::GArg:1195 case ConversionSpecifier::sArg:1196 case ConversionSpecifier::FreeBSDrArg:1197 case ConversionSpecifier::FreeBSDyArg:1198 case ConversionSpecifier::PArg:1199 case ConversionSpecifier::rArg:1200 case ConversionSpecifier::RArg:1201 case ConversionSpecifier::kArg:1202 case ConversionSpecifier::KArg:1203 return true;1204 1205 default:1206 return false;1207 }1208}1209bool PrintfSpecifier::hasValidFieldWidth() const {1210 if (FieldWidth.getHowSpecified() == OptionalAmount::NotSpecified)1211 return true;1212 1213 // The field width is valid for all conversions except n1214 switch (CS.getKind()) {1215 case ConversionSpecifier::nArg:1216 return false;1217 1218 default:1219 return true;1220 }1221}1222