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