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