brintos

brintos / llvm-project-archived public Read only

0
0
Text · 39.1 KiB · 8555504 Raw
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