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:
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     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 
LengthModifier()88   LengthModifier()
89     : Position(nullptr), kind(None) {}
LengthModifier(const char * pos,Kind k)90   LengthModifier(const char *pos, Kind k)
91     : Position(pos), kind(k) {}
92 
getStart()93   const char *getStart() const {
94     return Position;
95   }
96 
getLength()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 
getKind()112   Kind getKind() const { return kind; }
setKind(Kind k)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)
IsPrintf(isPrintf)198     : IsPrintf(isPrintf), Position(nullptr), EndScanList(nullptr),
199       kind(InvalidSpecifier) {}
200 
ConversionSpecifier(bool isPrintf,const char * pos,Kind k)201   ConversionSpecifier(bool isPrintf, const char *pos, Kind k)
202     : IsPrintf(isPrintf), Position(pos), EndScanList(nullptr), kind(k) {}
203 
getStart()204   const char *getStart() const {
205     return Position;
206   }
207 
getCharacters()208   StringRef getCharacters() const {
209     return StringRef(getStart(), getLength());
210   }
211 
consumesDataArgument()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 
getKind()226   Kind getKind() const { return kind; }
setKind(Kind k)227   void setKind(Kind k) { kind = k; }
getLength()228   unsigned getLength() const {
229     return EndScanList ? EndScanList - Position : 1;
230   }
setEndScanList(const char * pos)231   void setEndScanList(const char *pos) { EndScanList = pos; }
232 
isIntArg()233   bool isIntArg() const { return (kind >= IntArgBeg && kind <= IntArgEnd) ||
234     kind == FreeBSDrArg || kind == FreeBSDyArg; }
isUIntArg()235   bool isUIntArg() const { return kind >= UIntArgBeg && kind <= UIntArgEnd; }
isAnyIntArg()236   bool isAnyIntArg() const { return kind >= IntArgBeg && kind <= UIntArgEnd; }
isDoubleArg()237   bool isDoubleArg() const {
238     return kind >= DoubleArgBeg && kind <= DoubleArgEnd;
239   }
240 
241   const char *toString() const;
242 
isPrintfKind()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:
K(K)293   ArgType(Kind K = UnknownTy, const char *N = nullptr) : K(K), Name(N) {}
K(SpecificTy)294   ArgType(QualType T, const char *N = nullptr) : K(SpecificTy), T(T), Name(N) {}
ArgType(CanQualType T)295   ArgType(CanQualType T) : K(SpecificTy), T(T) {}
296 
Invalid()297   static ArgType Invalid() { return ArgType(InvalidTy); }
isValid()298   bool isValid() const { return K != InvalidTy; }
299 
isSizeT()300   bool isSizeT() const { return TK == TypeKind::SizeT; }
301 
isPtrdiffT()302   bool isPtrdiffT() const { return TK == TypeKind::PtrdiffT; }
303 
304   /// Create an ArgType which corresponds to the type pointer to A.
PtrTo(const ArgType & 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.
makeSizeT(const ArgType & A)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.
makePtrdiffT(const ArgType & A)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 
OptionalAmount(HowSpecified howSpecified,unsigned amount,const char * amountStart,unsigned amountLength,bool usesPositionalArg)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)
start(nullptr)349   : start(nullptr),length(0), hs(valid ? NotSpecified : Invalid), amt(0),
350   UsesPositionalArg(false), UsesDotPrefix(false) {}
351 
OptionalAmount(unsigned Amount)352   explicit OptionalAmount(unsigned Amount)
353     : start(nullptr), length(0), hs(Constant), amt(Amount),
354     UsesPositionalArg(false), UsesDotPrefix(false) {}
355 
isInvalid()356   bool isInvalid() const {
357     return hs == Invalid;
358   }
359 
getHowSpecified()360   HowSpecified getHowSpecified() const { return hs; }
setHowSpecified(HowSpecified h)361   void setHowSpecified(HowSpecified h) { hs = h; }
362 
hasDataArgument()363   bool hasDataArgument() const { return hs == Arg; }
364 
getArgIndex()365   unsigned getArgIndex() const {
366     assert(hasDataArgument());
367     return amt;
368   }
369 
getConstantAmount()370   unsigned getConstantAmount() const {
371     assert(hs == Constant);
372     return amt;
373   }
374 
getStart()375   const char *getStart() const {
376       // We include the . character if it is given.
377     return start - UsesDotPrefix;
378   }
379 
getConstantLength()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 
usesPositionalArg()389   bool usesPositionalArg() const { return (bool) UsesPositionalArg; }
getPositionalArgIndex()390   unsigned getPositionalArgIndex() const {
391     assert(hasDataArgument());
392     return amt + 1;
393   }
394 
usesDotPrefix()395   bool usesDotPrefix() const { return UsesDotPrefix; }
setUsesDotPrefix()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:
FormatSpecifier(bool isPrintf)421   FormatSpecifier(bool isPrintf)
422     : CS(isPrintf), VectorNumElts(false),
423       UsesPositionalArg(false), argIndex(0) {}
424 
setLengthModifier(LengthModifier lm)425   void setLengthModifier(LengthModifier lm) {
426     LM = lm;
427   }
428 
setUsesPositionalArg()429   void setUsesPositionalArg() { UsesPositionalArg = true; }
430 
setArgIndex(unsigned i)431   void setArgIndex(unsigned i) {
432     argIndex = i;
433   }
434 
getArgIndex()435   unsigned getArgIndex() const {
436     return argIndex;
437   }
438 
getPositionalArgIndex()439   unsigned getPositionalArgIndex() const {
440     return argIndex + 1;
441   }
442 
getLengthModifier()443   const LengthModifier &getLengthModifier() const {
444     return LM;
445   }
446 
getFieldWidth()447   const OptionalAmount &getFieldWidth() const {
448     return FieldWidth;
449   }
450 
setVectorNumElts(const OptionalAmount & Amt)451   void setVectorNumElts(const OptionalAmount &Amt) {
452     VectorNumElts = Amt;
453   }
454 
getVectorNumElts()455   const OptionalAmount &getVectorNumElts() const {
456     return VectorNumElts;
457   }
458 
setFieldWidth(const OptionalAmount & Amt)459   void setFieldWidth(const OptionalAmount &Amt) {
460     FieldWidth = Amt;
461   }
462 
usesPositionalArg()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:
PrintfConversionSpecifier()491   PrintfConversionSpecifier()
492     : ConversionSpecifier(true, nullptr, InvalidSpecifier) {}
493 
PrintfConversionSpecifier(const char * pos,Kind k)494   PrintfConversionSpecifier(const char *pos, Kind k)
495     : ConversionSpecifier(true, pos, k) {}
496 
isObjCArg()497   bool isObjCArg() const { return kind >= ObjCBeg && kind <= ObjCEnd; }
isDoubleArg()498   bool isDoubleArg() const { return kind >= DoubleArgBeg &&
499                                     kind <= DoubleArgEnd; }
500 
classof(const analyze_format_string::ConversionSpecifier * CS)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:
PrintfSpecifier()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.
setConversionSpecifier(const PrintfConversionSpecifier & cs)538   void setConversionSpecifier(const PrintfConversionSpecifier &cs) {
539     CS = cs;
540   }
setHasThousandsGrouping(const char * position)541   void setHasThousandsGrouping(const char *position) {
542     HasThousandsGrouping.setPosition(position);
543   }
setIsLeftJustified(const char * position)544   void setIsLeftJustified(const char *position) {
545     IsLeftJustified.setPosition(position);
546   }
setHasPlusPrefix(const char * position)547   void setHasPlusPrefix(const char *position) {
548     HasPlusPrefix.setPosition(position);
549   }
setHasSpacePrefix(const char * position)550   void setHasSpacePrefix(const char *position) {
551     HasSpacePrefix.setPosition(position);
552   }
setHasAlternativeForm(const char * position)553   void setHasAlternativeForm(const char *position) {
554     HasAlternativeForm.setPosition(position);
555   }
setHasLeadingZeros(const char * position)556   void setHasLeadingZeros(const char *position) {
557     HasLeadingZeroes.setPosition(position);
558   }
setHasObjCTechnicalTerm(const char * position)559   void setHasObjCTechnicalTerm(const char *position) {
560     HasObjCTechnicalTerm.setPosition(position);
561   }
setIsPrivate(const char * position)562   void setIsPrivate(const char *position) { IsPrivate.setPosition(position); }
setIsPublic(const char * position)563   void setIsPublic(const char *position) { IsPublic.setPosition(position); }
setIsSensitive(const char * position)564   void setIsSensitive(const char *position) {
565     IsSensitive.setPosition(position);
566   }
setUsesPositionalArg()567   void setUsesPositionalArg() { UsesPositionalArg = true; }
568 
569     // Methods for querying the format specifier.
570 
getConversionSpecifier()571   const PrintfConversionSpecifier &getConversionSpecifier() const {
572     return cast<PrintfConversionSpecifier>(CS);
573   }
574 
setPrecision(const OptionalAmount & Amt)575   void setPrecision(const OptionalAmount &Amt) {
576     Precision = Amt;
577     Precision.setUsesDotPrefix();
578   }
579 
getPrecision()580   const OptionalAmount &getPrecision() const {
581     return Precision;
582   }
583 
consumesDataArgument()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 
hasThousandsGrouping()595   const OptionalFlag &hasThousandsGrouping() const {
596       return HasThousandsGrouping;
597   }
isLeftJustified()598   const OptionalFlag &isLeftJustified() const { return IsLeftJustified; }
hasPlusPrefix()599   const OptionalFlag &hasPlusPrefix() const { return HasPlusPrefix; }
hasAlternativeForm()600   const OptionalFlag &hasAlternativeForm() const { return HasAlternativeForm; }
hasLeadingZeros()601   const OptionalFlag &hasLeadingZeros() const { return HasLeadingZeroes; }
hasSpacePrefix()602   const OptionalFlag &hasSpacePrefix() const { return HasSpacePrefix; }
hasObjCTechnicalTerm()603   const OptionalFlag &hasObjCTechnicalTerm() const { return HasObjCTechnicalTerm; }
isPrivate()604   const OptionalFlag &isPrivate() const { return IsPrivate; }
isPublic()605   const OptionalFlag &isPublic() const { return IsPublic; }
isSensitive()606   const OptionalFlag &isSensitive() const { return IsSensitive; }
usesPositionalArg()607   bool usesPositionalArg() const { return UsesPositionalArg; }
608 
getMaskType()609   StringRef getMaskType() const { return MaskType; }
setMaskType(StringRef S)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:
ScanfConversionSpecifier()641   ScanfConversionSpecifier()
642     : ConversionSpecifier(false, nullptr, InvalidSpecifier) {}
643 
ScanfConversionSpecifier(const char * pos,Kind k)644   ScanfConversionSpecifier(const char *pos, Kind k)
645     : ConversionSpecifier(false, pos, k) {}
646 
classof(const analyze_format_string::ConversionSpecifier * CS)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:
ScanfSpecifier()660   ScanfSpecifier() :
661     FormatSpecifier(/* isPrintf = */ false),
662     SuppressAssignment("*") {}
663 
setSuppressAssignment(const char * position)664   void setSuppressAssignment(const char *position) {
665     SuppressAssignment.setPosition(position);
666   }
667 
getSuppressAssignment()668   const OptionalFlag &getSuppressAssignment() const {
669     return SuppressAssignment;
670   }
671 
setConversionSpecifier(const ScanfConversionSpecifier & cs)672   void setConversionSpecifier(const ScanfConversionSpecifier &cs) {
673     CS = cs;
674   }
675 
getConversionSpecifier()676   const ScanfConversionSpecifier &getConversionSpecifier() const {
677     return cast<ScanfConversionSpecifier>(CS);
678   }
679 
consumesDataArgument()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:
FormatStringHandler()705   FormatStringHandler() {}
706   virtual ~FormatStringHandler();
707 
HandleNullChar(const char * nullCharacter)708   virtual void HandleNullChar(const char *nullCharacter) {}
709 
HandlePosition(const char * startPos,unsigned posLen)710   virtual void HandlePosition(const char *startPos, unsigned posLen) {}
711 
HandleInvalidPosition(const char * startPos,unsigned posLen,PositionContext p)712   virtual void HandleInvalidPosition(const char *startPos, unsigned posLen,
713                                      PositionContext p) {}
714 
HandleZeroPosition(const char * startPos,unsigned posLen)715   virtual void HandleZeroPosition(const char *startPos, unsigned posLen) {}
716 
HandleIncompleteSpecifier(const char * startSpecifier,unsigned specifierLen)717   virtual void HandleIncompleteSpecifier(const char *startSpecifier,
718                                          unsigned specifierLen) {}
719 
HandleEmptyObjCModifierFlag(const char * startFlags,unsigned flagsLen)720   virtual void HandleEmptyObjCModifierFlag(const char *startFlags,
721                                            unsigned flagsLen) {}
722 
HandleInvalidObjCModifierFlag(const char * startFlag,unsigned flagLen)723   virtual void HandleInvalidObjCModifierFlag(const char *startFlag,
724                                              unsigned flagLen) {}
725 
HandleObjCFlagsWithNonObjCConversion(const char * flagsStart,const char * flagsEnd,const char * conversionPosition)726   virtual void HandleObjCFlagsWithNonObjCConversion(const char *flagsStart,
727                                             const char *flagsEnd,
728                                             const char *conversionPosition) {}
729   // Printf-specific handlers.
730 
HandleInvalidPrintfConversionSpecifier(const analyze_printf::PrintfSpecifier & FS,const char * startSpecifier,unsigned specifierLen)731   virtual bool HandleInvalidPrintfConversionSpecifier(
732                                       const analyze_printf::PrintfSpecifier &FS,
733                                       const char *startSpecifier,
734                                       unsigned specifierLen) {
735     return true;
736   }
737 
HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier & FS,const char * startSpecifier,unsigned specifierLen,const TargetInfo & Target)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.
handleInvalidMaskType(StringRef MaskType)746   virtual void handleInvalidMaskType(StringRef MaskType) {}
747 
748     // Scanf-specific handlers.
749 
HandleInvalidScanfConversionSpecifier(const analyze_scanf::ScanfSpecifier & FS,const char * startSpecifier,unsigned specifierLen)750   virtual bool HandleInvalidScanfConversionSpecifier(
751                                         const analyze_scanf::ScanfSpecifier &FS,
752                                         const char *startSpecifier,
753                                         unsigned specifierLen) {
754     return true;
755   }
756 
HandleScanfSpecifier(const analyze_scanf::ScanfSpecifier & FS,const char * startSpecifier,unsigned specifierLen)757   virtual bool HandleScanfSpecifier(const analyze_scanf::ScanfSpecifier &FS,
758                                     const char *startSpecifier,
759                                     unsigned specifierLen) {
760     return true;
761   }
762 
HandleIncompleteScanList(const char * start,const char * end)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