LCOV - code coverage report
Current view: top level - lib - checkexceptionsafety.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 73 76 96.1 %
Date: 2013-03-30 Functions: 6 6 100.0 %
Branches: 87 108 80.6 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Cppcheck - A tool for static C/C++ code analysis
       3                 :            :  * Copyright (C) 2007-2013 Daniel Marjamäki and Cppcheck team.
       4                 :            :  *
       5                 :            :  * This program is free software: you can redistribute it and/or modify
       6                 :            :  * it under the terms of the GNU General Public License as published by
       7                 :            :  * the Free Software Foundation, either version 3 of the License, or
       8                 :            :  * (at your option) any later version.
       9                 :            :  *
      10                 :            :  * This program is distributed in the hope that it will be useful,
      11                 :            :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      12                 :            :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      13                 :            :  * GNU General Public License for more details.
      14                 :            :  *
      15                 :            :  * You should have received a copy of the GNU General Public License
      16                 :            :  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
      17                 :            :  */
      18                 :            : 
      19                 :            : //---------------------------------------------------------------------------
      20                 :            : #include "checkexceptionsafety.h"
      21                 :            : #include "symboldatabase.h"
      22                 :            : #include "token.h"
      23                 :            : 
      24                 :            : //---------------------------------------------------------------------------
      25                 :            : 
      26                 :            : // Register CheckExceptionSafety..
      27                 :            : namespace {
      28                 :         45 :     CheckExceptionSafety instance;
      29                 :            : }
      30                 :            : 
      31                 :            : 
      32                 :            : //---------------------------------------------------------------------------
      33                 :            : 
      34                 :       1771 : void CheckExceptionSafety::destructors()
      35                 :            : {
      36                 :       1771 :     const SymbolDatabase* const symbolDatabase = _tokenizer->getSymbolDatabase();
      37                 :            : 
      38                 :            :     // Perform check..
      39                 :       1771 :     const std::size_t functions = symbolDatabase->functionScopes.size();
      40         [ +  + ]:       3542 :     for (std::size_t i = 0; i < functions; ++i) {
      41                 :       1771 :         const Scope * scope = symbolDatabase->functionScopes[i];
      42                 :       1771 :         const Function * j = scope->function;
      43         [ +  + ]:       1771 :         if (j) {
      44                 :            :             // only looking for destructors
      45         [ +  + ]:       1726 :             if (j->type == Function::eDestructor) {
      46                 :            :                 // Inspect this destructor..
      47         [ +  + ]:        630 :                 for (const Token *tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) {
      48                 :            :                     // Skip try blocks
      49         [ +  + ]:        495 :                     if (Token::simpleMatch(tok, "try {")) {
      50                 :         45 :                         tok = tok->next()->link();
      51                 :            :                     }
      52                 :            : 
      53                 :            :                     // throw found within a destructor
      54         [ +  + ]:        495 :                     if (tok->str() == "throw") {
      55                 :         90 :                         destructorsError(tok);
      56                 :         90 :                         break;
      57                 :            :                     }
      58                 :            :                 }
      59                 :            :             }
      60                 :            :         }
      61                 :            :     }
      62                 :       1771 : }
      63                 :            : 
      64                 :            : 
      65                 :            : 
      66                 :            : 
      67                 :       1771 : void CheckExceptionSafety::deallocThrow()
      68                 :            : {
      69 [ +  - ][ +  - ]:       1771 :     if (!_settings->isEnabled("warning"))
         [ +  - ][ +  + ]
      70                 :       1771 :         return;
      71                 :            : 
      72                 :       1035 :     const SymbolDatabase* const symbolDatabase = _tokenizer->getSymbolDatabase();
      73                 :            : 
      74                 :            :     // Deallocate a global/member pointer and then throw exception
      75                 :            :     // the pointer will be a dead pointer
      76                 :       1035 :     const std::size_t functions = symbolDatabase->functionScopes.size();
      77         [ +  + ]:       2070 :     for (std::size_t i = 0; i < functions; ++i) {
      78                 :       1035 :         const Scope * scope = symbolDatabase->functionScopes[i];
      79         [ +  + ]:      20025 :         for (const Token *tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) {
      80                 :            :             // only looking for delete now
      81         [ +  + ]:      18990 :             if (tok->str() != "delete")
      82                 :      18720 :                 continue;
      83                 :            : 
      84                 :            :             // Check if this is something similar with: "delete p;"
      85                 :        270 :             tok = tok->next();
      86         [ -  + ]:        270 :             if (Token::simpleMatch(tok, "[ ]"))
      87                 :          0 :                 tok = tok->tokAt(2);
      88         [ -  + ]:        270 :             if (!tok)
      89                 :          0 :                 break;
      90         [ -  + ]:        270 :             if (!Token::Match(tok, "%var% ;"))
      91                 :          0 :                 continue;
      92                 :            : 
      93                 :            :             // we only look for global variables
      94                 :        270 :             const Variable *var = tok->variable();
      95 [ +  - ][ +  + ]:        270 :             if (!var || !(var->isGlobal() || var->isStatic()))
         [ +  + ][ +  + ]
      96                 :         45 :                 continue;
      97                 :            : 
      98                 :        225 :             const unsigned int varid(tok->varId());
      99                 :            : 
     100                 :            :             // Token where throw occurs
     101                 :        225 :             const Token *ThrowToken = 0;
     102                 :            : 
     103                 :            :             // is there a throw after the deallocation?
     104                 :        225 :             const Token* const end2 = tok->scope()->classEnd;
     105         [ +  + ]:       1665 :             for (const Token *tok2 = tok; tok2 != end2; tok2 = tok2->next()) {
     106                 :            :                 // Throw after delete -> Dead pointer
     107         [ +  + ]:       1620 :                 if (tok2->str() == "throw") {
     108         [ +  + ]:        180 :                     if (_settings->inconclusive) { // For inconclusive checking, throw directly.
     109                 :         45 :                         deallocThrowError(tok2, tok->str());
     110                 :         45 :                         break;
     111                 :            :                     }
     112                 :        135 :                     ThrowToken = tok2;
     113                 :            :                 }
     114                 :            : 
     115                 :            :                 // Variable is assigned -> Bail out
     116         [ +  + ]:       1440 :                 else if (Token::Match(tok2, "%varid% =", varid)) {
     117         [ +  - ]:         90 :                     if (ThrowToken) // For non-inconclusive checking, wait until we find an assignment to it. Otherwise we assume it is safe to leave a dead pointer.
     118                 :         90 :                         deallocThrowError(ThrowToken, tok2->str());
     119                 :         90 :                     break;
     120                 :            :                 }
     121                 :            :                 // Variable passed to function. Assume it becomes assigned -> Bail out
     122         [ +  + ]:       1350 :                 else if (Token::Match(tok2, "[,(] &| %varid% [,)]", varid)) // TODO: No bailout if passed by value or as const reference
     123                 :         45 :                     break;
     124                 :            :             }
     125                 :            :         }
     126                 :            :     }
     127                 :            : }
     128                 :            : 
     129                 :            : //---------------------------------------------------------------------------
     130                 :            : //      catch(const exception & err)
     131                 :            : //      {
     132                 :            : //         throw err;            // <- should be just "throw;"
     133                 :            : //      }
     134                 :            : //---------------------------------------------------------------------------
     135                 :       1771 : void CheckExceptionSafety::checkRethrowCopy()
     136                 :            : {
     137 [ +  - ][ +  - ]:       1771 :     if (!_settings->isEnabled("style"))
         [ +  - ][ +  + ]
     138                 :       1771 :         return;
     139                 :            : 
     140                 :       1035 :     const SymbolDatabase* const symbolDatabase = _tokenizer->getSymbolDatabase();
     141                 :            : 
     142         [ +  + ]:       4815 :     for (std::list<Scope>::const_iterator i = symbolDatabase->scopeList.begin(); i != symbolDatabase->scopeList.end(); ++i) {
     143         [ +  + ]:       3780 :         if (i->type != Scope::eCatch)
     144                 :       3060 :             continue;
     145                 :            : 
     146                 :        720 :         const unsigned int varid = i->classStart->tokAt(-2)->varId();
     147         [ +  + ]:        720 :         if (varid) {
     148 [ +  - ][ +  + ]:       4005 :             for (const Token* tok = i->classStart->next(); tok && tok != i->classEnd; tok = tok->next()) {
                 [ +  + ]
     149 [ +  + ][ +  - ]:       3330 :                 if (Token::simpleMatch(tok, "catch (") && tok->next()->link() && tok->next()->link()->next()) // Don't check inner catch - it is handled in another iteration of outer loop.
         [ +  - ][ +  + ]
     150                 :         90 :                     tok = tok->next()->link()->next()->link();
     151         [ +  + ]:       3240 :                 else if (Token::Match(tok, "throw %varid% ;", varid))
     152                 :        180 :                     rethrowCopyError(tok, tok->strAt(1));
     153                 :            :             }
     154                 :            :         }
     155                 :            :     }
     156                 :            : }
     157                 :            : 
     158                 :            : //---------------------------------------------------------------------------
     159                 :            : //    try {} catch (std::exception err) {} <- Should be "std::exception& err"
     160                 :            : //---------------------------------------------------------------------------
     161                 :       1771 : void CheckExceptionSafety::checkCatchExceptionByValue()
     162                 :            : {
     163 [ +  - ][ +  - ]:       1771 :     if (!_settings->isEnabled("style"))
         [ +  - ][ +  + ]
     164                 :       1771 :         return;
     165                 :            : 
     166                 :       1035 :     const SymbolDatabase* const symbolDatabase = _tokenizer->getSymbolDatabase();
     167                 :            : 
     168         [ +  + ]:       4815 :     for (std::list<Scope>::const_iterator i = symbolDatabase->scopeList.begin(); i != symbolDatabase->scopeList.end(); ++i) {
     169         [ +  + ]:       3780 :         if (i->type != Scope::eCatch)
     170                 :       3060 :             continue;
     171                 :            : 
     172                 :            :         // Find a pass-by-value declaration in the catch(), excluding basic types
     173                 :            :         // e.g. catch (std::exception err)
     174                 :        720 :         const Variable *var = i->classStart->tokAt(-2)->variable();
     175 [ +  + ][ +  + ]:        720 :         if (var && var->isClass() && !var->isPointer() && !var->isReference())
         [ +  - ][ +  - ]
                 [ +  + ]
     176                 :         90 :             catchExceptionByValueError(i->classDef);
     177                 :            :     }
     178 [ +  - ][ +  - ]:        135 : }

Generated by: LCOV version 1.9