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