]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/clang/include/clang/Analysis/Analyses/FormatString.h
MFV of 213310, tzdata2010m
[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 //===----------------------------------------------------------------------===//
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     
151     // GlibC specific specifiers.
152     PrintErrno,   // 'm'
153     
154     PrintfConvBeg = ObjCObjArg, PrintfConvEnd = PrintErrno,
155     
156     // ** Scanf-specific **    
157     ScanListArg, // '['
158     ScanfConvBeg = ScanListArg, ScanfConvEnd = ScanListArg
159   };
160   
161   ConversionSpecifier(bool isPrintf)
162     : IsPrintf(isPrintf), Position(0), EndScanList(0), kind(InvalidSpecifier) {}
163   
164   ConversionSpecifier(bool isPrintf, const char *pos, Kind k)
165     : IsPrintf(isPrintf), Position(pos), EndScanList(0), kind(k) {}
166   
167   const char *getStart() const {
168     return Position;
169   }
170   
171   llvm::StringRef getCharacters() const {
172     return llvm::StringRef(getStart(), getLength());
173   }
174   
175   bool consumesDataArgument() const {
176     switch (kind) {
177       case PrintErrno:
178         assert(IsPrintf);
179       case PercentArg:
180         return false;
181       default:
182         return true;
183     }
184   }
185   
186   Kind getKind() const { return kind; }
187   void setKind(Kind k) { kind = k; }
188   unsigned getLength() const {
189     return EndScanList ? EndScanList - Position : 1;
190   }
191   
192   const char *toString() const;
193   
194   bool isPrintfKind() const { return IsPrintf; }
195
196 protected:
197   bool IsPrintf;
198   const char *Position;
199   const char *EndScanList;
200   Kind kind;
201 };
202
203 class ArgTypeResult {
204 public:
205   enum Kind { UnknownTy, InvalidTy, SpecificTy, ObjCPointerTy, CPointerTy,
206     CStrTy, WCStrTy, WIntTy };
207 private:
208   const Kind K;
209   QualType T;
210   ArgTypeResult(bool) : K(InvalidTy) {}
211 public:
212   ArgTypeResult(Kind k = UnknownTy) : K(k) {}
213   ArgTypeResult(QualType t) : K(SpecificTy), T(t) {}
214   ArgTypeResult(CanQualType t) : K(SpecificTy), T(t) {}
215
216   static ArgTypeResult Invalid() { return ArgTypeResult(true); }
217
218   bool isValid() const { return K != InvalidTy; }
219
220   const QualType *getSpecificType() const {
221     return K == SpecificTy ? &T : 0;
222   }
223
224   bool matchesType(ASTContext &C, QualType argTy) const;
225
226   bool matchesAnyObjCObjectRef() const { return K == ObjCPointerTy; }
227
228   QualType getRepresentativeType(ASTContext &C) const;
229 };
230
231 class OptionalAmount {
232 public:
233   enum HowSpecified { NotSpecified, Constant, Arg, Invalid };
234
235   OptionalAmount(HowSpecified howSpecified,
236                  unsigned amount,
237                  const char *amountStart,
238                  unsigned amountLength,
239                  bool usesPositionalArg)
240   : start(amountStart), length(amountLength), hs(howSpecified), amt(amount),
241   UsesPositionalArg(usesPositionalArg), UsesDotPrefix(0) {}
242
243   OptionalAmount(bool valid = true)
244   : start(0),length(0), hs(valid ? NotSpecified : Invalid), amt(0),
245   UsesPositionalArg(0), UsesDotPrefix(0) {}
246
247   bool isInvalid() const {
248     return hs == Invalid;
249   }
250
251   HowSpecified getHowSpecified() const { return hs; }
252   void setHowSpecified(HowSpecified h) { hs = h; }
253
254   bool hasDataArgument() const { return hs == Arg; }
255
256   unsigned getArgIndex() const {
257     assert(hasDataArgument());
258     return amt;
259   }
260
261   unsigned getConstantAmount() const {
262     assert(hs == Constant);
263     return amt;
264   }
265
266   const char *getStart() const {
267       // We include the . character if it is given.
268     return start - UsesDotPrefix;
269   }
270
271   unsigned getConstantLength() const {
272     assert(hs == Constant);
273     return length + UsesDotPrefix;
274   }
275
276   ArgTypeResult getArgType(ASTContext &Ctx) const;
277
278   void toString(llvm::raw_ostream &os) const;
279
280   bool usesPositionalArg() const { return (bool) UsesPositionalArg; }
281   unsigned getPositionalArgIndex() const {
282     assert(hasDataArgument());
283     return amt + 1;
284   }
285
286   bool usesDotPrefix() const { return UsesDotPrefix; }
287   void setUsesDotPrefix() { UsesDotPrefix = true; }
288
289 private:
290   const char *start;
291   unsigned length;
292   HowSpecified hs;
293   unsigned amt;
294   bool UsesPositionalArg : 1;
295   bool UsesDotPrefix;
296 };
297
298
299 class FormatSpecifier {
300 protected:
301   LengthModifier LM;
302   OptionalAmount FieldWidth;
303   ConversionSpecifier CS;
304     /// Positional arguments, an IEEE extension:
305     ///  IEEE Std 1003.1, 2004 Edition
306     ///  http://www.opengroup.org/onlinepubs/009695399/functions/printf.html
307   bool UsesPositionalArg;
308   unsigned argIndex;
309 public:
310   FormatSpecifier(bool isPrintf)
311     : CS(isPrintf), UsesPositionalArg(false), argIndex(0) {}
312
313   void setLengthModifier(LengthModifier lm) {
314     LM = lm;
315   }
316
317   void setUsesPositionalArg() { UsesPositionalArg = true; }
318
319   void setArgIndex(unsigned i) {
320     argIndex = i;
321   }
322
323   unsigned getArgIndex() const {
324     return argIndex;
325   }
326
327   unsigned getPositionalArgIndex() const {
328     return argIndex + 1;
329   }
330
331   const LengthModifier &getLengthModifier() const {
332     return LM;
333   }
334
335   const OptionalAmount &getFieldWidth() const {
336     return FieldWidth;
337   }
338
339   void setFieldWidth(const OptionalAmount &Amt) {
340     FieldWidth = Amt;
341   }
342
343   bool usesPositionalArg() const { return UsesPositionalArg; }
344   
345   bool hasValidLengthModifier() const;
346 };
347
348 } // end analyze_format_string namespace
349
350 //===----------------------------------------------------------------------===//
351 /// Pieces specific to fprintf format strings.
352
353 namespace analyze_printf {
354
355 class PrintfConversionSpecifier : 
356   public analyze_format_string::ConversionSpecifier  {
357 public:
358   PrintfConversionSpecifier()
359     : ConversionSpecifier(true, 0, InvalidSpecifier) {}
360
361   PrintfConversionSpecifier(const char *pos, Kind k)
362     : ConversionSpecifier(true, pos, k) {}
363
364   bool isObjCArg() const { return kind >= ObjCBeg && kind <= ObjCEnd; }
365   bool isIntArg() const { return kind >= IntArgBeg && kind <= IntArgEnd; }
366   bool isUIntArg() const { return kind >= UIntArgBeg && kind <= UIntArgEnd; }
367   bool isDoubleArg() const { return kind >= DoubleArgBeg && 
368                                     kind <= DoubleArgBeg; }
369   unsigned getLength() const {
370       // Conversion specifiers currently only are represented by
371       // single characters, but we be flexible.
372     return 1;
373   }
374
375   static bool classof(const analyze_format_string::ConversionSpecifier *CS) {
376     return CS->isPrintfKind();
377   }
378 };
379
380 using analyze_format_string::ArgTypeResult;
381 using analyze_format_string::LengthModifier;
382 using analyze_format_string::OptionalAmount;
383 using analyze_format_string::OptionalFlag;
384
385 class PrintfSpecifier : public analyze_format_string::FormatSpecifier {
386   OptionalFlag IsLeftJustified; // '-'
387   OptionalFlag HasPlusPrefix; // '+'
388   OptionalFlag HasSpacePrefix; // ' '
389   OptionalFlag HasAlternativeForm; // '#'
390   OptionalFlag HasLeadingZeroes; // '0'
391   OptionalAmount Precision;
392 public:
393   PrintfSpecifier() :
394     FormatSpecifier(/* isPrintf = */ true),
395     IsLeftJustified("-"), HasPlusPrefix("+"), HasSpacePrefix(" "),
396     HasAlternativeForm("#"), HasLeadingZeroes("0") {}
397
398   static PrintfSpecifier Parse(const char *beg, const char *end);
399
400     // Methods for incrementally constructing the PrintfSpecifier.
401   void setConversionSpecifier(const PrintfConversionSpecifier &cs) {
402     CS = cs;
403   }
404   void setIsLeftJustified(const char *position) {
405     IsLeftJustified = true;
406     IsLeftJustified.setPosition(position);
407   }
408   void setHasPlusPrefix(const char *position) {
409     HasPlusPrefix = true;
410     HasPlusPrefix.setPosition(position);
411   }
412   void setHasSpacePrefix(const char *position) {
413     HasSpacePrefix = true;
414     HasSpacePrefix.setPosition(position);
415   }
416   void setHasAlternativeForm(const char *position) {
417     HasAlternativeForm = true;
418     HasAlternativeForm.setPosition(position);
419   }
420   void setHasLeadingZeros(const char *position) {
421     HasLeadingZeroes = true;
422     HasLeadingZeroes.setPosition(position);
423   }
424   void setUsesPositionalArg() { UsesPositionalArg = true; }
425
426     // Methods for querying the format specifier.
427
428   const PrintfConversionSpecifier &getConversionSpecifier() const {
429     return cast<PrintfConversionSpecifier>(CS);
430   }
431
432   void setPrecision(const OptionalAmount &Amt) {
433     Precision = Amt;
434     Precision.setUsesDotPrefix();
435   }
436
437   const OptionalAmount &getPrecision() const {
438     return Precision;
439   }
440   
441   bool consumesDataArgument() const {
442     return getConversionSpecifier().consumesDataArgument();
443   }
444
445   /// \brief Returns the builtin type that a data argument
446   /// paired with this format specifier should have.  This method
447   /// will return null if the format specifier does not have
448   /// a matching data argument or the matching argument matches
449   /// more than one type.
450   ArgTypeResult getArgType(ASTContext &Ctx) const;
451
452   const OptionalFlag &isLeftJustified() const { return IsLeftJustified; }
453   const OptionalFlag &hasPlusPrefix() const { return HasPlusPrefix; }
454   const OptionalFlag &hasAlternativeForm() const { return HasAlternativeForm; }
455   const OptionalFlag &hasLeadingZeros() const { return HasLeadingZeroes; }
456   const OptionalFlag &hasSpacePrefix() const { return HasSpacePrefix; }
457   bool usesPositionalArg() const { return UsesPositionalArg; }
458
459     /// Changes the specifier and length according to a QualType, retaining any
460     /// flags or options. Returns true on success, or false when a conversion
461     /// was not successful.
462   bool fixType(QualType QT);
463
464   void toString(llvm::raw_ostream &os) const;
465
466     // Validation methods - to check if any element results in undefined behavior
467   bool hasValidPlusPrefix() const;
468   bool hasValidAlternativeForm() const;
469   bool hasValidLeadingZeros() const;
470   bool hasValidSpacePrefix() const;
471   bool hasValidLeftJustified() const;
472
473   bool hasValidPrecision() const;
474   bool hasValidFieldWidth() const;
475 };
476 }  // end analyze_printf namespace
477
478 //===----------------------------------------------------------------------===//
479 /// Pieces specific to fscanf format strings.
480
481 namespace analyze_scanf {
482
483 class ScanfConversionSpecifier :
484     public analyze_format_string::ConversionSpecifier  {
485 public:
486   ScanfConversionSpecifier()
487     : ConversionSpecifier(false, 0, InvalidSpecifier) {}
488
489   ScanfConversionSpecifier(const char *pos, Kind k)
490     : ConversionSpecifier(false, pos, k) {}
491
492   void setEndScanList(const char *pos) { EndScanList = pos; }
493       
494   static bool classof(const analyze_format_string::ConversionSpecifier *CS) {
495     return !CS->isPrintfKind();
496   }      
497 };
498
499 using analyze_format_string::LengthModifier;
500 using analyze_format_string::OptionalAmount;
501 using analyze_format_string::OptionalFlag;
502
503 class ScanfSpecifier : public analyze_format_string::FormatSpecifier {
504   OptionalFlag SuppressAssignment; // '*'
505 public:
506   ScanfSpecifier() :
507     FormatSpecifier(/* isPrintf = */ false),
508     SuppressAssignment("*") {}
509
510   void setSuppressAssignment(const char *position) {
511     SuppressAssignment = true;
512     SuppressAssignment.setPosition(position);
513   }
514
515   const OptionalFlag &getSuppressAssignment() const {
516     return SuppressAssignment;
517   }
518
519   void setConversionSpecifier(const ScanfConversionSpecifier &cs) {
520     CS = cs;
521   }
522
523   const ScanfConversionSpecifier &getConversionSpecifier() const {
524     return cast<ScanfConversionSpecifier>(CS);
525   }
526   
527   bool consumesDataArgument() const {
528     return CS.consumesDataArgument() && !SuppressAssignment;
529   }
530
531   static ScanfSpecifier Parse(const char *beg, const char *end);
532 };
533
534 } // end analyze_scanf namespace
535
536 //===----------------------------------------------------------------------===//
537 // Parsing and processing of format strings (both fprintf and fscanf).
538
539 namespace analyze_format_string {
540
541 enum PositionContext { FieldWidthPos = 0, PrecisionPos = 1 };
542
543 class FormatStringHandler {
544 public:
545   FormatStringHandler() {}
546   virtual ~FormatStringHandler();
547
548   virtual void HandleNullChar(const char *nullCharacter) {}
549
550   virtual void HandleInvalidPosition(const char *startPos, unsigned posLen,
551                                      PositionContext p) {}
552
553   virtual void HandleZeroPosition(const char *startPos, unsigned posLen) {}
554
555   virtual void HandleIncompleteSpecifier(const char *startSpecifier,
556                                          unsigned specifierLen) {}
557
558   // Printf-specific handlers.
559
560   virtual bool HandleInvalidPrintfConversionSpecifier(
561                                       const analyze_printf::PrintfSpecifier &FS,
562                                       const char *startSpecifier,
563                                       unsigned specifierLen) {
564     return true;
565   }
566
567   virtual bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS,
568                                      const char *startSpecifier,
569                                      unsigned specifierLen) {
570     return true;
571   }
572
573     // Scanf-specific handlers.
574
575   virtual bool HandleInvalidScanfConversionSpecifier(
576                                         const analyze_scanf::ScanfSpecifier &FS,
577                                         const char *startSpecifier,
578                                         unsigned specifierLen) {
579     return true;
580   }
581
582   virtual bool HandleScanfSpecifier(const analyze_scanf::ScanfSpecifier &FS,
583                                     const char *startSpecifier,
584                                     unsigned specifierLen) {
585     return true;
586   }
587
588   virtual void HandleIncompleteScanList(const char *start, const char *end) {}
589 };
590
591 bool ParsePrintfString(FormatStringHandler &H,
592                        const char *beg, const char *end,
593                        bool FormatExtensions);
594
595 bool ParseScanfString(FormatStringHandler &H,
596                        const char *beg, const char *end);
597
598 } // end analyze_format_string namespace
599 } // end clang namespace
600 #endif