|
Cppcheck
|
00001 /* 00002 * Cppcheck - A tool for static C/C++ code analysis 00003 * Copyright (C) 2007-2013 Daniel Marjamäki and Cppcheck team. 00004 * 00005 * This program is free software: you can redistribute it and/or modify 00006 * it under the terms of the GNU General Public License as published by 00007 * the Free Software Foundation, either version 3 of the License, or 00008 * (at your option) any later version. 00009 * 00010 * This program is distributed in the hope that it will be useful, 00011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 * GNU General Public License for more details. 00014 * 00015 * You should have received a copy of the GNU General Public License 00016 * along with this program. If not, see <http://www.gnu.org/licenses/>. 00017 */ 00018 00019 00020 //--------------------------------------------------------------------------- 00021 #ifndef CheckBufferOverrunH 00022 #define CheckBufferOverrunH 00023 //--------------------------------------------------------------------------- 00024 00025 #include "config.h" 00026 #include "check.h" 00027 #include "settings.h" 00028 #include "mathlib.h" 00029 #include <list> 00030 #include <vector> 00031 #include <string> 00032 00033 class ErrorLogger; 00034 class Token; 00035 class Tokenizer; 00036 class Variable; 00037 00038 /// @addtogroup Checks 00039 /// @{ 00040 00041 /** 00042 * @brief buffer overruns and array index out of bounds 00043 * 00044 * Buffer overrun and array index out of bounds are pretty much the same. 00045 * But I generally use 'array index' if the code contains []. And the given 00046 * index is out of bounds. 00047 * I generally use 'buffer overrun' if you for example call a strcpy or 00048 * other function and pass a buffer and reads or writes too much data. 00049 */ 00050 class CPPCHECKLIB CheckBufferOverrun : public Check { 00051 public: 00052 00053 /** This constructor is used when registering the CheckClass */ 00054 CheckBufferOverrun() : Check(myName()) 00055 { } 00056 00057 /** This constructor is used when running checks. */ 00058 CheckBufferOverrun(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) 00059 : Check(myName(), tokenizer, settings, errorLogger) 00060 { } 00061 00062 void runSimplifiedChecks(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) { 00063 CheckBufferOverrun checkBufferOverrun(tokenizer, settings, errorLogger); 00064 checkBufferOverrun.bufferOverrun(); 00065 checkBufferOverrun.negativeIndex(); 00066 checkBufferOverrun.arrayIndexThenCheck(); 00067 00068 /** ExecutionPath checking.. */ 00069 checkBufferOverrun.executionPaths(); 00070 checkBufferOverrun.writeOutsideBufferSize(); 00071 } 00072 00073 /** @brief %Check for buffer overruns */ 00074 void bufferOverrun(); 00075 00076 /** @brief Using array index before bounds check */ 00077 void arrayIndexThenCheck(); 00078 00079 /** @brief %Check for buffer overruns by inspecting execution paths */ 00080 void executionPaths(); 00081 00082 /** @brief %Check using POSIX write function and writing outside buffer size */ 00083 void writeOutsideBufferSize(); 00084 00085 /** 00086 * @brief Get minimum length of format string result 00087 * @param input_string format string 00088 * @param parameters given parameters to sprintf 00089 * @return minimum length of resulting string 00090 */ 00091 static MathLib::bigint countSprintfLength(const std::string &input_string, const std::list<const Token*> ¶meters); 00092 00093 /** 00094 * @brief %Check code that matches: "sprintf ( %varid% , %str% [,)]" when varid is not 0, 00095 * and report found errors. 00096 * @param tok The "sprintf" token. 00097 * @param size The size of the buffer where sprintf is writing. 00098 */ 00099 void checkSprintfCall(const Token *tok, const MathLib::bigint size); 00100 00101 /** Check for buffer overruns - locate struct variables and check them with the .._CheckScope function */ 00102 void checkStructVariable(); 00103 00104 /** Check for buffer overruns - locate global variables and local function variables and check them with the checkScope function */ 00105 void checkGlobalAndLocalVariable(); 00106 00107 /** Check for buffer overruns due to allocating strlen(src) bytes instead of (strlen(src)+1) bytes before copying a string */ 00108 void checkBufferAllocatedWithStrlen(); 00109 00110 /** Check for buffer overruns due to copying command-line args to fixed-sized buffers without bounds checking */ 00111 void checkInsecureCmdLineArgs(); 00112 00113 /** Check for negative index */ 00114 void negativeIndex(); 00115 00116 /** Information about N-dimensional array */ 00117 class CPPCHECKLIB ArrayInfo { 00118 private: 00119 /** number of elements of array */ 00120 std::vector<MathLib::bigint> _num; 00121 00122 /** full name of variable as pattern */ 00123 std::string _varname; 00124 00125 /** size of each element in array */ 00126 MathLib::bigint _element_size; 00127 00128 /** variable id */ 00129 unsigned int _varid; 00130 00131 public: 00132 ArrayInfo(); 00133 ArrayInfo(const ArrayInfo &); 00134 ArrayInfo(const Variable *var, const Tokenizer *tokenizer); 00135 ArrayInfo & operator=(const ArrayInfo &ai); 00136 00137 /** 00138 * Create array info with specified data 00139 * The intention is that this is only a temporary solution.. all 00140 * checking should be based on ArrayInfo from the start and then 00141 * this will not be needed as the declare can be used instead. 00142 */ 00143 ArrayInfo(unsigned int id, const std::string &name, MathLib::bigint size1, MathLib::bigint n); 00144 00145 /** Create a copy ArrayInfo where the number of elements have been limited by a value */ 00146 ArrayInfo limit(MathLib::bigint value) const; 00147 00148 /** array sizes */ 00149 const std::vector<MathLib::bigint> &num() const { 00150 return _num; 00151 } 00152 00153 /** array size */ 00154 MathLib::bigint num(std::size_t index) const { 00155 return _num[index]; 00156 } 00157 void num(std::size_t index, MathLib::bigint number) { 00158 _num[index] = number; 00159 } 00160 00161 /** size of each element */ 00162 MathLib::bigint element_size() const { 00163 return _element_size; 00164 } 00165 00166 /** Variable name */ 00167 unsigned int varid() const { 00168 return _varid; 00169 } 00170 void varid(unsigned int id) { 00171 _varid = id; 00172 } 00173 00174 /** Variable name */ 00175 const std::string &varname() const { 00176 return _varname; 00177 } 00178 void varname(const std::string &name) { 00179 _varname = name; 00180 } 00181 }; 00182 00183 /** Check for buffer overruns (based on ArrayInfo) */ 00184 void checkScope(const Token *tok, const ArrayInfo &arrayInfo); 00185 00186 /** Check for buffer overruns */ 00187 void checkScope(const Token *tok, const std::vector<std::string> &varname, const ArrayInfo &arrayInfo); 00188 00189 /** Check scope helper function - parse for body */ 00190 void checkScopeForBody(const Token *tok, const ArrayInfo &arrayInfo, bool &bailout); 00191 00192 /** Helper function used when parsing for-loops */ 00193 void parse_for_body(const Token *tok2, const ArrayInfo &arrayInfo, const std::string &strindex, bool condition_out_of_bounds, unsigned int counter_varid, const std::string &min_counter_value, const std::string &max_counter_value); 00194 00195 /** Check readlink or readlinkat() buffer usage */ 00196 void checkReadlinkBufferUsage(const Token *tok, const Token *scope_begin, const MathLib::bigint total_size, const bool is_readlinkat); 00197 00198 /** 00199 * Helper function for checkFunctionCall - check a function parameter 00200 * \param tok token for the function name 00201 * \param par on what parameter is the array used 00202 * \param arrayInfo the array information 00203 * \param callstack call stack. This is used to prevent recursion and to provide better error messages. Pass a empty list from checkScope etc. 00204 */ 00205 void checkFunctionParameter(const Token &tok, const unsigned int par, const ArrayInfo &arrayInfo, std::list<const Token *> callstack); 00206 00207 /** 00208 * Helper function that checks if the array is used and if so calls the checkFunctionCall 00209 * @param tok token that matches "%var% (" 00210 * @param arrayInfo the array information 00211 * \param callstack call stack. This is used to prevent recursion and to provide better error messages. Pass a empty list from checkScope etc. 00212 */ 00213 void checkFunctionCall(const Token *tok, const ArrayInfo &arrayInfo, std::list<const Token *> callstack); 00214 00215 void arrayIndexOutOfBoundsError(const Token *tok, const ArrayInfo &arrayInfo, const std::vector<MathLib::bigint> &index); 00216 void arrayIndexInForLoop(const Token *tok, const ArrayInfo &arrayInfo); 00217 00218 private: 00219 00220 bool isArrayOfStruct(const Token* tok, int &position); 00221 void arrayIndexOutOfBoundsError(const std::list<const Token *> &callstack, const ArrayInfo &arrayInfo, const std::vector<MathLib::bigint> &index); 00222 void bufferOverrunError(const Token *tok, const std::string &varnames = ""); 00223 void bufferOverrunError(const std::list<const Token *> &callstack, const std::string &varnames = ""); 00224 void strncatUsageError(const Token *tok); 00225 void outOfBoundsError(const Token *tok, const std::string &what, const bool show_size_info, const MathLib::bigint &supplied_size, const MathLib::bigint &actual_size); 00226 void sizeArgumentAsCharError(const Token *tok); 00227 void terminateStrncpyError(const Token *tok, const std::string &varname); 00228 void bufferNotZeroTerminatedError(const Token *tok, const std::string &varname, const std::string &function); 00229 void negativeIndexError(const Token *tok, MathLib::bigint index); 00230 void cmdLineArgsError(const Token *tok); 00231 void pointerOutOfBoundsError(const Token *tok, const std::string &object); // UB when result of calculation is out of bounds 00232 void arrayIndexThenCheckError(const Token *tok, const std::string &indexName); 00233 void possibleBufferOverrunError(const Token *tok, const std::string &src, const std::string &dst, bool cat); 00234 void possibleReadlinkBufferOverrunError(const Token *tok, const std::string &funcname, const std::string &varname); 00235 void argumentSizeError(const Token *tok, const std::string &functionName, const std::string &varname); 00236 void writeOutsideBufferSizeError(const Token *tok, const std::size_t stringLength, const MathLib::bigint writeLength, const std::string& functionName); 00237 00238 public: 00239 void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const { 00240 CheckBufferOverrun c(0, settings, errorLogger); 00241 std::vector<MathLib::bigint> indexes; 00242 indexes.push_back(2); 00243 c.arrayIndexOutOfBoundsError(0, ArrayInfo(0, "array", 1, 2), indexes); 00244 c.bufferOverrunError(0, std::string("buffer")); 00245 c.strncatUsageError(0); 00246 c.outOfBoundsError(0, "index", true, 2, 1); 00247 c.sizeArgumentAsCharError(0); 00248 c.terminateStrncpyError(0, "buffer"); 00249 c.bufferNotZeroTerminatedError(0, "buffer", "strncpy"); 00250 c.negativeIndexError(0, -1); 00251 c.cmdLineArgsError(0); 00252 c.pointerOutOfBoundsError(0, "array"); 00253 c.arrayIndexThenCheckError(0, "index"); 00254 c.possibleBufferOverrunError(0, "source", "destination", false); 00255 c.possibleReadlinkBufferOverrunError(0, "readlink", "buffer"); 00256 c.argumentSizeError(0, "function", "array"); 00257 c.writeOutsideBufferSizeError(0,2,3,"write"); 00258 } 00259 private: 00260 00261 static std::string myName() { 00262 return "Bounds checking"; 00263 } 00264 00265 std::string classInfo() const { 00266 return "out of bounds checking\n"; 00267 } 00268 }; 00269 /// @} 00270 //--------------------------------------------------------------------------- 00271 #endif
1.7.6.1