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