Home | History | Annotate | Line # | Download | only in AST
      1 //= FormatString.h - Analysis of printf/fprintf 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-exception
      6 //
      7 //===----------------------------------------------------------------------===//
      8 //
      9 // This file defines APIs for analyzing the format strings of printf, fscanf,
     10 // and friends.
     11 //
     12 // The structure of format strings for fprintf are described in C99 7.19.6.1.
     13 //
     14 // The structure of format strings for fscanf are described in C99 7.19.6.2.
     15 //
     16 //===----------------------------------------------------------------------===//
     17 
     18 #ifndef LLVM_CLANG_ANALYSIS_ANALYSES_FORMATSTRING_H
     19 #define LLVM_CLANG_ANALYSIS_ANALYSES_FORMATSTRING_H
     20 
     21 #include "clang/AST/CanonicalType.h"
     22 
     23 namespace clang {
     24 
     25 class TargetInfo;
     26 
     27 //===----------------------------------------------------------------------===//
     28 /// Common components of both fprintf and fscanf format strings.
     29 namespace analyze_format_string {
     30 
     31 /// Class representing optional flags with location and representation
     32 /// information.
     33 class OptionalFlag {
     34 public:
     35   OptionalFlag(const char *Representation)
     36       : representation(Representation), flag(false) {}
     37   bool isSet() const { return flag; }
     38   void set() { flag = true; }
     39   void clear() { flag = false; }
     40   void setPosition(const char *position) {
     41     assert(position);
     42     flag = true;
     43     this->position = position;
     44   }
     45   const char *getPosition() const {
     46     assert(position);
     47     return position;
     48   }
     49   const char *toString() const { return representation; }
     50 
     51   // Overloaded operators for bool like qualities
     52   explicit operator bool() const { return flag; }
     53   OptionalFlag& operator=(const bool &rhs) {
     54     flag = rhs;
     55     return *this;  // Return a reference to myself.
     56   }
     57 private:
     58   const char *representation;
     59   const char *position;
     60   bool flag;
     61 };
     62 
     63 /// Represents the length modifier in a format string in scanf/printf.
     64 class LengthModifier {
     65 public:
     66   enum Kind {
     67     None,
     68     AsChar,       // 'hh'
     69     AsShort,      // 'h'
     70     AsShortLong,  // 'hl' (OpenCL float/int vector element)
     71     AsLong,       // 'l'
     72     AsLongLong,   // 'll'
     73     AsQuad,       // 'q' (BSD, deprecated, for 64-bit integer types)
     74     AsIntMax,     // 'j'
     75     AsSizeT,      // 'z'
     76     AsPtrDiff,    // 't'
     77     AsInt32,      // 'I32' (MSVCRT, like __int32)
     78     AsInt3264,    // 'I'   (MSVCRT, like __int3264 from MIDL)
     79     AsInt64,      // 'I64' (MSVCRT, like __int64)
     80     AsLongDouble, // 'L'
     81     AsAllocate,   // for '%as', GNU extension to C90 scanf
     82     AsMAllocate,  // for '%ms', GNU extension to scanf
     83     AsWide,       // 'w' (MSVCRT, like l but only for c, C, s, S, or Z
     84     AsWideChar = AsLong // for '%ls', only makes sense for printf
     85   };
     86 
     87   LengthModifier()
     88     : Position(nullptr), kind(None) {}
     89   LengthModifier(const char *pos, Kind k)
     90     : Position(pos), kind(k) {}
     91 
     92   const char *getStart() const {
     93     return Position;
     94   }
     95 
     96   unsigned getLength() const {
     97     switch (kind) {
     98       default:
     99         return 1;
    100       case AsLongLong:
    101       case AsChar:
    102         return 2;
    103       case AsInt32:
    104       case AsInt64:
    105         return 3;
    106       case None:
    107         return 0;
    108     }
    109   }
    110 
    111   Kind getKind() const { return kind; }
    112   void setKind(Kind k) { kind = k; }
    113 
    114   const char *toString() const;
    115 
    116 private:
    117   const char *Position;
    118   Kind kind;
    119 };
    120 
    121 class ConversionSpecifier {
    122 public:
    123   enum Kind {
    124     InvalidSpecifier = 0,
    125     // C99 conversion specifiers.
    126     cArg,
    127     dArg,
    128     DArg, // Apple extension
    129     iArg,
    130     IntArgBeg = dArg,
    131     IntArgEnd = iArg,
    132 
    133     oArg,
    134     OArg, // Apple extension
    135     uArg,
    136     UArg, // Apple extension
    137     xArg,
    138     XArg,
    139     UIntArgBeg = oArg,
    140     UIntArgEnd = XArg,
    141 
    142     fArg,
    143     FArg,
    144     eArg,
    145     EArg,
    146     gArg,
    147     GArg,
    148     aArg,
    149     AArg,
    150     DoubleArgBeg = fArg,
    151     DoubleArgEnd = AArg,
    152 
    153     sArg,
    154     pArg,
    155     nArg,
    156     PercentArg,
    157     CArg,
    158     SArg,
    159 
    160     // Apple extension: P specifies to os_log that the data being pointed to is
    161     // to be copied by os_log. The precision indicates the number of bytes to
    162     // copy.
    163     PArg,
    164 
    165     // ** Printf-specific **
    166 
    167     ZArg, // MS extension
    168 
    169     // Objective-C specific specifiers.
    170     ObjCObjArg, // '@'
    171     ObjCBeg = ObjCObjArg,
    172     ObjCEnd = ObjCObjArg,
    173 
    174     // FreeBSD kernel specific specifiers.
    175     FreeBSDbArg,
    176     FreeBSDDArg,
    177     FreeBSDrArg,
    178     FreeBSDyArg,
    179 
    180     // GlibC specific specifiers.
    181     PrintErrno, // 'm'
    182 
    183     PrintfConvBeg = ObjCObjArg,
    184     PrintfConvEnd = PrintErrno,
    185 
    186     // ** Scanf-specific **
    187     ScanListArg, // '['
    188     ScanfConvBeg = ScanListArg,
    189     ScanfConvEnd = ScanListArg
    190   };
    191 
    192   ConversionSpecifier(bool isPrintf = true)
    193     : IsPrintf(isPrintf), Position(nullptr), EndScanList(nullptr),
    194       kind(InvalidSpecifier) {}
    195 
    196   ConversionSpecifier(bool isPrintf, const char *pos, Kind k)
    197     : IsPrintf(isPrintf), Position(pos), EndScanList(nullptr), kind(k) {}
    198 
    199   const char *getStart() const {
    200     return Position;
    201   }
    202 
    203   StringRef getCharacters() const {
    204     return StringRef(getStart(), getLength());
    205   }
    206 
    207   bool consumesDataArgument() const {
    208     switch (kind) {
    209       case PrintErrno:
    210         assert(IsPrintf);
    211         return false;
    212       case PercentArg:
    213         return false;
    214       case InvalidSpecifier:
    215         return false;
    216       default:
    217         return true;
    218     }
    219   }
    220 
    221   Kind getKind() const { return kind; }
    222   void setKind(Kind k) { kind = k; }
    223   unsigned getLength() const {
    224     return EndScanList ? EndScanList - Position : 1;
    225   }
    226   void setEndScanList(const char *pos) { EndScanList = pos; }
    227 
    228   bool isIntArg() const { return (kind >= IntArgBeg && kind <= IntArgEnd) ||
    229     kind == FreeBSDrArg || kind == FreeBSDyArg; }
    230   bool isUIntArg() const { return kind >= UIntArgBeg && kind <= UIntArgEnd; }
    231   bool isAnyIntArg() const { return kind >= IntArgBeg && kind <= UIntArgEnd; }
    232   bool isDoubleArg() const {
    233     return kind >= DoubleArgBeg && kind <= DoubleArgEnd;
    234   }
    235 
    236   const char *toString() const;
    237 
    238   bool isPrintfKind() const { return IsPrintf; }
    239 
    240   Optional<ConversionSpecifier> getStandardSpecifier() const;
    241 
    242 protected:
    243   bool IsPrintf;
    244   const char *Position;
    245   const char *EndScanList;
    246   Kind kind;
    247 };
    248 
    249 class ArgType {
    250 public:
    251   enum Kind { UnknownTy, InvalidTy, SpecificTy, ObjCPointerTy, CPointerTy,
    252               AnyCharTy, CStrTy, WCStrTy, WIntTy };
    253 
    254   /// How well a given conversion specifier matches its argument.
    255   enum MatchKind {
    256     /// The conversion specifier and the argument types are incompatible. For
    257     /// instance, "%d" and float.
    258     NoMatch = 0,
    259     /// The conversion specifier and the argument type are compatible. For
    260     /// instance, "%d" and _Bool.
    261     Match = 1,
    262     /// The conversion specifier and the argument type are disallowed by the C
    263     /// standard, but are in practice harmless. For instance, "%p" and int*.
    264     NoMatchPedantic,
    265     /// The conversion specifier and the argument type are compatible, but still
    266     /// seems likely to be an error. For instance, "%hd" and _Bool.
    267     NoMatchTypeConfusion,
    268   };
    269 
    270 private:
    271   const Kind K;
    272   QualType T;
    273   const char *Name = nullptr;
    274   bool Ptr = false;
    275 
    276   /// The TypeKind identifies certain well-known types like size_t and
    277   /// ptrdiff_t.
    278   enum class TypeKind { DontCare, SizeT, PtrdiffT };
    279   TypeKind TK = TypeKind::DontCare;
    280 
    281 public:
    282   ArgType(Kind K = UnknownTy, const char *N = nullptr) : K(K), Name(N) {}
    283   ArgType(QualType T, const char *N = nullptr) : K(SpecificTy), T(T), Name(N) {}
    284   ArgType(CanQualType T) : K(SpecificTy), T(T) {}
    285 
    286   static ArgType Invalid() { return ArgType(InvalidTy); }
    287   bool isValid() const { return K != InvalidTy; }
    288 
    289   bool isSizeT() const { return TK == TypeKind::SizeT; }
    290 
    291   bool isPtrdiffT() const { return TK == TypeKind::PtrdiffT; }
    292 
    293   /// Create an ArgType which corresponds to the type pointer to A.
    294   static ArgType PtrTo(const ArgType& A) {
    295     assert(A.K >= InvalidTy && "ArgType cannot be pointer to invalid/unknown");
    296     ArgType Res = A;
    297     Res.Ptr = true;
    298     return Res;
    299   }
    300 
    301   /// Create an ArgType which corresponds to the size_t/ssize_t type.
    302   static ArgType makeSizeT(const ArgType &A) {
    303     ArgType Res = A;
    304     Res.TK = TypeKind::SizeT;
    305     return Res;
    306   }
    307 
    308   /// Create an ArgType which corresponds to the ptrdiff_t/unsigned ptrdiff_t
    309   /// type.
    310   static ArgType makePtrdiffT(const ArgType &A) {
    311     ArgType Res = A;
    312     Res.TK = TypeKind::PtrdiffT;
    313     return Res;
    314   }
    315 
    316   MatchKind matchesType(ASTContext &C, QualType argTy) const;
    317 
    318   QualType getRepresentativeType(ASTContext &C) const;
    319 
    320   ArgType makeVectorType(ASTContext &C, unsigned NumElts) const;
    321 
    322   std::string getRepresentativeTypeName(ASTContext &C) const;
    323 };
    324 
    325 class OptionalAmount {
    326 public:
    327   enum HowSpecified { NotSpecified, Constant, Arg, Invalid };
    328 
    329   OptionalAmount(HowSpecified howSpecified,
    330                  unsigned amount,
    331                  const char *amountStart,
    332                  unsigned amountLength,
    333                  bool usesPositionalArg)
    334   : start(amountStart), length(amountLength), hs(howSpecified), amt(amount),
    335   UsesPositionalArg(usesPositionalArg), UsesDotPrefix(0) {}
    336 
    337   OptionalAmount(bool valid = true)
    338   : start(nullptr),length(0), hs(valid ? NotSpecified : Invalid), amt(0),
    339   UsesPositionalArg(0), UsesDotPrefix(0) {}
    340 
    341   explicit OptionalAmount(unsigned Amount)
    342     : start(nullptr), length(0), hs(Constant), amt(Amount),
    343     UsesPositionalArg(false), UsesDotPrefix(false) {}
    344 
    345   bool isInvalid() const {
    346     return hs == Invalid;
    347   }
    348 
    349   HowSpecified getHowSpecified() const { return hs; }
    350   void setHowSpecified(HowSpecified h) { hs = h; }
    351 
    352   bool hasDataArgument() const { return hs == Arg; }
    353 
    354   unsigned getArgIndex() const {
    355     assert(hasDataArgument());
    356     return amt;
    357   }
    358 
    359   unsigned getConstantAmount() const {
    360     assert(hs == Constant);
    361     return amt;
    362   }
    363 
    364   const char *getStart() const {
    365       // We include the . character if it is given.
    366     return start - UsesDotPrefix;
    367   }
    368 
    369   unsigned getConstantLength() const {
    370     assert(hs == Constant);
    371     return length + UsesDotPrefix;
    372   }
    373 
    374   ArgType getArgType(ASTContext &Ctx) const;
    375 
    376   void toString(raw_ostream &os) const;
    377 
    378   bool usesPositionalArg() const { return (bool) UsesPositionalArg; }
    379   unsigned getPositionalArgIndex() const {
    380     assert(hasDataArgument());
    381     return amt + 1;
    382   }
    383 
    384   bool usesDotPrefix() const { return UsesDotPrefix; }
    385   void setUsesDotPrefix() { UsesDotPrefix = true; }
    386 
    387 private:
    388   const char *start;
    389   unsigned length;
    390   HowSpecified hs;
    391   unsigned amt;
    392   bool UsesPositionalArg : 1;
    393   bool UsesDotPrefix;
    394 };
    395 
    396 
    397 class FormatSpecifier {
    398 protected:
    399   LengthModifier LM;
    400   OptionalAmount FieldWidth;
    401   ConversionSpecifier CS;
    402   OptionalAmount VectorNumElts;
    403 
    404   /// Positional arguments, an IEEE extension:
    405   ///  IEEE Std 1003.1, 2004 Edition
    406   ///  http://www.opengroup.org/onlinepubs/009695399/functions/printf.html
    407   bool UsesPositionalArg;
    408   unsigned argIndex;
    409 public:
    410   FormatSpecifier(bool isPrintf)
    411     : CS(isPrintf), VectorNumElts(false),
    412       UsesPositionalArg(false), argIndex(0) {}
    413 
    414   void setLengthModifier(LengthModifier lm) {
    415     LM = lm;
    416   }
    417 
    418   void setUsesPositionalArg() { UsesPositionalArg = true; }
    419 
    420   void setArgIndex(unsigned i) {
    421     argIndex = i;
    422   }
    423 
    424   unsigned getArgIndex() const {
    425     return argIndex;
    426   }
    427 
    428   unsigned getPositionalArgIndex() const {
    429     return argIndex + 1;
    430   }
    431 
    432   const LengthModifier &getLengthModifier() const {
    433     return LM;
    434   }
    435 
    436   const OptionalAmount &getFieldWidth() const {
    437     return FieldWidth;
    438   }
    439 
    440   void setVectorNumElts(const OptionalAmount &Amt) {
    441     VectorNumElts = Amt;
    442   }
    443 
    444   const OptionalAmount &getVectorNumElts() const {
    445     return VectorNumElts;
    446   }
    447 
    448   void setFieldWidth(const OptionalAmount &Amt) {
    449     FieldWidth = Amt;
    450   }
    451 
    452   bool usesPositionalArg() const { return UsesPositionalArg; }
    453 
    454   bool hasValidLengthModifier(const TargetInfo &Target,
    455                               const LangOptions &LO) const;
    456 
    457   bool hasStandardLengthModifier() const;
    458 
    459   Optional<LengthModifier> getCorrectedLengthModifier() const;
    460 
    461   bool hasStandardConversionSpecifier(const LangOptions &LangOpt) const;
    462 
    463   bool hasStandardLengthConversionCombination() const;
    464 
    465   /// For a TypedefType QT, if it is a named integer type such as size_t,
    466   /// assign the appropriate value to LM and return true.
    467   static bool namedTypeToLengthModifier(QualType QT, LengthModifier &LM);
    468 };
    469 
    470 } // end analyze_format_string namespace
    471 
    472 //===----------------------------------------------------------------------===//
    473 /// Pieces specific to fprintf format strings.
    474 
    475 namespace analyze_printf {
    476 
    477 class PrintfConversionSpecifier :
    478   public analyze_format_string::ConversionSpecifier  {
    479 public:
    480   PrintfConversionSpecifier()
    481     : ConversionSpecifier(true, nullptr, InvalidSpecifier) {}
    482 
    483   PrintfConversionSpecifier(const char *pos, Kind k)
    484     : ConversionSpecifier(true, pos, k) {}
    485 
    486   bool isObjCArg() const { return kind >= ObjCBeg && kind <= ObjCEnd; }
    487   bool isDoubleArg() const { return kind >= DoubleArgBeg &&
    488                                     kind <= DoubleArgEnd; }
    489 
    490   static bool classof(const analyze_format_string::ConversionSpecifier *CS) {
    491     return CS->isPrintfKind();
    492   }
    493 };
    494 
    495 using analyze_format_string::ArgType;
    496 using analyze_format_string::LengthModifier;
    497 using analyze_format_string::OptionalAmount;
    498 using analyze_format_string::OptionalFlag;
    499 
    500 class PrintfSpecifier : public analyze_format_string::FormatSpecifier {
    501   OptionalFlag HasThousandsGrouping; // ''', POSIX extension.
    502   OptionalFlag IsLeftJustified; // '-'
    503   OptionalFlag HasPlusPrefix; // '+'
    504   OptionalFlag HasSpacePrefix; // ' '
    505   OptionalFlag HasAlternativeForm; // '#'
    506   OptionalFlag HasLeadingZeroes; // '0'
    507   OptionalFlag HasObjCTechnicalTerm; // '[tt]'
    508   OptionalFlag IsPrivate;            // '{private}'
    509   OptionalFlag IsPublic;             // '{public}'
    510   OptionalFlag IsSensitive;          // '{sensitive}'
    511   OptionalAmount Precision;
    512   StringRef MaskType;
    513 
    514   ArgType getScalarArgType(ASTContext &Ctx, bool IsObjCLiteral) const;
    515 
    516 public:
    517   PrintfSpecifier()
    518       : FormatSpecifier(/* isPrintf = */ true), HasThousandsGrouping("'"),
    519         IsLeftJustified("-"), HasPlusPrefix("+"), HasSpacePrefix(" "),
    520         HasAlternativeForm("#"), HasLeadingZeroes("0"),
    521         HasObjCTechnicalTerm("tt"), IsPrivate("private"), IsPublic("public"),
    522         IsSensitive("sensitive") {}
    523 
    524   static PrintfSpecifier Parse(const char *beg, const char *end);
    525 
    526     // Methods for incrementally constructing the PrintfSpecifier.
    527   void setConversionSpecifier(const PrintfConversionSpecifier &cs) {
    528     CS = cs;
    529   }
    530   void setHasThousandsGrouping(const char *position) {
    531     HasThousandsGrouping.setPosition(position);
    532   }
    533   void setIsLeftJustified(const char *position) {
    534     IsLeftJustified.setPosition(position);
    535   }
    536   void setHasPlusPrefix(const char *position) {
    537     HasPlusPrefix.setPosition(position);
    538   }
    539   void setHasSpacePrefix(const char *position) {
    540     HasSpacePrefix.setPosition(position);
    541   }
    542   void setHasAlternativeForm(const char *position) {
    543     HasAlternativeForm.setPosition(position);
    544   }
    545   void setHasLeadingZeros(const char *position) {
    546     HasLeadingZeroes.setPosition(position);
    547   }
    548   void setHasObjCTechnicalTerm(const char *position) {
    549     HasObjCTechnicalTerm.setPosition(position);
    550   }
    551   void setIsPrivate(const char *position) { IsPrivate.setPosition(position); }
    552   void setIsPublic(const char *position) { IsPublic.setPosition(position); }
    553   void setIsSensitive(const char *position) {
    554     IsSensitive.setPosition(position);
    555   }
    556   void setUsesPositionalArg() { UsesPositionalArg = true; }
    557 
    558     // Methods for querying the format specifier.
    559 
    560   const PrintfConversionSpecifier &getConversionSpecifier() const {
    561     return cast<PrintfConversionSpecifier>(CS);
    562   }
    563 
    564   void setPrecision(const OptionalAmount &Amt) {
    565     Precision = Amt;
    566     Precision.setUsesDotPrefix();
    567   }
    568 
    569   const OptionalAmount &getPrecision() const {
    570     return Precision;
    571   }
    572 
    573   bool consumesDataArgument() const {
    574     return getConversionSpecifier().consumesDataArgument();
    575   }
    576 
    577   /// Returns the builtin type that a data argument
    578   /// paired with this format specifier should have.  This method
    579   /// will return null if the format specifier does not have
    580   /// a matching data argument or the matching argument matches
    581   /// more than one type.
    582   ArgType getArgType(ASTContext &Ctx, bool IsObjCLiteral) const;
    583 
    584   const OptionalFlag &hasThousandsGrouping() const {
    585       return HasThousandsGrouping;
    586   }
    587   const OptionalFlag &isLeftJustified() const { return IsLeftJustified; }
    588   const OptionalFlag &hasPlusPrefix() const { return HasPlusPrefix; }
    589   const OptionalFlag &hasAlternativeForm() const { return HasAlternativeForm; }
    590   const OptionalFlag &hasLeadingZeros() const { return HasLeadingZeroes; }
    591   const OptionalFlag &hasSpacePrefix() const { return HasSpacePrefix; }
    592   const OptionalFlag &hasObjCTechnicalTerm() const { return HasObjCTechnicalTerm; }
    593   const OptionalFlag &isPrivate() const { return IsPrivate; }
    594   const OptionalFlag &isPublic() const { return IsPublic; }
    595   const OptionalFlag &isSensitive() const { return IsSensitive; }
    596   bool usesPositionalArg() const { return UsesPositionalArg; }
    597 
    598   StringRef getMaskType() const { return MaskType; }
    599   void setMaskType(StringRef S) { MaskType = S; }
    600 
    601   /// Changes the specifier and length according to a QualType, retaining any
    602   /// flags or options. Returns true on success, or false when a conversion
    603   /// was not successful.
    604   bool fixType(QualType QT, const LangOptions &LangOpt, ASTContext &Ctx,
    605                bool IsObjCLiteral);
    606 
    607   void toString(raw_ostream &os) const;
    608 
    609   // Validation methods - to check if any element results in undefined behavior
    610   bool hasValidPlusPrefix() const;
    611   bool hasValidAlternativeForm() const;
    612   bool hasValidLeadingZeros() const;
    613   bool hasValidSpacePrefix() const;
    614   bool hasValidLeftJustified() const;
    615   bool hasValidThousandsGroupingPrefix() const;
    616 
    617   bool hasValidPrecision() const;
    618   bool hasValidFieldWidth() const;
    619 };
    620 }  // end analyze_printf namespace
    621 
    622 //===----------------------------------------------------------------------===//
    623 /// Pieces specific to fscanf format strings.
    624 
    625 namespace analyze_scanf {
    626 
    627 class ScanfConversionSpecifier :
    628     public analyze_format_string::ConversionSpecifier  {
    629 public:
    630   ScanfConversionSpecifier()
    631     : ConversionSpecifier(false, nullptr, InvalidSpecifier) {}
    632 
    633   ScanfConversionSpecifier(const char *pos, Kind k)
    634     : ConversionSpecifier(false, pos, k) {}
    635 
    636   static bool classof(const analyze_format_string::ConversionSpecifier *CS) {
    637     return !CS->isPrintfKind();
    638   }
    639 };
    640 
    641 using analyze_format_string::ArgType;
    642 using analyze_format_string::LengthModifier;
    643 using analyze_format_string::OptionalAmount;
    644 using analyze_format_string::OptionalFlag;
    645 
    646 class ScanfSpecifier : public analyze_format_string::FormatSpecifier {
    647   OptionalFlag SuppressAssignment; // '*'
    648 public:
    649   ScanfSpecifier() :
    650     FormatSpecifier(/* isPrintf = */ false),
    651     SuppressAssignment("*") {}
    652 
    653   void setSuppressAssignment(const char *position) {
    654     SuppressAssignment.setPosition(position);
    655   }
    656 
    657   const OptionalFlag &getSuppressAssignment() const {
    658     return SuppressAssignment;
    659   }
    660 
    661   void setConversionSpecifier(const ScanfConversionSpecifier &cs) {
    662     CS = cs;
    663   }
    664 
    665   const ScanfConversionSpecifier &getConversionSpecifier() const {
    666     return cast<ScanfConversionSpecifier>(CS);
    667   }
    668 
    669   bool consumesDataArgument() const {
    670     return CS.consumesDataArgument() && !SuppressAssignment;
    671   }
    672 
    673   ArgType getArgType(ASTContext &Ctx) const;
    674 
    675   bool fixType(QualType QT, QualType RawQT, const LangOptions &LangOpt,
    676                ASTContext &Ctx);
    677 
    678   void toString(raw_ostream &os) const;
    679 
    680   static ScanfSpecifier Parse(const char *beg, const char *end);
    681 };
    682 
    683 } // end analyze_scanf namespace
    684 
    685 //===----------------------------------------------------------------------===//
    686 // Parsing and processing of format strings (both fprintf and fscanf).
    687 
    688 namespace analyze_format_string {
    689 
    690 enum PositionContext { FieldWidthPos = 0, PrecisionPos = 1 };
    691 
    692 class FormatStringHandler {
    693 public:
    694   FormatStringHandler() {}
    695   virtual ~FormatStringHandler();
    696 
    697   virtual void HandleNullChar(const char *nullCharacter) {}
    698 
    699   virtual void HandlePosition(const char *startPos, unsigned posLen) {}
    700 
    701   virtual void HandleInvalidPosition(const char *startPos, unsigned posLen,
    702                                      PositionContext p) {}
    703 
    704   virtual void HandleZeroPosition(const char *startPos, unsigned posLen) {}
    705 
    706   virtual void HandleIncompleteSpecifier(const char *startSpecifier,
    707                                          unsigned specifierLen) {}
    708 
    709   virtual void HandleEmptyObjCModifierFlag(const char *startFlags,
    710                                            unsigned flagsLen) {}
    711 
    712   virtual void HandleInvalidObjCModifierFlag(const char *startFlag,
    713                                              unsigned flagLen) {}
    714 
    715   virtual void HandleObjCFlagsWithNonObjCConversion(const char *flagsStart,
    716                                             const char *flagsEnd,
    717                                             const char *conversionPosition) {}
    718   // Printf-specific handlers.
    719 
    720   virtual bool HandleInvalidPrintfConversionSpecifier(
    721                                       const analyze_printf::PrintfSpecifier &FS,
    722                                       const char *startSpecifier,
    723                                       unsigned specifierLen) {
    724     return true;
    725   }
    726 
    727   virtual bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS,
    728                                      const char *startSpecifier,
    729                                      unsigned specifierLen) {
    730     return true;
    731   }
    732 
    733   /// Handle mask types whose sizes are not between one and eight bytes.
    734   virtual void handleInvalidMaskType(StringRef MaskType) {}
    735 
    736     // Scanf-specific handlers.
    737 
    738   virtual bool HandleInvalidScanfConversionSpecifier(
    739                                         const analyze_scanf::ScanfSpecifier &FS,
    740                                         const char *startSpecifier,
    741                                         unsigned specifierLen) {
    742     return true;
    743   }
    744 
    745   virtual bool HandleScanfSpecifier(const analyze_scanf::ScanfSpecifier &FS,
    746                                     const char *startSpecifier,
    747                                     unsigned specifierLen) {
    748     return true;
    749   }
    750 
    751   virtual void HandleIncompleteScanList(const char *start, const char *end) {}
    752 };
    753 
    754 bool ParsePrintfString(FormatStringHandler &H,
    755                        const char *beg, const char *end, const LangOptions &LO,
    756                        const TargetInfo &Target, bool isFreeBSDKPrintf);
    757 
    758 bool ParseFormatStringHasSArg(const char *beg, const char *end,
    759                               const LangOptions &LO, const TargetInfo &Target);
    760 
    761 bool ParseScanfString(FormatStringHandler &H,
    762                       const char *beg, const char *end, const LangOptions &LO,
    763                       const TargetInfo &Target);
    764 
    765 /// Return true if the given string has at least one formatting specifier.
    766 bool parseFormatStringHasFormattingSpecifiers(const char *Begin,
    767                                               const char *End,
    768                                               const LangOptions &LO,
    769                                               const TargetInfo &Target);
    770 
    771 } // end analyze_format_string namespace
    772 } // end clang namespace
    773 #endif
    774