📄 checkbufferoverrun.cpp
字号:
/* * Cppcheck - A tool for static C/C++ code analysis * Copyright (C) 2007-2009 Daniel Marjamäki, Reijo Tomperi, Nicolas Le Cam, * Leandro Penz, Kimmo Varis, Vesa Pikki * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/ *///---------------------------------------------------------------------------// Buffer overrun..//---------------------------------------------------------------------------#include "checkbufferoverrun.h"#include "tokenize.h"#include "errorlogger.h"#include <algorithm>#include <sstream>#include <list>#include <cstring>#include <cstdlib> // <- strtoul//---------------------------------------------------------------------------// _callStack used when parsing into subfunctions.CheckBufferOverrunClass::CheckBufferOverrunClass(const Tokenizer *tokenizer, const Settings &settings, ErrorLogger *errorLogger) : _settings(settings){ _tokenizer = tokenizer; _errorLogger = errorLogger;}CheckBufferOverrunClass::~CheckBufferOverrunClass(){}void CheckBufferOverrunClass::arrayIndexOutOfBounds(const Token *tok){ _callStack.push_back(tok); _errorLogger->arrayIndexOutOfBounds(_tokenizer, _callStack); _callStack.pop_back();}//---------------------------------------------------------------------------//---------------------------------------------------------------------------// Check array usage..//---------------------------------------------------------------------------void CheckBufferOverrunClass::CheckBufferOverrun_CheckScope(const Token *tok, const char *varname[], const int size, const int total_size, unsigned int varid){ unsigned int varc = 0; std::string varnames; while (varname[varc]) { if (varc > 0) varnames += " . "; varnames += varname[varc]; ++varc; } if (varc == 0) varc = 1; varc = 2 * (varc - 1); // Array index.. if (varid > 0) { if (Token::Match(tok, "%varid% [ %num% ]", varid)) { const char *num = tok->strAt(2); if (std::strtol(num, NULL, 10) >= size) { arrayIndexOutOfBounds(tok->next()); } } } else if (Token::Match(tok, std::string(varnames + " [ %num% ]").c_str())) { const char *num = tok->strAt(2 + varc); if (std::strtol(num, NULL, 10) >= size) { arrayIndexOutOfBounds(tok->next()); } } int indentlevel = 0; for (; tok; tok = tok->next()) { if (tok->str() == "{") { ++indentlevel; } else if (tok->str() == "}") { --indentlevel; if (indentlevel < 0) return; } // Array index.. if (varid > 0) { if (!tok->isName() && !Token::Match(tok, "[.&]") && Token::Match(tok->next(), "%varid% [ %num% ]", varid)) { const char *num = tok->strAt(3); if (std::strtol(num, NULL, 10) >= size) { arrayIndexOutOfBounds(tok->next()); } } } else if (!tok->isName() && !Token::Match(tok, "[.&]") && Token::Match(tok->next(), std::string(varnames + " [ %num% ]").c_str())) { const char *num = tok->next()->strAt(2 + varc); if (std::strtol(num, NULL, 10) >= size) { arrayIndexOutOfBounds(tok->next()); } tok = tok->tokAt(4); continue; } // memset, memcmp, memcpy, strncpy, fgets.. if (varid > 0) { if (Token::Match(tok, "memset|memcpy|memmove|memcmp|strncpy|fgets")) { if (Token::Match(tok->next(), "( %varid% , %num% , %num% )", varid) || Token::Match(tok->next(), "( %var% , %varid% , %num% )", varid)) { const char *num = tok->strAt(6); if (std::atoi(num) > total_size) { _errorLogger->bufferOverrun(_tokenizer, tok); } } } } else if (Token::Match(tok, "memset|memcpy|memmove|memcmp|strncpy|fgets")) { if (Token::Match(tok->next(), std::string("( " + varnames + " , %num% , %num% )").c_str()) || Token::Match(tok->next(), std::string("( %var% , " + varnames + " , %num% )").c_str())) { const char *num = tok->strAt(varc + 6); if (std::atoi(num) > total_size) { _errorLogger->bufferOverrun(_tokenizer, tok); } } continue; } // Loop.. if (Token::simpleMatch(tok, "for (")) { const Token *tok2 = tok->tokAt(2); // for - setup.. if (Token::Match(tok2, "%var% = 0 ;")) tok2 = tok2->tokAt(4); else if (Token::Match(tok2, "%type% %var% = 0 ;")) tok2 = tok2->tokAt(5); else if (Token::Match(tok2, "%type% %type% %var% = 0 ;")) tok2 = tok2->tokAt(6); else continue; // for - condition.. if (!Token::Match(tok2, "%var% < %num% ;") && !Token::Match(tok2, "%var% <= %num% ;")) continue; // Get index variable and stopsize. const char *strindex = tok2->aaaa(); int value = ((tok2->next()->aaaa1() == '=') ? 1 : 0) + std::atoi(tok2->strAt(2)); if (value <= size) continue; // Goto the end of the for loop.. while (tok2 && tok2->str() != ")") tok2 = tok2->next(); if (!tok2 || !tok2->tokAt(5)) break; std::ostringstream pattern; pattern << varnames << " [ " << strindex << " ]"; int indentlevel2 = 0; while ((tok2 = tok2->next())) { if (tok2->str() == ";" && indentlevel2 == 0) break; if (tok2->str() == "{") ++indentlevel2; if (tok2->str() == "}") { --indentlevel2; if (indentlevel2 <= 0) break; } if (Token::Match(tok2, pattern.str().c_str())) { _errorLogger->bufferOverrun(_tokenizer, tok2); break; } } continue; } // Writing data into array.. if (Token::Match(tok, ("strcpy|strcat ( " + varnames + " , %str% )").c_str())) { int len = 0; const char *str = tok->strAt(varc + 4); while (*str) { if (*str == '\\') ++str; ++str; ++len; } if (len > 2 && len >= (int)size + 2) { _errorLogger->bufferOverrun(_tokenizer, tok); } continue; } // Dangerous usage of strncat.. if (varid > 0 && Token::Match(tok, "strncat ( %varid% , %any% , %num% )", varid)) { int n = atoi(tok->strAt(6)); if (n == size) _errorLogger->strncatUsage(_tokenizer, tok); } // Dangerous usage of strncpy + strncat.. if (varid > 0 && Token::Match(tok, "strncpy|strncat ( %varid% , %any% , %num% ) ; strncat ( %varid% , %any% , %num% )", varid)) { int n = atoi(tok->strAt(6)) + atoi(tok->strAt(15)); if (n > size) _errorLogger->strncatUsage(_tokenizer, tok->tokAt(9)); } // sprintf.. if (varid > 0 && Token::Match(tok, "sprintf ( %varid% , %str% ,", varid)) { int len = 0; for (const Token *tok2 = tok->tokAt(6); tok2 && tok2->str() != ")"; tok2 = tok2->next()) { if (tok2->aaaa0() == '\"') { len -= 2; const char *str = tok->strAt(0); while (*str) { if (*str == '\\') ++str; ++str; ++len; } } } if (len > (int)size) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -