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_AST_FORMATSTRING_H
19 #define LLVM_CLANG_AST_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(false) {}
336 
337   OptionalAmount(bool valid = true)
338   : start(nullptr),length(0), hs(valid ? NotSpecified : Invalid), amt(0),
339   UsesPositionalArg(false), UsesDotPrefix(false) {}
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                                      const TargetInfo &Target) {
731     return true;
732   }
733 
734   /// Handle mask types whose sizes are not between one and eight bytes.
735   virtual void handleInvalidMaskType(StringRef MaskType) {}
736 
737     // Scanf-specific handlers.
738 
739   virtual bool HandleInvalidScanfConversionSpecifier(
740                                         const analyze_scanf::ScanfSpecifier &FS,
741                                         const char *startSpecifier,
742                                         unsigned specifierLen) {
743     return true;
744   }
745 
746   virtual bool HandleScanfSpecifier(const analyze_scanf::ScanfSpecifier &FS,
747                                     const char *startSpecifier,
748                                     unsigned specifierLen) {
749     return true;
750   }
751 
752   virtual void HandleIncompleteScanList(const char *start, const char *end) {}
753 };
754 
755 bool ParsePrintfString(FormatStringHandler &H,
756                        const char *beg, const char *end, const LangOptions &LO,
757                        const TargetInfo &Target, bool isFreeBSDKPrintf);
758 
759 bool ParseFormatStringHasSArg(const char *beg, const char *end,
760                               const LangOptions &LO, const TargetInfo &Target);
761 
762 bool ParseScanfString(FormatStringHandler &H,
763                       const char *beg, const char *end, const LangOptions &LO,
764                       const TargetInfo &Target);
765 
766 /// Return true if the given string has at least one formatting specifier.
767 bool parseFormatStringHasFormattingSpecifiers(const char *Begin,
768                                               const char *End,
769                                               const LangOptions &LO,
770                                               const TargetInfo &Target);
771 
772 } // end analyze_format_string namespace
773 } // end clang namespace
774 #endif
775