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() const { 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     flag = true;
44     this->position = position;
45   }
getPosition()46   const char *getPosition() const {
47     assert(position);
48     return position;
49   }
toString()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     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 
LengthModifier()87   LengthModifier()
88     : Position(nullptr), kind(None) {}
LengthModifier(const char * pos,Kind k)89   LengthModifier(const char *pos, Kind k)
90     : Position(pos), kind(k) {}
91 
getStart()92   const char *getStart() const {
93     return Position;
94   }
95 
getLength()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 
getKind()111   Kind getKind() const { return kind; }
setKind(Kind k)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)
IsPrintf(isPrintf)193     : IsPrintf(isPrintf), Position(nullptr), EndScanList(nullptr),
194       kind(InvalidSpecifier) {}
195 
ConversionSpecifier(bool isPrintf,const char * pos,Kind k)196   ConversionSpecifier(bool isPrintf, const char *pos, Kind k)
197     : IsPrintf(isPrintf), Position(pos), EndScanList(nullptr), kind(k) {}
198 
getStart()199   const char *getStart() const {
200     return Position;
201   }
202 
getCharacters()203   StringRef getCharacters() const {
204     return StringRef(getStart(), getLength());
205   }
206 
consumesDataArgument()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 
getKind()221   Kind getKind() const { return kind; }
setKind(Kind k)222   void setKind(Kind k) { kind = k; }
getLength()223   unsigned getLength() const {
224     return EndScanList ? EndScanList - Position : 1;
225   }
setEndScanList(const char * pos)226   void setEndScanList(const char *pos) { EndScanList = pos; }
227 
isIntArg()228   bool isIntArg() const { return (kind >= IntArgBeg && kind <= IntArgEnd) ||
229     kind == FreeBSDrArg || kind == FreeBSDyArg; }
isUIntArg()230   bool isUIntArg() const { return kind >= UIntArgBeg && kind <= UIntArgEnd; }
isAnyIntArg()231   bool isAnyIntArg() const { return kind >= IntArgBeg && kind <= UIntArgEnd; }
isDoubleArg()232   bool isDoubleArg() const {
233     return kind >= DoubleArgBeg && kind <= DoubleArgEnd;
234   }
235 
236   const char *toString() const;
237 
isPrintfKind()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   enum MatchKind { NoMatch = 0, Match = 1, NoMatchPedantic };
255 
256 private:
257   const Kind K;
258   QualType T;
259   const char *Name = nullptr;
260   bool Ptr = false;
261 
262   /// The TypeKind identifies certain well-known types like size_t and
263   /// ptrdiff_t.
264   enum class TypeKind { DontCare, SizeT, PtrdiffT };
265   TypeKind TK = TypeKind::DontCare;
266 
267 public:
K(K)268   ArgType(Kind K = UnknownTy, const char *N = nullptr) : K(K), Name(N) {}
K(SpecificTy)269   ArgType(QualType T, const char *N = nullptr) : K(SpecificTy), T(T), Name(N) {}
ArgType(CanQualType T)270   ArgType(CanQualType T) : K(SpecificTy), T(T) {}
271 
Invalid()272   static ArgType Invalid() { return ArgType(InvalidTy); }
isValid()273   bool isValid() const { return K != InvalidTy; }
274 
isSizeT()275   bool isSizeT() const { return TK == TypeKind::SizeT; }
276 
isPtrdiffT()277   bool isPtrdiffT() const { return TK == TypeKind::PtrdiffT; }
278 
279   /// Create an ArgType which corresponds to the type pointer to A.
PtrTo(const ArgType & A)280   static ArgType PtrTo(const ArgType& A) {
281     assert(A.K >= InvalidTy && "ArgType cannot be pointer to invalid/unknown");
282     ArgType Res = A;
283     Res.Ptr = true;
284     return Res;
285   }
286 
287   /// Create an ArgType which corresponds to the size_t/ssize_t type.
makeSizeT(const ArgType & A)288   static ArgType makeSizeT(const ArgType &A) {
289     ArgType Res = A;
290     Res.TK = TypeKind::SizeT;
291     return Res;
292   }
293 
294   /// Create an ArgType which corresponds to the ptrdiff_t/unsigned ptrdiff_t
295   /// type.
makePtrdiffT(const ArgType & A)296   static ArgType makePtrdiffT(const ArgType &A) {
297     ArgType Res = A;
298     Res.TK = TypeKind::PtrdiffT;
299     return Res;
300   }
301 
302   MatchKind matchesType(ASTContext &C, QualType argTy) const;
303 
304   QualType getRepresentativeType(ASTContext &C) const;
305 
306   ArgType makeVectorType(ASTContext &C, unsigned NumElts) const;
307 
308   std::string getRepresentativeTypeName(ASTContext &C) const;
309 };
310 
311 class OptionalAmount {
312 public:
313   enum HowSpecified { NotSpecified, Constant, Arg, Invalid };
314 
OptionalAmount(HowSpecified howSpecified,unsigned amount,const char * amountStart,unsigned amountLength,bool usesPositionalArg)315   OptionalAmount(HowSpecified howSpecified,
316                  unsigned amount,
317                  const char *amountStart,
318                  unsigned amountLength,
319                  bool usesPositionalArg)
320   : start(amountStart), length(amountLength), hs(howSpecified), amt(amount),
321   UsesPositionalArg(usesPositionalArg), UsesDotPrefix(0) {}
322 
323   OptionalAmount(bool valid = true)
start(nullptr)324   : start(nullptr),length(0), hs(valid ? NotSpecified : Invalid), amt(0),
325   UsesPositionalArg(0), UsesDotPrefix(0) {}
326 
OptionalAmount(unsigned Amount)327   explicit OptionalAmount(unsigned Amount)
328     : start(nullptr), length(0), hs(Constant), amt(Amount),
329     UsesPositionalArg(false), UsesDotPrefix(false) {}
330 
isInvalid()331   bool isInvalid() const {
332     return hs == Invalid;
333   }
334 
getHowSpecified()335   HowSpecified getHowSpecified() const { return hs; }
setHowSpecified(HowSpecified h)336   void setHowSpecified(HowSpecified h) { hs = h; }
337 
hasDataArgument()338   bool hasDataArgument() const { return hs == Arg; }
339 
getArgIndex()340   unsigned getArgIndex() const {
341     assert(hasDataArgument());
342     return amt;
343   }
344 
getConstantAmount()345   unsigned getConstantAmount() const {
346     assert(hs == Constant);
347     return amt;
348   }
349 
getStart()350   const char *getStart() const {
351       // We include the . character if it is given.
352     return start - UsesDotPrefix;
353   }
354 
getConstantLength()355   unsigned getConstantLength() const {
356     assert(hs == Constant);
357     return length + UsesDotPrefix;
358   }
359 
360   ArgType getArgType(ASTContext &Ctx) const;
361 
362   void toString(raw_ostream &os) const;
363 
usesPositionalArg()364   bool usesPositionalArg() const { return (bool) UsesPositionalArg; }
getPositionalArgIndex()365   unsigned getPositionalArgIndex() const {
366     assert(hasDataArgument());
367     return amt + 1;
368   }
369 
usesDotPrefix()370   bool usesDotPrefix() const { return UsesDotPrefix; }
setUsesDotPrefix()371   void setUsesDotPrefix() { UsesDotPrefix = true; }
372 
373 private:
374   const char *start;
375   unsigned length;
376   HowSpecified hs;
377   unsigned amt;
378   bool UsesPositionalArg : 1;
379   bool UsesDotPrefix;
380 };
381 
382 
383 class FormatSpecifier {
384 protected:
385   LengthModifier LM;
386   OptionalAmount FieldWidth;
387   ConversionSpecifier CS;
388   OptionalAmount VectorNumElts;
389 
390   /// Positional arguments, an IEEE extension:
391   ///  IEEE Std 1003.1, 2004 Edition
392   ///  http://www.opengroup.org/onlinepubs/009695399/functions/printf.html
393   bool UsesPositionalArg;
394   unsigned argIndex;
395 public:
FormatSpecifier(bool isPrintf)396   FormatSpecifier(bool isPrintf)
397     : CS(isPrintf), VectorNumElts(false),
398       UsesPositionalArg(false), argIndex(0) {}
399 
setLengthModifier(LengthModifier lm)400   void setLengthModifier(LengthModifier lm) {
401     LM = lm;
402   }
403 
setUsesPositionalArg()404   void setUsesPositionalArg() { UsesPositionalArg = true; }
405 
setArgIndex(unsigned i)406   void setArgIndex(unsigned i) {
407     argIndex = i;
408   }
409 
getArgIndex()410   unsigned getArgIndex() const {
411     return argIndex;
412   }
413 
getPositionalArgIndex()414   unsigned getPositionalArgIndex() const {
415     return argIndex + 1;
416   }
417 
getLengthModifier()418   const LengthModifier &getLengthModifier() const {
419     return LM;
420   }
421 
getFieldWidth()422   const OptionalAmount &getFieldWidth() const {
423     return FieldWidth;
424   }
425 
setVectorNumElts(const OptionalAmount & Amt)426   void setVectorNumElts(const OptionalAmount &Amt) {
427     VectorNumElts = Amt;
428   }
429 
getVectorNumElts()430   const OptionalAmount &getVectorNumElts() const {
431     return VectorNumElts;
432   }
433 
setFieldWidth(const OptionalAmount & Amt)434   void setFieldWidth(const OptionalAmount &Amt) {
435     FieldWidth = Amt;
436   }
437 
usesPositionalArg()438   bool usesPositionalArg() const { return UsesPositionalArg; }
439 
440   bool hasValidLengthModifier(const TargetInfo &Target) const;
441 
442   bool hasStandardLengthModifier() const;
443 
444   Optional<LengthModifier> getCorrectedLengthModifier() const;
445 
446   bool hasStandardConversionSpecifier(const LangOptions &LangOpt) const;
447 
448   bool hasStandardLengthConversionCombination() const;
449 
450   /// For a TypedefType QT, if it is a named integer type such as size_t,
451   /// assign the appropriate value to LM and return true.
452   static bool namedTypeToLengthModifier(QualType QT, LengthModifier &LM);
453 };
454 
455 } // end analyze_format_string namespace
456 
457 //===----------------------------------------------------------------------===//
458 /// Pieces specific to fprintf format strings.
459 
460 namespace analyze_printf {
461 
462 class PrintfConversionSpecifier :
463   public analyze_format_string::ConversionSpecifier  {
464 public:
PrintfConversionSpecifier()465   PrintfConversionSpecifier()
466     : ConversionSpecifier(true, nullptr, InvalidSpecifier) {}
467 
PrintfConversionSpecifier(const char * pos,Kind k)468   PrintfConversionSpecifier(const char *pos, Kind k)
469     : ConversionSpecifier(true, pos, k) {}
470 
isObjCArg()471   bool isObjCArg() const { return kind >= ObjCBeg && kind <= ObjCEnd; }
isDoubleArg()472   bool isDoubleArg() const { return kind >= DoubleArgBeg &&
473                                     kind <= DoubleArgEnd; }
474 
classof(const analyze_format_string::ConversionSpecifier * CS)475   static bool classof(const analyze_format_string::ConversionSpecifier *CS) {
476     return CS->isPrintfKind();
477   }
478 };
479 
480 using analyze_format_string::ArgType;
481 using analyze_format_string::LengthModifier;
482 using analyze_format_string::OptionalAmount;
483 using analyze_format_string::OptionalFlag;
484 
485 class PrintfSpecifier : public analyze_format_string::FormatSpecifier {
486   OptionalFlag HasThousandsGrouping; // ''', POSIX extension.
487   OptionalFlag IsLeftJustified; // '-'
488   OptionalFlag HasPlusPrefix; // '+'
489   OptionalFlag HasSpacePrefix; // ' '
490   OptionalFlag HasAlternativeForm; // '#'
491   OptionalFlag HasLeadingZeroes; // '0'
492   OptionalFlag HasObjCTechnicalTerm; // '[tt]'
493   OptionalFlag IsPrivate;            // '{private}'
494   OptionalFlag IsPublic;             // '{public}'
495   OptionalFlag IsSensitive;          // '{sensitive}'
496   OptionalAmount Precision;
497   StringRef MaskType;
498 
499   ArgType getScalarArgType(ASTContext &Ctx, bool IsObjCLiteral) const;
500 
501 public:
PrintfSpecifier()502   PrintfSpecifier()
503       : FormatSpecifier(/* isPrintf = */ true), HasThousandsGrouping("'"),
504         IsLeftJustified("-"), HasPlusPrefix("+"), HasSpacePrefix(" "),
505         HasAlternativeForm("#"), HasLeadingZeroes("0"),
506         HasObjCTechnicalTerm("tt"), IsPrivate("private"), IsPublic("public"),
507         IsSensitive("sensitive") {}
508 
509   static PrintfSpecifier Parse(const char *beg, const char *end);
510 
511     // Methods for incrementally constructing the PrintfSpecifier.
setConversionSpecifier(const PrintfConversionSpecifier & cs)512   void setConversionSpecifier(const PrintfConversionSpecifier &cs) {
513     CS = cs;
514   }
setHasThousandsGrouping(const char * position)515   void setHasThousandsGrouping(const char *position) {
516     HasThousandsGrouping.setPosition(position);
517   }
setIsLeftJustified(const char * position)518   void setIsLeftJustified(const char *position) {
519     IsLeftJustified.setPosition(position);
520   }
setHasPlusPrefix(const char * position)521   void setHasPlusPrefix(const char *position) {
522     HasPlusPrefix.setPosition(position);
523   }
setHasSpacePrefix(const char * position)524   void setHasSpacePrefix(const char *position) {
525     HasSpacePrefix.setPosition(position);
526   }
setHasAlternativeForm(const char * position)527   void setHasAlternativeForm(const char *position) {
528     HasAlternativeForm.setPosition(position);
529   }
setHasLeadingZeros(const char * position)530   void setHasLeadingZeros(const char *position) {
531     HasLeadingZeroes.setPosition(position);
532   }
setHasObjCTechnicalTerm(const char * position)533   void setHasObjCTechnicalTerm(const char *position) {
534     HasObjCTechnicalTerm.setPosition(position);
535   }
setIsPrivate(const char * position)536   void setIsPrivate(const char *position) { IsPrivate.setPosition(position); }
setIsPublic(const char * position)537   void setIsPublic(const char *position) { IsPublic.setPosition(position); }
setIsSensitive(const char * position)538   void setIsSensitive(const char *position) {
539     IsSensitive.setPosition(position);
540   }
setUsesPositionalArg()541   void setUsesPositionalArg() { UsesPositionalArg = true; }
542 
543     // Methods for querying the format specifier.
544 
getConversionSpecifier()545   const PrintfConversionSpecifier &getConversionSpecifier() const {
546     return cast<PrintfConversionSpecifier>(CS);
547   }
548 
setPrecision(const OptionalAmount & Amt)549   void setPrecision(const OptionalAmount &Amt) {
550     Precision = Amt;
551     Precision.setUsesDotPrefix();
552   }
553 
getPrecision()554   const OptionalAmount &getPrecision() const {
555     return Precision;
556   }
557 
consumesDataArgument()558   bool consumesDataArgument() const {
559     return getConversionSpecifier().consumesDataArgument();
560   }
561 
562   /// Returns the builtin type that a data argument
563   /// paired with this format specifier should have.  This method
564   /// will return null if the format specifier does not have
565   /// a matching data argument or the matching argument matches
566   /// more than one type.
567   ArgType getArgType(ASTContext &Ctx, bool IsObjCLiteral) const;
568 
hasThousandsGrouping()569   const OptionalFlag &hasThousandsGrouping() const {
570       return HasThousandsGrouping;
571   }
isLeftJustified()572   const OptionalFlag &isLeftJustified() const { return IsLeftJustified; }
hasPlusPrefix()573   const OptionalFlag &hasPlusPrefix() const { return HasPlusPrefix; }
hasAlternativeForm()574   const OptionalFlag &hasAlternativeForm() const { return HasAlternativeForm; }
hasLeadingZeros()575   const OptionalFlag &hasLeadingZeros() const { return HasLeadingZeroes; }
hasSpacePrefix()576   const OptionalFlag &hasSpacePrefix() const { return HasSpacePrefix; }
hasObjCTechnicalTerm()577   const OptionalFlag &hasObjCTechnicalTerm() const { return HasObjCTechnicalTerm; }
isPrivate()578   const OptionalFlag &isPrivate() const { return IsPrivate; }
isPublic()579   const OptionalFlag &isPublic() const { return IsPublic; }
isSensitive()580   const OptionalFlag &isSensitive() const { return IsSensitive; }
usesPositionalArg()581   bool usesPositionalArg() const { return UsesPositionalArg; }
582 
getMaskType()583   StringRef getMaskType() const { return MaskType; }
setMaskType(StringRef S)584   void setMaskType(StringRef S) { MaskType = S; }
585 
586   /// Changes the specifier and length according to a QualType, retaining any
587   /// flags or options. Returns true on success, or false when a conversion
588   /// was not successful.
589   bool fixType(QualType QT, const LangOptions &LangOpt, ASTContext &Ctx,
590                bool IsObjCLiteral);
591 
592   void toString(raw_ostream &os) const;
593 
594   // Validation methods - to check if any element results in undefined behavior
595   bool hasValidPlusPrefix() const;
596   bool hasValidAlternativeForm() const;
597   bool hasValidLeadingZeros() const;
598   bool hasValidSpacePrefix() const;
599   bool hasValidLeftJustified() const;
600   bool hasValidThousandsGroupingPrefix() const;
601 
602   bool hasValidPrecision() const;
603   bool hasValidFieldWidth() const;
604 };
605 }  // end analyze_printf namespace
606 
607 //===----------------------------------------------------------------------===//
608 /// Pieces specific to fscanf format strings.
609 
610 namespace analyze_scanf {
611 
612 class ScanfConversionSpecifier :
613     public analyze_format_string::ConversionSpecifier  {
614 public:
ScanfConversionSpecifier()615   ScanfConversionSpecifier()
616     : ConversionSpecifier(false, nullptr, InvalidSpecifier) {}
617 
ScanfConversionSpecifier(const char * pos,Kind k)618   ScanfConversionSpecifier(const char *pos, Kind k)
619     : ConversionSpecifier(false, pos, k) {}
620 
classof(const analyze_format_string::ConversionSpecifier * CS)621   static bool classof(const analyze_format_string::ConversionSpecifier *CS) {
622     return !CS->isPrintfKind();
623   }
624 };
625 
626 using analyze_format_string::ArgType;
627 using analyze_format_string::LengthModifier;
628 using analyze_format_string::OptionalAmount;
629 using analyze_format_string::OptionalFlag;
630 
631 class ScanfSpecifier : public analyze_format_string::FormatSpecifier {
632   OptionalFlag SuppressAssignment; // '*'
633 public:
ScanfSpecifier()634   ScanfSpecifier() :
635     FormatSpecifier(/* isPrintf = */ false),
636     SuppressAssignment("*") {}
637 
setSuppressAssignment(const char * position)638   void setSuppressAssignment(const char *position) {
639     SuppressAssignment.setPosition(position);
640   }
641 
getSuppressAssignment()642   const OptionalFlag &getSuppressAssignment() const {
643     return SuppressAssignment;
644   }
645 
setConversionSpecifier(const ScanfConversionSpecifier & cs)646   void setConversionSpecifier(const ScanfConversionSpecifier &cs) {
647     CS = cs;
648   }
649 
getConversionSpecifier()650   const ScanfConversionSpecifier &getConversionSpecifier() const {
651     return cast<ScanfConversionSpecifier>(CS);
652   }
653 
consumesDataArgument()654   bool consumesDataArgument() const {
655     return CS.consumesDataArgument() && !SuppressAssignment;
656   }
657 
658   ArgType getArgType(ASTContext &Ctx) const;
659 
660   bool fixType(QualType QT, QualType RawQT, const LangOptions &LangOpt,
661                ASTContext &Ctx);
662 
663   void toString(raw_ostream &os) const;
664 
665   static ScanfSpecifier Parse(const char *beg, const char *end);
666 };
667 
668 } // end analyze_scanf namespace
669 
670 //===----------------------------------------------------------------------===//
671 // Parsing and processing of format strings (both fprintf and fscanf).
672 
673 namespace analyze_format_string {
674 
675 enum PositionContext { FieldWidthPos = 0, PrecisionPos = 1 };
676 
677 class FormatStringHandler {
678 public:
FormatStringHandler()679   FormatStringHandler() {}
680   virtual ~FormatStringHandler();
681 
HandleNullChar(const char * nullCharacter)682   virtual void HandleNullChar(const char *nullCharacter) {}
683 
HandlePosition(const char * startPos,unsigned posLen)684   virtual void HandlePosition(const char *startPos, unsigned posLen) {}
685 
HandleInvalidPosition(const char * startPos,unsigned posLen,PositionContext p)686   virtual void HandleInvalidPosition(const char *startPos, unsigned posLen,
687                                      PositionContext p) {}
688 
HandleZeroPosition(const char * startPos,unsigned posLen)689   virtual void HandleZeroPosition(const char *startPos, unsigned posLen) {}
690 
HandleIncompleteSpecifier(const char * startSpecifier,unsigned specifierLen)691   virtual void HandleIncompleteSpecifier(const char *startSpecifier,
692                                          unsigned specifierLen) {}
693 
HandleEmptyObjCModifierFlag(const char * startFlags,unsigned flagsLen)694   virtual void HandleEmptyObjCModifierFlag(const char *startFlags,
695                                            unsigned flagsLen) {}
696 
HandleInvalidObjCModifierFlag(const char * startFlag,unsigned flagLen)697   virtual void HandleInvalidObjCModifierFlag(const char *startFlag,
698                                              unsigned flagLen) {}
699 
HandleObjCFlagsWithNonObjCConversion(const char * flagsStart,const char * flagsEnd,const char * conversionPosition)700   virtual void HandleObjCFlagsWithNonObjCConversion(const char *flagsStart,
701                                             const char *flagsEnd,
702                                             const char *conversionPosition) {}
703   // Printf-specific handlers.
704 
HandleInvalidPrintfConversionSpecifier(const analyze_printf::PrintfSpecifier & FS,const char * startSpecifier,unsigned specifierLen)705   virtual bool HandleInvalidPrintfConversionSpecifier(
706                                       const analyze_printf::PrintfSpecifier &FS,
707                                       const char *startSpecifier,
708                                       unsigned specifierLen) {
709     return true;
710   }
711 
HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier & FS,const char * startSpecifier,unsigned specifierLen)712   virtual bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS,
713                                      const char *startSpecifier,
714                                      unsigned specifierLen) {
715     return true;
716   }
717 
718   /// Handle mask types whose sizes are not between one and eight bytes.
handleInvalidMaskType(StringRef MaskType)719   virtual void handleInvalidMaskType(StringRef MaskType) {}
720 
721     // Scanf-specific handlers.
722 
HandleInvalidScanfConversionSpecifier(const analyze_scanf::ScanfSpecifier & FS,const char * startSpecifier,unsigned specifierLen)723   virtual bool HandleInvalidScanfConversionSpecifier(
724                                         const analyze_scanf::ScanfSpecifier &FS,
725                                         const char *startSpecifier,
726                                         unsigned specifierLen) {
727     return true;
728   }
729 
HandleScanfSpecifier(const analyze_scanf::ScanfSpecifier & FS,const char * startSpecifier,unsigned specifierLen)730   virtual bool HandleScanfSpecifier(const analyze_scanf::ScanfSpecifier &FS,
731                                     const char *startSpecifier,
732                                     unsigned specifierLen) {
733     return true;
734   }
735 
HandleIncompleteScanList(const char * start,const char * end)736   virtual void HandleIncompleteScanList(const char *start, const char *end) {}
737 };
738 
739 bool ParsePrintfString(FormatStringHandler &H,
740                        const char *beg, const char *end, const LangOptions &LO,
741                        const TargetInfo &Target, bool isFreeBSDKPrintf);
742 
743 bool ParseFormatStringHasSArg(const char *beg, const char *end,
744                               const LangOptions &LO, const TargetInfo &Target);
745 
746 bool ParseScanfString(FormatStringHandler &H,
747                       const char *beg, const char *end, const LangOptions &LO,
748                       const TargetInfo &Target);
749 
750 } // end analyze_format_string namespace
751 } // end clang namespace
752 #endif
753