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