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