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