zcov: / lib/Analysis/PrintfFormatString.cpp


Files: 1 Branches Taken: 66.7% 88 / 132
Generated: 2010-02-10 01:31 Branches Executed: 97.0% 128 / 132
Line Coverage: 79.4% 135 / 170


Programs: 2 Runs 3018


       1                 : //= PrintfFormatStrings.cpp - Analysis of printf 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                 : // Handling of format string in printf and friends.  The structure of format
      11                 : // strings for fprintf() are described in C99 7.19.6.1.
      12                 : //
      13                 : //===----------------------------------------------------------------------===//
      14                 : 
      15                 : #include "clang/Analysis/Analyses/PrintfFormatString.h"
      16                 : #include "clang/AST/ASTContext.h"
      17                 : 
      18                 : using clang::analyze_printf::FormatSpecifier;
      19                 : using clang::analyze_printf::OptionalAmount;
      20                 : using clang::analyze_printf::ArgTypeResult;
      21                 : using clang::analyze_printf::FormatStringHandler;
      22                 : using namespace clang;
      23                 : 
      24                 : namespace {
      25                 : class FormatSpecifierResult {
      26                 :   FormatSpecifier FS;
      27                 :   const char *Start;
      28                 :   bool Stop;
      29                 : public:
      30              418:   FormatSpecifierResult(bool stop = false)
      31              418:     : Start(0), Stop(stop) {}
      32                 :   FormatSpecifierResult(const char *start,
      33              544:                         const FormatSpecifier &fs)
      34              544:     : FS(fs), Start(start), Stop(false) {}
      35                 : 
      36                 :   
      37             1088:   const char *getStart() const { return Start; }
      38              962:   bool shouldStop() const { return Stop; }
      39             1498:   bool hasValue() const { return Start != 0; }
      40              544:   const FormatSpecifier &getValue() const {
                        0: branch 1 not taken
                      544: branch 2 taken
      41              544:     assert(hasValue());
      42              544:     return FS;
      43                 :   }
      44                 :   const FormatSpecifier &getValue() { return FS; }
      45                 : };
      46                 : } // end anonymous namespace
      47                 : 
      48                 : template <typename T>
      49                 : class UpdateOnReturn {
      50                 :   T &ValueToUpdate;
      51                 :   const T &ValueToCopy;
      52                 : public:
      53             1575:   UpdateOnReturn(T &valueToUpdate, const T &valueToCopy)
      54             1575:     : ValueToUpdate(valueToUpdate), ValueToCopy(valueToCopy) {}
      55                 :   
      56             1575:   ~UpdateOnReturn() {
      57             1575:     ValueToUpdate = ValueToCopy;
      58             1575:   }
      59                 : };  
      60                 : 
      61              613: static OptionalAmount ParseAmount(const char *&Beg, const char *E) {
      62              613:   const char *I = Beg;
      63              613:   UpdateOnReturn <const char*> UpdateBeg(Beg, I);
      64                 :   
      65              613:   bool foundDigits = false;
      66              613:   unsigned accumulator = 0;
      67                 : 
                      665: branch 0 taken
                        0: branch 1 not taken
      68             1330:   for ( ; I != E; ++I) {
      69              665:     char c = *I;
                      580: branch 0 taken
                       85: branch 1 taken
                       52: branch 2 taken
                      528: branch 3 taken
      70              665:     if (c >= '0' && c <= '9') {
      71               52:       foundDigits = true;
      72               52:       accumulator += (accumulator * 10) + (c - '0');
      73                 :       continue;
      74                 :     }
      75                 : 
                       52: branch 0 taken
                      561: branch 1 taken
      76              613:     if (foundDigits)
      77               52:       return OptionalAmount(accumulator, Beg);
      78                 :     
                       18: branch 0 taken
                      543: branch 1 taken
      79              561:     if (c == '*') {
      80               18:       ++I;
      81               18:       return OptionalAmount(OptionalAmount::Arg, Beg);
      82                 :     }
      83                 :     
      84              543:     break;
      85                 :   }
      86                 :   
      87              543:   return OptionalAmount();  
      88                 : }
      89                 : 
      90                 : static FormatSpecifierResult ParseFormatSpecifier(FormatStringHandler &H,
      91                 :                                                   const char *&Beg,
      92              962:                                                   const char *E) {
      93                 :   
      94                 :   using namespace clang::analyze_printf;
      95                 :   
      96              962:   const char *I = Beg;
      97              962:   const char *Start = 0;
      98              962:   UpdateOnReturn <const char*> UpdateBeg(Beg, I);
      99                 : 
     100                 :   // Look for a '%' character that indicates the start of a format specifier.
                     5108: branch 0 taken
                      403: branch 1 taken
     101             5511:   for ( ; I != E ; ++I) {
     102             5108:     char c = *I;
                        4: branch 0 taken
                     5104: branch 1 taken
     103             5108:     if (c == '\0') {
     104                 :       // Detect spurious null characters, which are likely errors.
     105                4:       H.HandleNullChar(I);
     106                4:       return true;
     107                 :     }
                      555: branch 0 taken
                     4549: branch 1 taken
     108             5104:     if (c == '%') {
     109              555:       Start = I++;  // Record the start of the format specifier.
     110              555:       break;
     111                 :     }
     112                 :   }
     113                 :   
     114                 :   // No format specifier found?
                      403: branch 0 taken
                      555: branch 1 taken
     115              958:   if (!Start)
     116              403:     return false;
     117                 :   
                        1: branch 0 taken
                      554: branch 1 taken
     118              555:   if (I == E) {
     119                 :     // No more characters left?
     120                1:     H.HandleIncompleteFormatSpecifier(Start, E - Start);
     121                1:     return true;
     122                 :   }
     123                 :       
     124              554:   FormatSpecifier FS;
     125                 :   
     126                 :   // Look for flags (if any).
     127              554:   bool hasMore = true;
                      554: branch 0 taken
                        0: branch 1 not taken
     128              554:   for ( ; I != E; ++I) {
                      554: branch 0 taken
                        0: branch 1 not taken
                        0: branch 2 not taken
                        0: branch 3 not taken
                        0: branch 4 not taken
                        0: branch 5 not taken
     129              554:     switch (*I) {
     130              554:       default: hasMore = false; break;
     131                0:       case '-': FS.setIsLeftJustified(); break;
     132                0:       case '+': FS.setHasPlusPrefix(); break;
     133                0:       case ' ': FS.setHasSpacePrefix(); break;
     134                0:       case '#': FS.setHasAlternativeForm(); break;
     135                0:       case '0': FS.setHasLeadingZeros(); break;
     136                 :     }
                      554: branch 0 taken
                        0: branch 1 not taken
     137              554:     if (!hasMore)
     138              554:       break;
     139                 :   }      
     140                 : 
                        0: branch 0 not taken
                      554: branch 1 taken
     141              554:   if (I == E) {
     142                 :     // No more characters left?
     143                0:     H.HandleIncompleteFormatSpecifier(Start, E - Start);
     144                0:     return true;
     145                 :   }
     146                 :   
     147                 :   // Look for the field width (if any).
     148              554:   FS.setFieldWidth(ParseAmount(I, E));
     149                 :       
                        0: branch 0 not taken
                      554: branch 1 taken
     150              554:   if (I == E) {
     151                 :     // No more characters left?
     152                0:     H.HandleIncompleteFormatSpecifier(Start, E - Start);
     153                0:     return true;
     154                 :   }  
     155                 :   
     156                 :   // Look for the precision (if any).  
                       60: branch 0 taken
                      494: branch 1 taken
     157              554:   if (*I == '.') {
     158               60:     ++I;
                        1: branch 0 taken
                       59: branch 1 taken
     159               60:     if (I == E) {
     160                1:       H.HandleIncompleteFormatSpecifier(Start, E - Start);
     161                1:       return true;
     162                 :     }
     163                 :     
     164               59:     FS.setPrecision(ParseAmount(I, E));
     165                 : 
                        0: branch 0 not taken
                       59: branch 1 taken
     166               59:     if (I == E) {
     167                 :       // No more characters left?
     168                0:       H.HandleIncompleteFormatSpecifier(Start, E - Start);
     169                0:       return true;
     170                 :     }
     171                 :   }
     172                 : 
     173                 :   // Look for the length modifier.
     174              553:   LengthModifier lm = None;
                      542: branch 0 taken
                        1: branch 1 taken
                        6: branch 2 taken
                        0: branch 3 not taken
                        2: branch 4 taken
                        0: branch 5 not taken
                        1: branch 6 taken
                        1: branch 7 taken
     175              553:   switch (*I) {
     176                 :     default:
     177              542:       break;
     178                 :     case 'h':
     179                1:       ++I;
                        1: branch 0 taken
                        0: branch 1 not taken
                        1: branch 2 taken
                        0: branch 3 not taken
     180                1:       lm = (I != E && *I == 'h') ? ++I, AsChar : AsShort;      
     181                1:       break;
     182                 :     case 'l':
     183                6:       ++I;
                        5: branch 0 taken
                        1: branch 1 taken
                        1: branch 2 taken
                        4: branch 3 taken
     184                6:       lm = (I != E && *I == 'l') ? ++I, AsLongLong : AsLong;
     185                6:       break;
     186                0:     case 'j': lm = AsIntMax;     ++I; break;
     187                2:     case 'z': lm = AsSizeT;      ++I; break;
     188                0:     case 't': lm = AsPtrDiff;    ++I; break;
     189                1:     case 'L': lm = AsLongDouble; ++I; break;
     190                1:     case 'q': lm = AsLongLong;   ++I; break;
     191                 :   }
     192              553:   FS.setLengthModifier(lm);
     193                 :   
                        1: branch 0 taken
                      552: branch 1 taken
     194              553:   if (I == E) {
     195                 :     // No more characters left?
     196                1:     H.HandleIncompleteFormatSpecifier(Start, E - Start);
     197                1:     return true;
     198                 :   }
     199                 : 
                        1: branch 0 taken
                      551: branch 1 taken
     200              552:   if (*I == '\0') {
     201                 :     // Detect spurious null characters, which are likely errors.
     202                1:     H.HandleNullChar(I);
     203                1:     return true;
     204                 :   }
     205                 :   
     206                 :   // Finally, look for the conversion specifier.
     207              551:   const char *conversionPosition = I++;
     208              551:   ConversionSpecifier::Kind k = ConversionSpecifier::InvalidSpecifier;
                        7: branch 0 taken
                      298: branch 1 taken
                        2: branch 2 taken
                        0: branch 3 not taken
                        0: branch 4 not taken
                        6: branch 5 taken
                        2: branch 6 taken
                      130: branch 7 taken
                        0: branch 8 not taken
                        0: branch 9 not taken
                        0: branch 10 not taken
                        0: branch 11 not taken
                        0: branch 12 not taken
                        0: branch 13 not taken
                        0: branch 14 not taken
                        0: branch 15 not taken
                       72: branch 16 taken
                        4: branch 17 taken
                        4: branch 18 taken
                        9: branch 19 taken
                       15: branch 20 taken
                        2: branch 21 taken
     209              551:   switch (*conversionPosition) {
     210                 :     default:
     211                7:       break;
     212                 :     // C99: 7.19.6.1 (section 8).
     213              298:     case 'd': k = ConversionSpecifier::dArg; break;
     214                2:     case 'i': k = ConversionSpecifier::iArg; break;
     215                0:     case 'o': k = ConversionSpecifier::oArg; break;
     216                0:     case 'u': k = ConversionSpecifier::uArg; break;
     217                6:     case 'x': k = ConversionSpecifier::xArg; break;
     218                2:     case 'X': k = ConversionSpecifier::XArg; break;
     219              130:     case 'f': k = ConversionSpecifier::fArg; break;
     220                0:     case 'F': k = ConversionSpecifier::FArg; break;
     221                0:     case 'e': k = ConversionSpecifier::eArg; break;
     222                0:     case 'E': k = ConversionSpecifier::EArg; break;
     223                0:     case 'g': k = ConversionSpecifier::gArg; break;
     224                0:     case 'G': k = ConversionSpecifier::GArg; break;
     225                0:     case 'a': k = ConversionSpecifier::aArg; break;
     226                0:     case 'A': k = ConversionSpecifier::AArg; break;
     227                0:     case 'c': k = ConversionSpecifier::IntAsCharArg; break;
     228               72:     case 's': k = ConversionSpecifier::CStrArg;      break;
     229                4:     case 'p': k = ConversionSpecifier::VoidPtrArg;   break;
     230                4:     case 'n': k = ConversionSpecifier::OutIntPtrArg; break;
     231                9:     case '%': k = ConversionSpecifier::PercentArg;   break;      
     232                 :     // Objective-C.
     233               15:     case '@': k = ConversionSpecifier::ObjCObjArg; break;
     234                 :     // Glibc specific.
     235                2:     case 'm': k = ConversionSpecifier::PrintErrno; break;
     236                 :   }
     237              551:   FS.setConversionSpecifier(ConversionSpecifier(conversionPosition, k));
     238                 : 
                        7: branch 0 taken
                      544: branch 1 taken
     239              551:   if (k == ConversionSpecifier::InvalidSpecifier) {
     240                7:     H.HandleInvalidConversionSpecifier(FS, Beg, I - Beg);
     241                7:     return false; // Keep processing format specifiers.
     242                 :   }
     243              544:   return FormatSpecifierResult(Start, FS);
     244                 : }
     245                 : 
     246                 : bool clang::analyze_printf::ParseFormatString(FormatStringHandler &H,
     247              473:                        const char *I, const char *E) {
     248                 :   // Keep looking for a format specifier until we have exhausted the string.
                      962: branch 0 taken
                      454: branch 1 taken
     249             1889:   while (I != E) {
     250              962:     const FormatSpecifierResult &FSR = ParseFormatSpecifier(H, I, E);
     251                 :     // Did a fail-stop error of any kind occur when parsing the specifier?
     252                 :     // If so, don't do any more processing.
                        8: branch 1 taken
                      954: branch 2 taken
     253              962:     if (FSR.shouldStop())
     254                8:       return true;;
     255                 :     // Did we exhaust the string or encounter an error that
     256                 :     // we can recover from?
                      544: branch 1 taken
                      410: branch 2 taken
     257              954:     if (!FSR.hasValue())
     258              410:       continue;
     259                 :     // We have a format specifier.  Pass it to the callback.
                       11: branch 4 taken
                      533: branch 5 taken
     260              544:     if (!H.HandleFormatSpecifier(FSR.getValue(), FSR.getStart(),
     261                 :                                  I - FSR.getStart()))
     262               11:       return true;
     263                 :   }  
                        0: branch 0 not taken
                      454: branch 1 taken
     264              454:   assert(I == E && "Format string not exhausted");      
     265              454:   return false;
     266                 : }
     267                 : 
                      473: branch 0 taken
                      473: branch 1 taken
                        0: branch 3 not taken
                        0: branch 4 not taken
                        0: branch 6 not taken
                      473: branch 7 taken
     268              473: FormatStringHandler::~FormatStringHandler() {}
     269                 : 
     270                 : //===----------------------------------------------------------------------===//
     271                 : // Methods on FormatSpecifier.
     272                 : //===----------------------------------------------------------------------===//
     273                 : 
     274              515: ArgTypeResult FormatSpecifier::getArgType(ASTContext &Ctx) const {
                        0: branch 1 not taken
                      515: branch 2 taken
     275              515:   if (!CS.consumesDataArgument())
     276                0:     return ArgTypeResult::Invalid();
     277                 :   
                      288: branch 1 taken
                      227: branch 2 taken
     278              515:   if (CS.isIntArg())
                        0: branch 0 not taken
                      283: branch 1 taken
                        0: branch 2 not taken
                        0: branch 3 not taken
                        2: branch 4 taken
                        1: branch 5 taken
                        0: branch 6 not taken
                        2: branch 7 taken
                        0: branch 8 not taken
                        0: branch 9 not taken
     279              288:     switch (LM) {
     280                 :       case AsLongDouble: 
     281                0:         return ArgTypeResult::Invalid();
     282              283:       case None: return Ctx.IntTy;
     283                0:       case AsChar: return Ctx.SignedCharTy;
     284                0:       case AsShort: return Ctx.ShortTy;
     285                2:       case AsLong: return Ctx.LongTy;
     286                1:       case AsLongLong: return Ctx.LongLongTy;
     287                 :       case AsIntMax:
     288                 :         // FIXME: Return unknown for now.
     289                0:         return ArgTypeResult();
     290                2:       case AsSizeT: return Ctx.getSizeType();
     291                0:       case AsPtrDiff: return Ctx.getPointerDiffType();
     292                 :     }
     293                 : 
                        8: branch 1 taken
                      219: branch 2 taken
     294              227:   if (CS.isUIntArg())
                        0: branch 0 not taken
                        6: branch 1 taken
                        1: branch 2 taken
                        0: branch 3 not taken
                        0: branch 4 not taken
                        1: branch 5 taken
                        0: branch 6 not taken
                        0: branch 7 not taken
                        0: branch 8 not taken
                        0: branch 9 not taken
     295                8:     switch (LM) {
     296                 :       case AsLongDouble: 
     297                0:         return ArgTypeResult::Invalid();
     298                6:       case None: return Ctx.UnsignedIntTy;
     299                1:       case AsChar: return Ctx.UnsignedCharTy;
     300                0:       case AsShort: return Ctx.UnsignedShortTy;
     301                0:       case AsLong: return Ctx.UnsignedLongTy;
     302                1:       case AsLongLong: return Ctx.UnsignedLongLongTy;
     303                 :       case AsIntMax:
     304                 :         // FIXME: Return unknown for now.
     305                0:         return ArgTypeResult();
     306                 :       case AsSizeT: 
     307                 :         // FIXME: How to get the corresponding unsigned
     308                 :         // version of size_t?
     309                0:         return ArgTypeResult();
     310                 :       case AsPtrDiff:
     311                 :         // FIXME: How to get the corresponding unsigned
     312                 :         // version of ptrdiff_t?
     313                0:         return ArgTypeResult();
     314                 :     }
     315                 :   
                      130: branch 1 taken
                       89: branch 2 taken
     316              219:   if (CS.isDoubleArg()) {
                        1: branch 0 taken
                      129: branch 1 taken
     317              130:     if (LM == AsLongDouble)
     318                1:       return Ctx.LongDoubleTy;
     319              129:     return Ctx.DoubleTy;
     320                 :   }
     321                 : 
     322                 :   // FIXME: Handle other cases.
     323               89:   return ArgTypeResult();
     324                 : }
     325                 : 

Generated: 2010-02-10 01:31 by zcov