]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/clang/include/clang/Analysis/Analyses/FormatString.h
Merge ^/head r277804 through r277843.
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / clang / include / clang / Analysis / Analyses / FormatString.h
1 //= FormatString.h - Analysis of printf/fprintf format strings --*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file defines APIs for analyzing the format strings of printf, fscanf,
11 // and friends.
12 //
13 // The structure of format strings for fprintf are described in C99 7.19.6.1.
14 //
15 // The structure of format strings for fscanf are described in C99 7.19.6.2.
16 //
17 //===----------------------------------------------------------------------===//
18
19 #ifndef LLVM_CLANG_ANALYSIS_ANALYSES_FORMATSTRING_H
20 #define LLVM_CLANG_ANALYSIS_ANALYSES_FORMATSTRING_H
21
22 #include "clang/AST/CanonicalType.h"
23
24 namespace clang {
25
26 class TargetInfo;
27
28 //===----------------------------------------------------------------------===//
29 /// Common components of both fprintf and fscanf format strings.
30 namespace analyze_format_string {
31
32 /// Class representing optional flags with location and representation
33 /// information.
34 class OptionalFlag {
35 public:
36   OptionalFlag(const char *Representation)
37       : representation(Representation), flag(false) {}
38   bool isSet() { return flag; }
39   void set() { flag = true; }
40   void clear() { flag = false; }
41   void setPosition(const char *position) {
42     assert(position);
43     this->position = position;
44   }
45   const char *getPosition() const {
46     assert(position);
47     return position;
48   }
49   const char *toString() const { return representation; }
50
51   // Overloaded operators for bool like qualities
52   LLVM_EXPLICIT operator bool() const { return flag; }
53   OptionalFlag& operator=(const bool &rhs) {
54     flag = rhs;
55     return *this;  // Return a reference to myself.
56   }
57 private:
58   const char *representation;
59   const char *position;
60   bool flag;
61 };
62
63 /// Represents the length modifier in a format string in scanf/printf.
64 class LengthModifier {
65 public:
66   enum Kind {
67     None,
68     AsChar,       // 'hh'
69     AsShort,      // 'h'
70     AsLong,       // 'l'
71     AsLongLong,   // 'll'
72     AsQuad,       // 'q' (BSD, deprecated, for 64-bit integer types)
73     AsIntMax,     // 'j'
74     AsSizeT,      // 'z'
75     AsPtrDiff,    // 't'
76     AsInt32,      // 'I32' (MSVCRT, like __int32)
77     AsInt3264,    // 'I'   (MSVCRT, like __int3264 from MIDL)
78     AsInt64,      // 'I64' (MSVCRT, like __int64)
79     AsLongDouble, // 'L'
80     AsAllocate,   // for '%as', GNU extension to C90 scanf
81     AsMAllocate,  // for '%ms', GNU extension to scanf
82     AsWide,       // 'w' (MSVCRT, like l but only for c, C, s, S, or Z
83     AsWideChar = AsLong // for '%ls', only makes sense for printf
84   };
85
86   LengthModifier()
87     : Position(nullptr), kind(None) {}
88   LengthModifier(const char *pos, Kind k)
89     : Position(pos), kind(k) {}
90
91   const char *getStart() const {
92     return Position;
93   }
94
95   unsigned getLength() const {
96     switch (kind) {
97       default:
98         return 1;
99       case AsLongLong:
100       case AsChar:
101         return 2;
102       case AsInt32:
103       case AsInt64:
104         return 3;
105       case None:
106         return 0;
107     }
108   }
109
110   Kind getKind() const { return kind; }
111   void setKind(Kind k) { kind = k; }
112
113   const char *toString() const;
114
115 private:
116   const char *Position;
117   Kind kind;
118 };
119
120 class ConversionSpecifier {
121 public:
122   enum Kind {
123     InvalidSpecifier = 0,
124       // C99 conversion specifiers.
125     cArg,
126     dArg,
127     DArg, // Apple extension
128     iArg,
129     IntArgBeg = dArg, IntArgEnd = iArg,
130
131     oArg,
132     OArg, // Apple extension
133     uArg,
134     UArg, // Apple extension
135     xArg,
136     XArg,
137     UIntArgBeg = oArg, UIntArgEnd = XArg,
138
139     fArg,
140     FArg,
141     eArg,
142     EArg,
143     gArg,
144     GArg,
145     aArg,
146     AArg,
147     DoubleArgBeg = fArg, DoubleArgEnd = AArg,
148
149     sArg,
150     pArg,
151     nArg,
152     PercentArg,
153     CArg,
154     SArg,
155
156     // ** Printf-specific **
157
158     ZArg, // MS extension
159
160     // Objective-C specific specifiers.
161     ObjCObjArg,  // '@'
162     ObjCBeg = ObjCObjArg, ObjCEnd = ObjCObjArg,
163
164     // FreeBSD kernel specific specifiers.
165     FreeBSDbArg,
166     FreeBSDDArg,
167     FreeBSDrArg,
168     FreeBSDyArg,
169
170     // GlibC specific specifiers.
171     PrintErrno,   // 'm'
172
173     PrintfConvBeg = ObjCObjArg, PrintfConvEnd = PrintErrno,
174
175     // ** Scanf-specific **
176     ScanListArg, // '['
177     ScanfConvBeg = ScanListArg, ScanfConvEnd = ScanListArg
178   };
179
180   ConversionSpecifier(bool isPrintf = true)
181     : IsPrintf(isPrintf), Position(nullptr), EndScanList(nullptr),
182       kind(InvalidSpecifier) {}
183
184   ConversionSpecifier(bool isPrintf, const char *pos, Kind k)
185     : IsPrintf(isPrintf), Position(pos), EndScanList(nullptr), kind(k) {}
186
187   const char *getStart() const {
188     return Position;
189   }
190
191   StringRef getCharacters() const {
192     return StringRef(getStart(), getLength());
193   }
194
195   bool consumesDataArgument() const {
196     switch (kind) {
197       case PrintErrno:
198         assert(IsPrintf);
199         return false;
200       case PercentArg:
201         return false;
202       default:
203         return true;
204     }
205   }
206
207   Kind getKind() const { return kind; }
208   void setKind(Kind k) { kind = k; }
209   unsigned getLength() const {
210     return EndScanList ? EndScanList - Position : 1;
211   }
212
213   bool isIntArg() const { return (kind >= IntArgBeg && kind <= IntArgEnd) ||
214     kind == FreeBSDrArg || kind == FreeBSDyArg; }
215   bool isUIntArg() const { return kind >= UIntArgBeg && kind <= UIntArgEnd; }
216   bool isAnyIntArg() const { return kind >= IntArgBeg && kind <= UIntArgEnd; }
217   const char *toString() const;
218
219   bool isPrintfKind() const { return IsPrintf; }
220   
221   Optional<ConversionSpecifier> getStandardSpecifier() const;
222
223 protected:
224   bool IsPrintf;
225   const char *Position;
226   const char *EndScanList;
227   Kind kind;
228 };
229
230 class ArgType {
231 public:
232   enum Kind { UnknownTy, InvalidTy, SpecificTy, ObjCPointerTy, CPointerTy,
233               AnyCharTy, CStrTy, WCStrTy, WIntTy };
234 private:
235   const Kind K;
236   QualType T;
237   const char *Name;
238   bool Ptr;
239 public:
240   ArgType(Kind k = UnknownTy, const char *n = nullptr)
241       : K(k), Name(n), Ptr(false) {}
242   ArgType(QualType t, const char *n = nullptr)
243       : K(SpecificTy), T(t), Name(n), Ptr(false) {}
244   ArgType(CanQualType t) : K(SpecificTy), T(t), Name(nullptr), Ptr(false) {}
245
246   static ArgType Invalid() { return ArgType(InvalidTy); }
247   bool isValid() const { return K != InvalidTy; }
248
249   /// Create an ArgType which corresponds to the type pointer to A.
250   static ArgType PtrTo(const ArgType& A) {
251     assert(A.K >= InvalidTy && "ArgType cannot be pointer to invalid/unknown");
252     ArgType Res = A;
253     Res.Ptr = true;
254     return Res;
255   }
256
257   bool matchesType(ASTContext &C, QualType argTy) const;
258
259   QualType getRepresentativeType(ASTContext &C) const;
260
261   std::string getRepresentativeTypeName(ASTContext &C) const;
262 };
263
264 class OptionalAmount {
265 public:
266   enum HowSpecified { NotSpecified, Constant, Arg, Invalid };
267
268   OptionalAmount(HowSpecified howSpecified,
269                  unsigned amount,
270                  const char *amountStart,
271                  unsigned amountLength,
272                  bool usesPositionalArg)
273   : start(amountStart), length(amountLength), hs(howSpecified), amt(amount),
274   UsesPositionalArg(usesPositionalArg), UsesDotPrefix(0) {}
275
276   OptionalAmount(bool valid = true)
277   : start(nullptr),length(0), hs(valid ? NotSpecified : Invalid), amt(0),
278   UsesPositionalArg(0), UsesDotPrefix(0) {}
279
280   bool isInvalid() const {
281     return hs == Invalid;
282   }
283
284   HowSpecified getHowSpecified() const { return hs; }
285   void setHowSpecified(HowSpecified h) { hs = h; }
286
287   bool hasDataArgument() const { return hs == Arg; }
288
289   unsigned getArgIndex() const {
290     assert(hasDataArgument());
291     return amt;
292   }
293
294   unsigned getConstantAmount() const {
295     assert(hs == Constant);
296     return amt;
297   }
298
299   const char *getStart() const {
300       // We include the . character if it is given.
301     return start - UsesDotPrefix;
302   }
303
304   unsigned getConstantLength() const {
305     assert(hs == Constant);
306     return length + UsesDotPrefix;
307   }
308
309   ArgType getArgType(ASTContext &Ctx) const;
310
311   void toString(raw_ostream &os) const;
312
313   bool usesPositionalArg() const { return (bool) UsesPositionalArg; }
314   unsigned getPositionalArgIndex() const {
315     assert(hasDataArgument());
316     return amt + 1;
317   }
318
319   bool usesDotPrefix() const { return UsesDotPrefix; }
320   void setUsesDotPrefix() { UsesDotPrefix = true; }
321
322 private:
323   const char *start;
324   unsigned length;
325   HowSpecified hs;
326   unsigned amt;
327   bool UsesPositionalArg : 1;
328   bool UsesDotPrefix;
329 };
330
331
332 class FormatSpecifier {
333 protected:
334   LengthModifier LM;
335   OptionalAmount FieldWidth;
336   ConversionSpecifier CS;
337   /// Positional arguments, an IEEE extension:
338   ///  IEEE Std 1003.1, 2004 Edition
339   ///  http://www.opengroup.org/onlinepubs/009695399/functions/printf.html
340   bool UsesPositionalArg;
341   unsigned argIndex;
342 public:
343   FormatSpecifier(bool isPrintf)
344     : CS(isPrintf), UsesPositionalArg(false), argIndex(0) {}
345
346   void setLengthModifier(LengthModifier lm) {
347     LM = lm;
348   }
349
350   void setUsesPositionalArg() { UsesPositionalArg = true; }
351
352   void setArgIndex(unsigned i) {
353     argIndex = i;
354   }
355
356   unsigned getArgIndex() const {
357     return argIndex;
358   }
359
360   unsigned getPositionalArgIndex() const {
361     return argIndex + 1;
362   }
363
364   const LengthModifier &getLengthModifier() const {
365     return LM;
366   }
367
368   const OptionalAmount &getFieldWidth() const {
369     return FieldWidth;
370   }
371
372   void setFieldWidth(const OptionalAmount &Amt) {
373     FieldWidth = Amt;
374   }
375
376   bool usesPositionalArg() const { return UsesPositionalArg; }
377
378   bool hasValidLengthModifier(const TargetInfo &Target) const;
379
380   bool hasStandardLengthModifier() const;
381
382   Optional<LengthModifier> getCorrectedLengthModifier() const;
383
384   bool hasStandardConversionSpecifier(const LangOptions &LangOpt) const;
385
386   bool hasStandardLengthConversionCombination() const;
387
388   /// For a TypedefType QT, if it is a named integer type such as size_t,
389   /// assign the appropriate value to LM and return true.
390   static bool namedTypeToLengthModifier(QualType QT, LengthModifier &LM);
391 };
392
393 } // end analyze_format_string namespace
394
395 //===----------------------------------------------------------------------===//
396 /// Pieces specific to fprintf format strings.
397
398 namespace analyze_printf {
399
400 class PrintfConversionSpecifier :
401   public analyze_format_string::ConversionSpecifier  {
402 public:
403   PrintfConversionSpecifier()
404     : ConversionSpecifier(true, nullptr, InvalidSpecifier) {}
405
406   PrintfConversionSpecifier(const char *pos, Kind k)
407     : ConversionSpecifier(true, pos, k) {}
408
409   bool isObjCArg() const { return kind >= ObjCBeg && kind <= ObjCEnd; }
410   bool isDoubleArg() const { return kind >= DoubleArgBeg &&
411                                     kind <= DoubleArgEnd; }
412   unsigned getLength() const {
413       // Conversion specifiers currently only are represented by
414       // single characters, but we be flexible.
415     return 1;
416   }
417
418   static bool classof(const analyze_format_string::ConversionSpecifier *CS) {
419     return CS->isPrintfKind();
420   }
421 };
422
423 using analyze_format_string::ArgType;
424 using analyze_format_string::LengthModifier;
425 using analyze_format_string::OptionalAmount;
426 using analyze_format_string::OptionalFlag;
427
428 class PrintfSpecifier : public analyze_format_string::FormatSpecifier {
429   OptionalFlag HasThousandsGrouping; // ''', POSIX extension.
430   OptionalFlag IsLeftJustified; // '-'
431   OptionalFlag HasPlusPrefix; // '+'
432   OptionalFlag HasSpacePrefix; // ' '
433   OptionalFlag HasAlternativeForm; // '#'
434   OptionalFlag HasLeadingZeroes; // '0'
435   OptionalAmount Precision;
436 public:
437   PrintfSpecifier() :
438     FormatSpecifier(/* isPrintf = */ true),
439     HasThousandsGrouping("'"), IsLeftJustified("-"), HasPlusPrefix("+"),
440     HasSpacePrefix(" "), HasAlternativeForm("#"), HasLeadingZeroes("0") {}
441
442   static PrintfSpecifier Parse(const char *beg, const char *end);
443
444     // Methods for incrementally constructing the PrintfSpecifier.
445   void setConversionSpecifier(const PrintfConversionSpecifier &cs) {
446     CS = cs;
447   }
448   void setHasThousandsGrouping(const char *position) {
449     HasThousandsGrouping = true;
450     HasThousandsGrouping.setPosition(position);
451   }
452   void setIsLeftJustified(const char *position) {
453     IsLeftJustified = true;
454     IsLeftJustified.setPosition(position);
455   }
456   void setHasPlusPrefix(const char *position) {
457     HasPlusPrefix = true;
458     HasPlusPrefix.setPosition(position);
459   }
460   void setHasSpacePrefix(const char *position) {
461     HasSpacePrefix = true;
462     HasSpacePrefix.setPosition(position);
463   }
464   void setHasAlternativeForm(const char *position) {
465     HasAlternativeForm = true;
466     HasAlternativeForm.setPosition(position);
467   }
468   void setHasLeadingZeros(const char *position) {
469     HasLeadingZeroes = true;
470     HasLeadingZeroes.setPosition(position);
471   }
472   void setUsesPositionalArg() { UsesPositionalArg = true; }
473
474     // Methods for querying the format specifier.
475
476   const PrintfConversionSpecifier &getConversionSpecifier() const {
477     return cast<PrintfConversionSpecifier>(CS);
478   }
479
480   void setPrecision(const OptionalAmount &Amt) {
481     Precision = Amt;
482     Precision.setUsesDotPrefix();
483   }
484
485   const OptionalAmount &getPrecision() const {
486     return Precision;
487   }
488
489   bool consumesDataArgument() const {
490     return getConversionSpecifier().consumesDataArgument();
491   }
492
493   /// \brief Returns the builtin type that a data argument
494   /// paired with this format specifier should have.  This method
495   /// will return null if the format specifier does not have
496   /// a matching data argument or the matching argument matches
497   /// more than one type.
498   ArgType getArgType(ASTContext &Ctx, bool IsObjCLiteral) const;
499
500   const OptionalFlag &hasThousandsGrouping() const {
501       return HasThousandsGrouping;
502   }
503   const OptionalFlag &isLeftJustified() const { return IsLeftJustified; }
504   const OptionalFlag &hasPlusPrefix() const { return HasPlusPrefix; }
505   const OptionalFlag &hasAlternativeForm() const { return HasAlternativeForm; }
506   const OptionalFlag &hasLeadingZeros() const { return HasLeadingZeroes; }
507   const OptionalFlag &hasSpacePrefix() const { return HasSpacePrefix; }
508   bool usesPositionalArg() const { return UsesPositionalArg; }
509
510   /// Changes the specifier and length according to a QualType, retaining any
511   /// flags or options. Returns true on success, or false when a conversion
512   /// was not successful.
513   bool fixType(QualType QT, const LangOptions &LangOpt, ASTContext &Ctx,
514                bool IsObjCLiteral);
515
516   void toString(raw_ostream &os) const;
517
518   // Validation methods - to check if any element results in undefined behavior
519   bool hasValidPlusPrefix() const;
520   bool hasValidAlternativeForm() const;
521   bool hasValidLeadingZeros() const;
522   bool hasValidSpacePrefix() const;
523   bool hasValidLeftJustified() const;
524   bool hasValidThousandsGroupingPrefix() const;
525
526   bool hasValidPrecision() const;
527   bool hasValidFieldWidth() const;
528 };
529 }  // end analyze_printf namespace
530
531 //===----------------------------------------------------------------------===//
532 /// Pieces specific to fscanf format strings.
533
534 namespace analyze_scanf {
535
536 class ScanfConversionSpecifier :
537     public analyze_format_string::ConversionSpecifier  {
538 public:
539   ScanfConversionSpecifier()
540     : ConversionSpecifier(false, nullptr, InvalidSpecifier) {}
541
542   ScanfConversionSpecifier(const char *pos, Kind k)
543     : ConversionSpecifier(false, pos, k) {}
544
545   void setEndScanList(const char *pos) { EndScanList = pos; }
546
547   static bool classof(const analyze_format_string::ConversionSpecifier *CS) {
548     return !CS->isPrintfKind();
549   }
550 };
551
552 using analyze_format_string::ArgType;
553 using analyze_format_string::LengthModifier;
554 using analyze_format_string::OptionalAmount;
555 using analyze_format_string::OptionalFlag;
556
557 class ScanfSpecifier : public analyze_format_string::FormatSpecifier {
558   OptionalFlag SuppressAssignment; // '*'
559 public:
560   ScanfSpecifier() :
561     FormatSpecifier(/* isPrintf = */ false),
562     SuppressAssignment("*") {}
563
564   void setSuppressAssignment(const char *position) {
565     SuppressAssignment = true;
566     SuppressAssignment.setPosition(position);
567   }
568
569   const OptionalFlag &getSuppressAssignment() const {
570     return SuppressAssignment;
571   }
572
573   void setConversionSpecifier(const ScanfConversionSpecifier &cs) {
574     CS = cs;
575   }
576
577   const ScanfConversionSpecifier &getConversionSpecifier() const {
578     return cast<ScanfConversionSpecifier>(CS);
579   }
580
581   bool consumesDataArgument() const {
582     return CS.consumesDataArgument() && !SuppressAssignment;
583   }
584
585   ArgType getArgType(ASTContext &Ctx) const;
586
587   bool fixType(QualType QT, QualType RawQT, const LangOptions &LangOpt,
588                ASTContext &Ctx);
589
590   void toString(raw_ostream &os) const;
591
592   static ScanfSpecifier Parse(const char *beg, const char *end);
593 };
594
595 } // end analyze_scanf namespace
596
597 //===----------------------------------------------------------------------===//
598 // Parsing and processing of format strings (both fprintf and fscanf).
599
600 namespace analyze_format_string {
601
602 enum PositionContext { FieldWidthPos = 0, PrecisionPos = 1 };
603
604 class FormatStringHandler {
605 public:
606   FormatStringHandler() {}
607   virtual ~FormatStringHandler();
608
609   virtual void HandleNullChar(const char *nullCharacter) {}
610
611   virtual void HandlePosition(const char *startPos, unsigned posLen) {}
612
613   virtual void HandleInvalidPosition(const char *startPos, unsigned posLen,
614                                      PositionContext p) {}
615
616   virtual void HandleZeroPosition(const char *startPos, unsigned posLen) {}
617
618   virtual void HandleIncompleteSpecifier(const char *startSpecifier,
619                                          unsigned specifierLen) {}
620
621   // Printf-specific handlers.
622
623   virtual bool HandleInvalidPrintfConversionSpecifier(
624                                       const analyze_printf::PrintfSpecifier &FS,
625                                       const char *startSpecifier,
626                                       unsigned specifierLen) {
627     return true;
628   }
629
630   virtual bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS,
631                                      const char *startSpecifier,
632                                      unsigned specifierLen) {
633     return true;
634   }
635
636     // Scanf-specific handlers.
637
638   virtual bool HandleInvalidScanfConversionSpecifier(
639                                         const analyze_scanf::ScanfSpecifier &FS,
640                                         const char *startSpecifier,
641                                         unsigned specifierLen) {
642     return true;
643   }
644
645   virtual bool HandleScanfSpecifier(const analyze_scanf::ScanfSpecifier &FS,
646                                     const char *startSpecifier,
647                                     unsigned specifierLen) {
648     return true;
649   }
650
651   virtual void HandleIncompleteScanList(const char *start, const char *end) {}
652 };
653
654 bool ParsePrintfString(FormatStringHandler &H,
655                        const char *beg, const char *end, const LangOptions &LO,
656                        const TargetInfo &Target, bool isFreeBSDKPrintf);
657   
658 bool ParseFormatStringHasSArg(const char *beg, const char *end, const LangOptions &LO,
659                               const TargetInfo &Target);
660
661 bool ParseScanfString(FormatStringHandler &H,
662                       const char *beg, const char *end, const LangOptions &LO,
663                       const TargetInfo &Target);
664
665 } // end analyze_format_string namespace
666 } // end clang namespace
667 #endif