brintos

brintos / llvm-project-archived public Read only

0
0
Text · 18.8 KiB · 41cf71a Raw
573 lines · cpp
1//= ScanfFormatString.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 scanf and friends.  The structure of format10// strings for fscanf() are described in C99 7.19.6.2.11//12//===----------------------------------------------------------------------===//13 14#include "clang/AST/FormatString.h"15#include "FormatStringParsing.h"16#include "clang/Basic/TargetInfo.h"17 18using clang::analyze_format_string::ArgType;19using clang::analyze_format_string::FormatStringHandler;20using clang::analyze_format_string::LengthModifier;21using clang::analyze_format_string::OptionalAmount;22using clang::analyze_format_string::ConversionSpecifier;23using clang::analyze_scanf::ScanfConversionSpecifier;24using clang::analyze_scanf::ScanfSpecifier;25using clang::UpdateOnReturn;26using namespace clang;27 28typedef clang::analyze_format_string::SpecifierResult<ScanfSpecifier>29        ScanfSpecifierResult;30 31static bool ParseScanList(FormatStringHandler &H,32                          ScanfConversionSpecifier &CS,33                          const char *&Beg, const char *E) {34  const char *I = Beg;35  const char *start = I - 1;36  UpdateOnReturn <const char*> UpdateBeg(Beg, I);37 38  // No more characters?39  if (I == E) {40    H.HandleIncompleteScanList(start, I);41    return true;42  }43 44  // Special case: ']' is the first character.45  if (*I == ']') {46    if (++I == E) {47      H.HandleIncompleteScanList(start, I - 1);48      return true;49    }50  }51 52  // Special case: "^]" are the first characters.53  if (I + 1 != E && I[0] == '^' && I[1] == ']') {54    I += 2;55    if (I == E) {56      H.HandleIncompleteScanList(start, I - 1);57      return true;58    }59  }60 61  // Look for a ']' character which denotes the end of the scan list.62  while (*I != ']') {63    if (++I == E) {64      H.HandleIncompleteScanList(start, I - 1);65      return true;66    }67  }68 69  CS.setEndScanList(I);70  return false;71}72 73// FIXME: Much of this is copy-paste from ParsePrintfSpecifier.74// We can possibly refactor.75static ScanfSpecifierResult ParseScanfSpecifier(FormatStringHandler &H,76                                                const char *&Beg,77                                                const char *E,78                                                unsigned &argIndex,79                                                const LangOptions &LO,80                                                const TargetInfo &Target) {81  using namespace clang::analyze_format_string;82  using namespace clang::analyze_scanf;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    H.HandleIncompleteSpecifier(Start, E - Start);108    return true;109  }110 111  ScanfSpecifier FS;112  if (ParseArgPosition(H, FS, Start, I, E))113    return true;114 115  if (I == E) {116      // No more characters left?117    H.HandleIncompleteSpecifier(Start, E - Start);118    return true;119  }120 121  // Look for '*' flag if it is present.122  if (*I == '*') {123    FS.setSuppressAssignment(I);124    if (++I == E) {125      H.HandleIncompleteSpecifier(Start, E - Start);126      return true;127    }128  }129 130  // Look for the field width (if any).  Unlike printf, this is either131  // a fixed integer or isn't present.132  const OptionalAmount &Amt = clang::analyze_format_string::ParseAmount(I, E);133  if (Amt.getHowSpecified() != OptionalAmount::NotSpecified) {134    assert(Amt.getHowSpecified() == OptionalAmount::Constant);135    FS.setFieldWidth(Amt);136 137    if (I == E) {138      // No more characters left?139      H.HandleIncompleteSpecifier(Start, E - Start);140      return true;141    }142  }143 144  // Look for the length modifier.145  if (ParseLengthModifier(FS, I, E, LO, /*IsScanf=*/true) && I == E) {146      // No more characters left?147    H.HandleIncompleteSpecifier(Start, E - Start);148    return true;149  }150 151  // Detect spurious null characters, which are likely errors.152  if (*I == '\0') {153    H.HandleNullChar(I);154    return true;155  }156 157  // Finally, look for the conversion specifier.158  const char *conversionPosition = I++;159  ScanfConversionSpecifier::Kind k = ScanfConversionSpecifier::InvalidSpecifier;160  switch (*conversionPosition) {161    default:162      break;163    case '%': k = ConversionSpecifier::PercentArg;   break;164    case 'b': k = ConversionSpecifier::bArg; break;165    case 'A': k = ConversionSpecifier::AArg; break;166    case 'E': k = ConversionSpecifier::EArg; break;167    case 'F': k = ConversionSpecifier::FArg; break;168    case 'G': k = ConversionSpecifier::GArg; break;169    case 'X': k = ConversionSpecifier::XArg; break;170    case 'a': k = ConversionSpecifier::aArg; break;171    case 'd': k = ConversionSpecifier::dArg; break;172    case 'e': k = ConversionSpecifier::eArg; break;173    case 'f': k = ConversionSpecifier::fArg; break;174    case 'g': k = ConversionSpecifier::gArg; break;175    case 'i': k = ConversionSpecifier::iArg; break;176    case 'n': k = ConversionSpecifier::nArg; break;177    case 'c': k = ConversionSpecifier::cArg; break;178    case 'C': k = ConversionSpecifier::CArg; break;179    case 'S': k = ConversionSpecifier::SArg; break;180    case '[': k = ConversionSpecifier::ScanListArg; break;181    case 'u': k = ConversionSpecifier::uArg; break;182    case 'x': k = ConversionSpecifier::xArg; break;183    case 'o': k = ConversionSpecifier::oArg; break;184    case 's': k = ConversionSpecifier::sArg; break;185    case 'p': k = ConversionSpecifier::pArg; break;186    // Apple extensions187      // Apple-specific188    case 'D':189      if (Target.getTriple().isOSDarwin())190        k = ConversionSpecifier::DArg;191      break;192    case 'O':193      if (Target.getTriple().isOSDarwin())194        k = ConversionSpecifier::OArg;195      break;196    case 'U':197      if (Target.getTriple().isOSDarwin())198        k = ConversionSpecifier::UArg;199      break;200  }201  ScanfConversionSpecifier CS(conversionPosition, k);202  if (k == ScanfConversionSpecifier::ScanListArg) {203    if (ParseScanList(H, CS, I, E))204      return true;205  }206  FS.setConversionSpecifier(CS);207  if (CS.consumesDataArgument() && !FS.getSuppressAssignment()208      && !FS.usesPositionalArg())209    FS.setArgIndex(argIndex++);210 211  // FIXME: '%' and '*' doesn't make sense.  Issue a warning.212  // FIXME: 'ConsumedSoFar' and '*' doesn't make sense.213 214  if (k == ScanfConversionSpecifier::InvalidSpecifier) {215    unsigned Len = I - Beg;216    if (ParseUTF8InvalidSpecifier(Beg, E, Len)) {217      CS.setEndScanList(Beg + Len);218      FS.setConversionSpecifier(CS);219    }220    // Assume the conversion takes one argument.221    return !H.HandleInvalidScanfConversionSpecifier(FS, Beg, Len);222  }223  return ScanfSpecifierResult(Start, FS);224}225 226ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const {227  const ScanfConversionSpecifier &CS = getConversionSpecifier();228 229  if (!CS.consumesDataArgument())230    return ArgType::Invalid();231 232  switch(CS.getKind()) {233    // Signed int.234    case ConversionSpecifier::dArg:235    case ConversionSpecifier::DArg:236    case ConversionSpecifier::iArg:237      switch (LM.getKind()) {238        case LengthModifier::None:239          return ArgType::PtrTo(Ctx.IntTy);240        case LengthModifier::AsChar:241          return ArgType::PtrTo(ArgType::AnyCharTy);242        case LengthModifier::AsShort:243          return ArgType::PtrTo(Ctx.ShortTy);244        case LengthModifier::AsLong:245          return ArgType::PtrTo(Ctx.LongTy);246        case LengthModifier::AsLongLong:247        case LengthModifier::AsQuad:248          return ArgType::PtrTo(Ctx.LongLongTy);249        case LengthModifier::AsInt64:250          return ArgType::PtrTo(ArgType(Ctx.LongLongTy, "__int64"));251        case LengthModifier::AsIntMax:252          return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t"));253        case LengthModifier::AsSizeT:254          return ArgType::PtrTo(ArgType::makeSizeT(255              ArgType(Ctx.getSignedSizeType(), "signed size_t")));256        case LengthModifier::AsPtrDiff:257          return ArgType::PtrTo(ArgType::makePtrdiffT(258              ArgType(Ctx.getPointerDiffType(), "ptrdiff_t")));259        case LengthModifier::AsLongDouble:260          // GNU extension.261          return ArgType::PtrTo(Ctx.LongLongTy);262        case LengthModifier::AsAllocate:263        case LengthModifier::AsMAllocate:264        case LengthModifier::AsInt32:265        case LengthModifier::AsInt3264:266        case LengthModifier::AsWide:267        case LengthModifier::AsShortLong:268          return ArgType::Invalid();269      }270      llvm_unreachable("Unsupported LengthModifier Type");271 272    // Unsigned int.273    case ConversionSpecifier::bArg:274    case ConversionSpecifier::oArg:275    case ConversionSpecifier::OArg:276    case ConversionSpecifier::uArg:277    case ConversionSpecifier::UArg:278    case ConversionSpecifier::xArg:279    case ConversionSpecifier::XArg:280      switch (LM.getKind()) {281        case LengthModifier::None:282          return ArgType::PtrTo(Ctx.UnsignedIntTy);283        case LengthModifier::AsChar:284          return ArgType::PtrTo(Ctx.UnsignedCharTy);285        case LengthModifier::AsShort:286          return ArgType::PtrTo(Ctx.UnsignedShortTy);287        case LengthModifier::AsLong:288          return ArgType::PtrTo(Ctx.UnsignedLongTy);289        case LengthModifier::AsLongLong:290        case LengthModifier::AsQuad:291          return ArgType::PtrTo(Ctx.UnsignedLongLongTy);292        case LengthModifier::AsInt64:293          return ArgType::PtrTo(ArgType(Ctx.UnsignedLongLongTy, "unsigned __int64"));294        case LengthModifier::AsIntMax:295          return ArgType::PtrTo(ArgType(Ctx.getUIntMaxType(), "uintmax_t"));296        case LengthModifier::AsSizeT:297          return ArgType::PtrTo(298              ArgType::makeSizeT(ArgType(Ctx.getSizeType(), "size_t")));299        case LengthModifier::AsPtrDiff:300          return ArgType::PtrTo(ArgType::makePtrdiffT(301              ArgType(Ctx.getUnsignedPointerDiffType(), "unsigned ptrdiff_t")));302        case LengthModifier::AsLongDouble:303          // GNU extension.304          return ArgType::PtrTo(Ctx.UnsignedLongLongTy);305        case LengthModifier::AsAllocate:306        case LengthModifier::AsMAllocate:307        case LengthModifier::AsInt32:308        case LengthModifier::AsInt3264:309        case LengthModifier::AsWide:310        case LengthModifier::AsShortLong:311          return ArgType::Invalid();312      }313      llvm_unreachable("Unsupported LengthModifier Type");314 315    // Float.316    case ConversionSpecifier::aArg:317    case ConversionSpecifier::AArg:318    case ConversionSpecifier::eArg:319    case ConversionSpecifier::EArg:320    case ConversionSpecifier::fArg:321    case ConversionSpecifier::FArg:322    case ConversionSpecifier::gArg:323    case ConversionSpecifier::GArg:324      switch (LM.getKind()) {325        case LengthModifier::None:326          return ArgType::PtrTo(Ctx.FloatTy);327        case LengthModifier::AsLong:328          return ArgType::PtrTo(Ctx.DoubleTy);329        case LengthModifier::AsLongDouble:330          return ArgType::PtrTo(Ctx.LongDoubleTy);331        default:332          return ArgType::Invalid();333      }334 335    // Char, string and scanlist.336    case ConversionSpecifier::cArg:337    case ConversionSpecifier::sArg:338    case ConversionSpecifier::ScanListArg:339      switch (LM.getKind()) {340        case LengthModifier::None:341          return ArgType::PtrTo(ArgType::AnyCharTy);342        case LengthModifier::AsLong:343        case LengthModifier::AsWide:344          return ArgType::PtrTo(ArgType(Ctx.getWideCharType(), "wchar_t"));345        case LengthModifier::AsAllocate:346        case LengthModifier::AsMAllocate:347          return ArgType::PtrTo(ArgType::CStrTy);348        case LengthModifier::AsShort:349          if (Ctx.getTargetInfo().getTriple().isOSMSVCRT())350            return ArgType::PtrTo(ArgType::AnyCharTy);351          [[fallthrough]];352        default:353          return ArgType::Invalid();354      }355    case ConversionSpecifier::CArg:356    case ConversionSpecifier::SArg:357      // FIXME: Mac OS X specific?358      switch (LM.getKind()) {359        case LengthModifier::None:360        case LengthModifier::AsWide:361          return ArgType::PtrTo(ArgType(Ctx.getWideCharType(), "wchar_t"));362        case LengthModifier::AsAllocate:363        case LengthModifier::AsMAllocate:364          return ArgType::PtrTo(ArgType(ArgType::WCStrTy, "wchar_t *"));365        case LengthModifier::AsShort:366          if (Ctx.getTargetInfo().getTriple().isOSMSVCRT())367            return ArgType::PtrTo(ArgType::AnyCharTy);368          [[fallthrough]];369        default:370          return ArgType::Invalid();371      }372 373    // Pointer.374    case ConversionSpecifier::pArg:375      return ArgType::PtrTo(ArgType::CPointerTy);376 377    // Write-back.378    case ConversionSpecifier::nArg:379      switch (LM.getKind()) {380        case LengthModifier::None:381          return ArgType::PtrTo(Ctx.IntTy);382        case LengthModifier::AsChar:383          return ArgType::PtrTo(Ctx.SignedCharTy);384        case LengthModifier::AsShort:385          return ArgType::PtrTo(Ctx.ShortTy);386        case LengthModifier::AsLong:387          return ArgType::PtrTo(Ctx.LongTy);388        case LengthModifier::AsLongLong:389        case LengthModifier::AsQuad:390          return ArgType::PtrTo(Ctx.LongLongTy);391        case LengthModifier::AsInt64:392          return ArgType::PtrTo(ArgType(Ctx.LongLongTy, "__int64"));393        case LengthModifier::AsIntMax:394          return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t"));395        case LengthModifier::AsSizeT:396          return ArgType::PtrTo(ArgType::makeSizeT(397              ArgType(Ctx.getSignedSizeType(), "signed size_t")));398        case LengthModifier::AsPtrDiff:399          return ArgType::PtrTo(ArgType::makePtrdiffT(400              ArgType(Ctx.getPointerDiffType(), "ptrdiff_t")));401        case LengthModifier::AsLongDouble:402          return ArgType(); // FIXME: Is this a known extension?403        case LengthModifier::AsAllocate:404        case LengthModifier::AsMAllocate:405        case LengthModifier::AsInt32:406        case LengthModifier::AsInt3264:407        case LengthModifier::AsWide:408        case LengthModifier::AsShortLong:409          return ArgType::Invalid();410        }411 412    default:413      break;414  }415 416  return ArgType();417}418 419bool ScanfSpecifier::fixType(QualType QT, QualType RawQT,420                             const LangOptions &LangOpt,421                             ASTContext &Ctx) {422 423  // %n is different from other conversion specifiers; don't try to fix it.424  if (CS.getKind() == ConversionSpecifier::nArg)425    return false;426 427  if (!QT->isPointerType())428    return false;429 430  QualType PT = QT->getPointeeType();431 432  // If it's an enum, get its underlying type.433  if (const auto *ED = PT->getAsEnumDecl()) {434    // Don't try to fix incomplete enums.435    if (!ED->isComplete())436      return false;437    PT = ED->getIntegerType();438  }439 440  const BuiltinType *BT = PT->getAs<BuiltinType>();441  if (!BT)442    return false;443 444  // Pointer to a character.445  if (PT->isAnyCharacterType()) {446    CS.setKind(ConversionSpecifier::sArg);447    if (PT->isWideCharType())448      LM.setKind(LengthModifier::AsWideChar);449    else450      LM.setKind(LengthModifier::None);451 452    // If we know the target array length, we can use it as a field width.453    if (const ConstantArrayType *CAT = Ctx.getAsConstantArrayType(RawQT)) {454      if (CAT->getSizeModifier() == ArraySizeModifier::Normal)455        FieldWidth = OptionalAmount(OptionalAmount::Constant,456                                    CAT->getZExtSize() - 1, "", 0, false);457    }458    return true;459  }460 461  // Figure out the length modifier.462  switch (BT->getKind()) {463    // no modifier464    case BuiltinType::UInt:465    case BuiltinType::Int:466    case BuiltinType::Float:467      LM.setKind(LengthModifier::None);468      break;469 470    // hh471    case BuiltinType::Char_U:472    case BuiltinType::UChar:473    case BuiltinType::Char_S:474    case BuiltinType::SChar:475      LM.setKind(LengthModifier::AsChar);476      break;477 478    // h479    case BuiltinType::Short:480    case BuiltinType::UShort:481      LM.setKind(LengthModifier::AsShort);482      break;483 484    // l485    case BuiltinType::Long:486    case BuiltinType::ULong:487    case BuiltinType::Double:488      LM.setKind(LengthModifier::AsLong);489      break;490 491    // ll492    case BuiltinType::LongLong:493    case BuiltinType::ULongLong:494      LM.setKind(LengthModifier::AsLongLong);495      break;496 497    // L498    case BuiltinType::LongDouble:499      LM.setKind(LengthModifier::AsLongDouble);500      break;501 502    // Don't know.503    default:504      return false;505  }506 507  // Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers in C99.508  if (LangOpt.C99 || LangOpt.CPlusPlus11)509    namedTypeToLengthModifier(Ctx, PT, LM);510 511  // If fixing the length modifier was enough, we are done.512  if (hasValidLengthModifier(Ctx.getTargetInfo(), LangOpt)) {513    const analyze_scanf::ArgType &AT = getArgType(Ctx);514    if (AT.isValid() && AT.matchesType(Ctx, QT))515      return true;516  }517 518  // Figure out the conversion specifier.519  if (PT->isRealFloatingType())520    CS.setKind(ConversionSpecifier::fArg);521  else if (PT->isSignedIntegerType())522    CS.setKind(ConversionSpecifier::dArg);523  else if (PT->isUnsignedIntegerType())524    CS.setKind(ConversionSpecifier::uArg);525  else526    llvm_unreachable("Unexpected type");527 528  return true;529}530 531void ScanfSpecifier::toString(raw_ostream &os) const {532  os << "%";533 534  if (usesPositionalArg())535    os << getPositionalArgIndex() << "$";536  if (SuppressAssignment)537    os << "*";538 539  FieldWidth.toString(os);540  os << LM.toString();541  os << CS.toString();542}543 544bool clang::analyze_format_string::ParseScanfString(FormatStringHandler &H,545                                                    const char *I,546                                                    const char *E,547                                                    const LangOptions &LO,548                                                    const TargetInfo &Target) {549 550  unsigned argIndex = 0;551 552  // Keep looking for a format specifier until we have exhausted the string.553  while (I != E) {554    const ScanfSpecifierResult &FSR = ParseScanfSpecifier(H, I, E, argIndex,555                                                          LO, Target);556    // Did a fail-stop error of any kind occur when parsing the specifier?557    // If so, don't do any more processing.558    if (FSR.shouldStop())559      return true;560      // Did we exhaust the string or encounter an error that561      // we can recover from?562    if (!FSR.hasValue())563      continue;564      // We have a format specifier.  Pass it to the callback.565    if (!H.HandleScanfSpecifier(FSR.getValue(), FSR.getStart(),566                                I - FSR.getStart())) {567      return true;568    }569  }570  assert(I == E && "Format string not exhausted");571  return false;572}573