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