CheckBufferOverrun: Add CTU analysis
This commit is contained in:
parent
8efa106d2a
commit
15fc9a622d
|
@ -636,3 +636,106 @@ void CheckBufferOverrun::bufferNotZeroTerminatedError(const Token *tok, const st
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// CTU..
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
std::string CheckBufferOverrun::MyFileInfo::toString() const OVERRIDE
|
||||||
|
{
|
||||||
|
return CTU::toString(unsafeUsage);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CheckBufferOverrun::isCtuUnsafeBufferUsage(const Check *check, const Token *argtok, MathLib::bigint *offset)
|
||||||
|
{
|
||||||
|
const CheckBufferOverrun *c = dynamic_cast<const CheckBufferOverrun *>(check);
|
||||||
|
if (!c)
|
||||||
|
return false;
|
||||||
|
if (!argtok->valueType())
|
||||||
|
return false;
|
||||||
|
if (!Token::Match(argtok, "%name% [") || argtok->astParent() != argtok->next() || Token::simpleMatch(argtok->linkAt(1), "] ["))
|
||||||
|
return false;
|
||||||
|
if (!argtok->next()->astOperand2())
|
||||||
|
return false;
|
||||||
|
if (!argtok->next()->astOperand2()->hasKnownIntValue())
|
||||||
|
return false;
|
||||||
|
if (!offset)
|
||||||
|
return false;
|
||||||
|
*offset = argtok->next()->astOperand2()->getKnownIntValue() * argtok->valueType()->typeSize(*c->mSettings);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Parse current TU and extract file info */
|
||||||
|
Check::FileInfo *CheckBufferOverrun::getFileInfo(const Tokenizer *tokenizer, const Settings *settings) const OVERRIDE
|
||||||
|
{
|
||||||
|
const std::list<CTU::FileInfo::UnsafeUsage> &unsafeUsage = CTU::getUnsafeUsage(tokenizer, settings, this, isCtuUnsafeBufferUsage);
|
||||||
|
if (unsafeUsage.empty())
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
MyFileInfo *fileInfo = new MyFileInfo;
|
||||||
|
fileInfo->unsafeUsage = unsafeUsage;
|
||||||
|
return fileInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
Check::FileInfo * CheckBufferOverrun::loadFileInfoFromXml(const tinyxml2::XMLElement *xmlElement) const OVERRIDE
|
||||||
|
{
|
||||||
|
const std::list<CTU::FileInfo::UnsafeUsage> &unsafeUsage = CTU::loadUnsafeUsageListFromXml(xmlElement);
|
||||||
|
if (unsafeUsage.empty())
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
MyFileInfo *fileInfo = new MyFileInfo;
|
||||||
|
fileInfo->unsafeUsage = unsafeUsage;
|
||||||
|
return fileInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Analyse all file infos for all TU */
|
||||||
|
bool CheckBufferOverrun::analyseWholeProgram(const CTU::FileInfo *ctu, const std::list<Check::FileInfo*> &fileInfo, const Settings& settings, ErrorLogger &errorLogger) OVERRIDE {
|
||||||
|
if (!ctu)
|
||||||
|
return false;
|
||||||
|
bool foundErrors = false;
|
||||||
|
(void)settings; // This argument is unused
|
||||||
|
|
||||||
|
const std::map<std::string, std::list<const CTU::FileInfo::CallBase *>> callsMap = ctu->getCallsMap();
|
||||||
|
|
||||||
|
for (Check::FileInfo *fi1 : fileInfo)
|
||||||
|
{
|
||||||
|
const MyFileInfo *fi = dynamic_cast<MyFileInfo*>(fi1);
|
||||||
|
if (!fi)
|
||||||
|
continue;
|
||||||
|
for (const CTU::FileInfo::UnsafeUsage &unsafeUsage : fi->unsafeUsage) {
|
||||||
|
const CTU::FileInfo::FunctionCall *functionCall = nullptr;
|
||||||
|
|
||||||
|
const std::list<ErrorLogger::ErrorMessage::FileLocation> &locationList =
|
||||||
|
ctu->getErrorPath(CTU::FileInfo::InvalidValueType::bufferOverflow,
|
||||||
|
unsafeUsage,
|
||||||
|
callsMap,
|
||||||
|
"Using argument ARG",
|
||||||
|
&functionCall,
|
||||||
|
false);
|
||||||
|
if (locationList.empty())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (unsafeUsage.value > 0) {
|
||||||
|
const ErrorLogger::ErrorMessage errmsg(locationList,
|
||||||
|
emptyString,
|
||||||
|
Severity::error,
|
||||||
|
"Buffer access out of bounds; '" + unsafeUsage.myArgumentName + "' buffer size is " + MathLib::toString(functionCall->callArgValue) + " and it is accessed at offset " + MathLib::toString(unsafeUsage.value) + ".",
|
||||||
|
"ctubufferoverrun",
|
||||||
|
CWE788, false);
|
||||||
|
errorLogger.reportErr(errmsg);
|
||||||
|
} else {
|
||||||
|
const ErrorLogger::ErrorMessage errmsg(locationList,
|
||||||
|
emptyString,
|
||||||
|
Severity::error,
|
||||||
|
"Buffer access out of bounds; buffer '" + unsafeUsage.myArgumentName + "' is accessed at offset " + MathLib::toString(unsafeUsage.value) + ".",
|
||||||
|
"ctubufferunderrun",
|
||||||
|
CWE786, false);
|
||||||
|
errorLogger.reportErr(errmsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
foundErrors = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return foundErrors;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
|
|
||||||
#include "check.h"
|
#include "check.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include "ctu.h"
|
||||||
#include "errorlogger.h"
|
#include "errorlogger.h"
|
||||||
#include "mathlib.h"
|
#include "mathlib.h"
|
||||||
#include "tokenize.h"
|
#include "tokenize.h"
|
||||||
|
@ -76,6 +77,13 @@ public:
|
||||||
c.bufferOverflowError(nullptr, nullptr);
|
c.bufferOverflowError(nullptr, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @brief Parse current TU and extract file info */
|
||||||
|
Check::FileInfo *getFileInfo(const Tokenizer *tokenizer, const Settings *settings) const OVERRIDE;
|
||||||
|
|
||||||
|
/** @brief Analyse all file infos for all TU */
|
||||||
|
bool analyseWholeProgram(const CTU::FileInfo *ctu, const std::list<Check::FileInfo*> &fileInfo, const Settings& settings, ErrorLogger &errorLogger) OVERRIDE;
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void arrayIndex();
|
void arrayIndex();
|
||||||
|
@ -94,6 +102,23 @@ private:
|
||||||
|
|
||||||
ValueFlow::Value getBufferSize(const Token *bufTok) const;
|
ValueFlow::Value getBufferSize(const Token *bufTok) const;
|
||||||
|
|
||||||
|
// CTU
|
||||||
|
|
||||||
|
/** data for multifile checking */
|
||||||
|
class MyFileInfo : public Check::FileInfo {
|
||||||
|
public:
|
||||||
|
/** function arguments that data are unconditionally read */
|
||||||
|
std::list<CTU::FileInfo::UnsafeUsage> unsafeUsage;
|
||||||
|
|
||||||
|
/** Convert MyFileInfo data into xml string */
|
||||||
|
std::string toString() const OVERRIDE;
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool isCtuUnsafeBufferUsage(const Check *check, const Token *argtok, MathLib::bigint *value);
|
||||||
|
|
||||||
|
Check::FileInfo * loadFileInfoFromXml(const tinyxml2::XMLElement *xmlElement) const OVERRIDE;
|
||||||
|
|
||||||
|
|
||||||
static std::string myName() {
|
static std::string myName() {
|
||||||
return "Bounds checking";
|
return "Bounds checking";
|
||||||
}
|
}
|
||||||
|
|
|
@ -594,8 +594,9 @@ std::string CheckNullPointer::MyFileInfo::toString() const
|
||||||
return CTU::toString(unsafeUsage);
|
return CTU::toString(unsafeUsage);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isUnsafeUsage(const Check *check, const Token *vartok)
|
static bool isUnsafeUsage(const Check *check, const Token *vartok, MathLib::bigint *value)
|
||||||
{
|
{
|
||||||
|
(void)value;
|
||||||
const CheckNullPointer *checkNullPointer = dynamic_cast<const CheckNullPointer *>(check);
|
const CheckNullPointer *checkNullPointer = dynamic_cast<const CheckNullPointer *>(check);
|
||||||
bool unknown = false;
|
bool unknown = false;
|
||||||
return checkNullPointer && checkNullPointer->isPointerDeRef(vartok, unknown);
|
return checkNullPointer && checkNullPointer->isPointerDeRef(vartok, unknown);
|
||||||
|
|
|
@ -1342,8 +1342,9 @@ Check::FileInfo *CheckUninitVar::getFileInfo(const Tokenizer *tokenizer, const S
|
||||||
return checker.getFileInfo();
|
return checker.getFileInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isVariableUsage(const Check *check, const Token *vartok)
|
static bool isVariableUsage(const Check *check, const Token *vartok, MathLib::bigint *value)
|
||||||
{
|
{
|
||||||
|
(void)value;
|
||||||
const CheckUninitVar *c = dynamic_cast<const CheckUninitVar *>(check);
|
const CheckUninitVar *c = dynamic_cast<const CheckUninitVar *>(check);
|
||||||
return c && c->isVariableUsage(vartok, true, CheckUninitVar::Alloc::ARRAY);
|
return c && c->isVariableUsage(vartok, true, CheckUninitVar::Alloc::ARRAY);
|
||||||
}
|
}
|
||||||
|
|
49
lib/ctu.cpp
49
lib/ctu.cpp
|
@ -37,6 +37,7 @@ static const char ATTR_INFO[] = "info";
|
||||||
static const char ATTR_MY_ID[] = "my-id";
|
static const char ATTR_MY_ID[] = "my-id";
|
||||||
static const char ATTR_MY_ARGNR[] = "my-argnr";
|
static const char ATTR_MY_ARGNR[] = "my-argnr";
|
||||||
static const char ATTR_MY_ARGNAME[] = "my-argname";
|
static const char ATTR_MY_ARGNAME[] = "my-argname";
|
||||||
|
static const char ATTR_VALUE[] = "value";
|
||||||
|
|
||||||
int CTU::maxCtuDepth = 2;
|
int CTU::maxCtuDepth = 2;
|
||||||
|
|
||||||
|
@ -123,6 +124,7 @@ std::string CTU::FileInfo::UnsafeUsage::toString() const
|
||||||
<< " " << ATTR_MY_ARGNAME << "=\"" << myArgumentName << '\"'
|
<< " " << ATTR_MY_ARGNAME << "=\"" << myArgumentName << '\"'
|
||||||
<< " " << ATTR_LOC_FILENAME << "=\"" << location.fileName << '\"'
|
<< " " << ATTR_LOC_FILENAME << "=\"" << location.fileName << '\"'
|
||||||
<< " " << ATTR_LOC_LINENR << "=\"" << location.linenr << '\"'
|
<< " " << ATTR_LOC_LINENR << "=\"" << location.linenr << '\"'
|
||||||
|
<< " " << ATTR_VALUE << "=\"" << value << "\""
|
||||||
<< "/>\n";
|
<< "/>\n";
|
||||||
return out.str();
|
return out.str();
|
||||||
}
|
}
|
||||||
|
@ -246,6 +248,8 @@ std::list<CTU::FileInfo::UnsafeUsage> CTU::loadUnsafeUsageListFromXml(const tiny
|
||||||
unsafeUsage.myArgumentName = readAttrString(e, ATTR_MY_ARGNAME, &error);
|
unsafeUsage.myArgumentName = readAttrString(e, ATTR_MY_ARGNAME, &error);
|
||||||
unsafeUsage.location.fileName = readAttrString(e, ATTR_LOC_FILENAME, &error);
|
unsafeUsage.location.fileName = readAttrString(e, ATTR_LOC_FILENAME, &error);
|
||||||
unsafeUsage.location.linenr = readAttrInt(e, ATTR_LOC_LINENR, &error);
|
unsafeUsage.location.linenr = readAttrInt(e, ATTR_LOC_LINENR, &error);
|
||||||
|
unsafeUsage.value = readAttrInt(e, ATTR_VALUE, &error);
|
||||||
|
|
||||||
if (!error)
|
if (!error)
|
||||||
ret.push_back(unsafeUsage);
|
ret.push_back(unsafeUsage);
|
||||||
}
|
}
|
||||||
|
@ -306,10 +310,10 @@ CTU::FileInfo *CTU::getFileInfo(const Tokenizer *tokenizer)
|
||||||
if (!argtok)
|
if (!argtok)
|
||||||
continue;
|
continue;
|
||||||
for (const ValueFlow::Value &value : argtok->values()) {
|
for (const ValueFlow::Value &value : argtok->values()) {
|
||||||
if (!value.isIntValue() || value.intvalue != 0 || value.isInconclusive())
|
if ((!value.isIntValue() || value.intvalue != 0 || value.isInconclusive()) && !value.isBufferSizeValue())
|
||||||
continue;
|
continue;
|
||||||
FileInfo::FunctionCall functionCall;
|
FileInfo::FunctionCall functionCall;
|
||||||
functionCall.callValueType = ValueFlow::Value::INT;
|
functionCall.callValueType = value.valueType;
|
||||||
functionCall.callId = getFunctionId(tokenizer, tok->astOperand1()->function());
|
functionCall.callId = getFunctionId(tokenizer, tok->astOperand1()->function());
|
||||||
functionCall.callFunctionName = tok->astOperand1()->expressionString();
|
functionCall.callFunctionName = tok->astOperand1()->expressionString();
|
||||||
functionCall.location.fileName = tokenizer->list.file(tok);
|
functionCall.location.fileName = tokenizer->list.file(tok);
|
||||||
|
@ -369,18 +373,19 @@ CTU::FileInfo *CTU::getFileInfo(const Tokenizer *tokenizer)
|
||||||
return fileInfo;
|
return fileInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isUnsafeFunction(const Tokenizer *tokenizer, const Settings *settings, const Scope *scope, int argnr, const Token **tok, const Check *check, bool (*isUnsafeUsage)(const Check *check, const Token *argtok))
|
static std::list<std::pair<const Token *, MathLib::bigint>> getUnsafeFunction(const Tokenizer *tokenizer, const Settings *settings, const Scope *scope, int argnr, const Check *check, bool (*isUnsafeUsage)(const Check *check, const Token *argtok, MathLib::bigint *value))
|
||||||
{
|
{
|
||||||
|
std::list<std::pair<const Token *, MathLib::bigint>> ret;
|
||||||
const Variable * const argvar = scope->function->getArgumentVar(argnr);
|
const Variable * const argvar = scope->function->getArgumentVar(argnr);
|
||||||
if (!argvar->isPointer())
|
if (!argvar->isPointer())
|
||||||
return false;
|
return ret;
|
||||||
for (const Token *tok2 = scope->bodyStart; tok2 != scope->bodyEnd; tok2 = tok2->next()) {
|
for (const Token *tok2 = scope->bodyStart; tok2 != scope->bodyEnd; tok2 = tok2->next()) {
|
||||||
if (Token::Match(tok2, ")|else {")) {
|
if (Token::Match(tok2, ")|else {")) {
|
||||||
tok2 = tok2->linkAt(1);
|
tok2 = tok2->linkAt(1);
|
||||||
if (Token::findmatch(tok2->link(), "return|throw", tok2))
|
if (Token::findmatch(tok2->link(), "return|throw", tok2))
|
||||||
return false;
|
return ret;
|
||||||
if (isVariableChanged(tok2->link(), tok2, argvar->declarationId(), false, settings, tokenizer->isCPP()))
|
if (isVariableChanged(tok2->link(), tok2, argvar->declarationId(), false, settings, tokenizer->isCPP()))
|
||||||
return false;
|
return ret;
|
||||||
}
|
}
|
||||||
if (Token::Match(tok2, "%oror%|&&|?")) {
|
if (Token::Match(tok2, "%oror%|&&|?")) {
|
||||||
tok2 = tok2->findExpressionStartEndTokens().second;
|
tok2 = tok2->findExpressionStartEndTokens().second;
|
||||||
|
@ -388,15 +393,16 @@ static bool isUnsafeFunction(const Tokenizer *tokenizer, const Settings *setting
|
||||||
}
|
}
|
||||||
if (tok2->variable() != argvar)
|
if (tok2->variable() != argvar)
|
||||||
continue;
|
continue;
|
||||||
if (!isUnsafeUsage(check, tok2))
|
MathLib::bigint value = 0;
|
||||||
return false;
|
if (!isUnsafeUsage(check, tok2, &value))
|
||||||
*tok = tok2;
|
return ret; // TODO: Is this a read? then continue..
|
||||||
return true;
|
ret.emplace_back(tok2, value);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
return false;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::list<CTU::FileInfo::UnsafeUsage> CTU::getUnsafeUsage(const Tokenizer *tokenizer, const Settings *settings, const Check *check, bool (*isUnsafeUsage)(const Check *check, const Token *argtok))
|
std::list<CTU::FileInfo::UnsafeUsage> CTU::getUnsafeUsage(const Tokenizer *tokenizer, const Settings *settings, const Check *check, bool (*isUnsafeUsage)(const Check *check, const Token *argtok, MathLib::bigint *_value))
|
||||||
{
|
{
|
||||||
std::list<CTU::FileInfo::UnsafeUsage> unsafeUsage;
|
std::list<CTU::FileInfo::UnsafeUsage> unsafeUsage;
|
||||||
|
|
||||||
|
@ -410,9 +416,11 @@ std::list<CTU::FileInfo::UnsafeUsage> CTU::getUnsafeUsage(const Tokenizer *token
|
||||||
|
|
||||||
// "Unsafe" functions unconditionally reads data before it is written..
|
// "Unsafe" functions unconditionally reads data before it is written..
|
||||||
for (int argnr = 0; argnr < function->argCount(); ++argnr) {
|
for (int argnr = 0; argnr < function->argCount(); ++argnr) {
|
||||||
const Token *tok;
|
for (const std::pair<const Token *, MathLib::bigint> &v : getUnsafeFunction(tokenizer, settings, &scope, argnr, check, isUnsafeUsage)) {
|
||||||
if (isUnsafeFunction(tokenizer, settings, &scope, argnr, &tok, check, isUnsafeUsage))
|
const Token *tok = v.first;
|
||||||
unsafeUsage.push_back(CTU::FileInfo::UnsafeUsage(CTU::getFunctionId(tokenizer, function), argnr+1, tok->str(), CTU::FileInfo::Location(tokenizer,tok)));
|
MathLib::bigint value = v.second;
|
||||||
|
unsafeUsage.emplace_back(CTU::getFunctionId(tokenizer, function), argnr+1, tok->str(), CTU::FileInfo::Location(tokenizer,tok), value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -421,6 +429,7 @@ std::list<CTU::FileInfo::UnsafeUsage> CTU::getUnsafeUsage(const Tokenizer *token
|
||||||
|
|
||||||
static bool findPath(const std::string &callId,
|
static bool findPath(const std::string &callId,
|
||||||
unsigned int callArgNr,
|
unsigned int callArgNr,
|
||||||
|
MathLib::bigint unsafeValue,
|
||||||
CTU::FileInfo::InvalidValueType invalidValue,
|
CTU::FileInfo::InvalidValueType invalidValue,
|
||||||
const std::map<std::string, std::list<const CTU::FileInfo::CallBase *>> &callsMap,
|
const std::map<std::string, std::list<const CTU::FileInfo::CallBase *>> &callsMap,
|
||||||
const CTU::FileInfo::CallBase *path[10],
|
const CTU::FileInfo::CallBase *path[10],
|
||||||
|
@ -451,6 +460,12 @@ static bool findPath(const std::string &callId,
|
||||||
if (functionCall->callValueType != ValueFlow::Value::UNINIT)
|
if (functionCall->callValueType != ValueFlow::Value::UNINIT)
|
||||||
continue;
|
continue;
|
||||||
break;
|
break;
|
||||||
|
case CTU::FileInfo::InvalidValueType::bufferOverflow:
|
||||||
|
if (functionCall->callValueType != ValueFlow::Value::BUFFER_SIZE)
|
||||||
|
continue;
|
||||||
|
if (unsafeValue < 0 || unsafeValue >= functionCall->callArgValue)
|
||||||
|
break;
|
||||||
|
continue;
|
||||||
};
|
};
|
||||||
path[index] = functionCall;
|
path[index] = functionCall;
|
||||||
return true;
|
return true;
|
||||||
|
@ -460,7 +475,7 @@ static bool findPath(const std::string &callId,
|
||||||
if (!nestedCall)
|
if (!nestedCall)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (findPath(nestedCall->myId, nestedCall->myArgNr, invalidValue, callsMap, path, index + 1, warning)) {
|
if (findPath(nestedCall->myId, nestedCall->myArgNr, unsafeValue, invalidValue, callsMap, path, index + 1, warning)) {
|
||||||
path[index] = nestedCall;
|
path[index] = nestedCall;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -480,7 +495,7 @@ std::list<ErrorLogger::ErrorMessage::FileLocation> CTU::FileInfo::getErrorPath(I
|
||||||
|
|
||||||
const CTU::FileInfo::CallBase *path[10] = {0};
|
const CTU::FileInfo::CallBase *path[10] = {0};
|
||||||
|
|
||||||
if (!findPath(unsafeUsage.myId, unsafeUsage.myArgNr, invalidValue, callsMap, path, 0, warning))
|
if (!findPath(unsafeUsage.myId, unsafeUsage.myArgNr, unsafeUsage.value, invalidValue, callsMap, path, 0, warning))
|
||||||
return locationList;
|
return locationList;
|
||||||
|
|
||||||
const std::string value1 = (invalidValue == InvalidValueType::null) ? "null" : "uninitialized";
|
const std::string value1 = (invalidValue == InvalidValueType::null) ? "null" : "uninitialized";
|
||||||
|
|
|
@ -33,7 +33,7 @@
|
||||||
namespace CTU {
|
namespace CTU {
|
||||||
class CPPCHECKLIB FileInfo : public Check::FileInfo {
|
class CPPCHECKLIB FileInfo : public Check::FileInfo {
|
||||||
public:
|
public:
|
||||||
enum InvalidValueType { null, uninit };
|
enum InvalidValueType { null, uninit, bufferOverflow };
|
||||||
|
|
||||||
std::string toString() const OVERRIDE;
|
std::string toString() const OVERRIDE;
|
||||||
|
|
||||||
|
@ -47,11 +47,12 @@ namespace CTU {
|
||||||
|
|
||||||
struct UnsafeUsage {
|
struct UnsafeUsage {
|
||||||
UnsafeUsage() = default;
|
UnsafeUsage() = default;
|
||||||
UnsafeUsage(const std::string &myId, unsigned int myArgNr, const std::string &myArgumentName, const Location &location) : myId(myId), myArgNr(myArgNr), myArgumentName(myArgumentName), location(location) {}
|
UnsafeUsage(const std::string &myId, unsigned int myArgNr, const std::string &myArgumentName, const Location &location, MathLib::bigint value) : myId(myId), myArgNr(myArgNr), myArgumentName(myArgumentName), location(location), value(value) {}
|
||||||
std::string myId;
|
std::string myId;
|
||||||
unsigned int myArgNr;
|
unsigned int myArgNr;
|
||||||
std::string myArgumentName;
|
std::string myArgumentName;
|
||||||
Location location;
|
Location location;
|
||||||
|
MathLib::bigint value;
|
||||||
std::string toString() const;
|
std::string toString() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -126,7 +127,7 @@ namespace CTU {
|
||||||
/** @brief Parse current TU and extract file info */
|
/** @brief Parse current TU and extract file info */
|
||||||
CPPCHECKLIB FileInfo *getFileInfo(const Tokenizer *tokenizer);
|
CPPCHECKLIB FileInfo *getFileInfo(const Tokenizer *tokenizer);
|
||||||
|
|
||||||
CPPCHECKLIB std::list<FileInfo::UnsafeUsage> getUnsafeUsage(const Tokenizer *tokenizer, const Settings *settings, const Check *check, bool (*isUnsafeUsage)(const Check *check, const Token *argtok));
|
CPPCHECKLIB std::list<FileInfo::UnsafeUsage> getUnsafeUsage(const Tokenizer *tokenizer, const Settings *settings, const Check *check, bool (*isUnsafeUsage)(const Check *check, const Token *argtok, MathLib::bigint *value));
|
||||||
|
|
||||||
CPPCHECKLIB std::list<FileInfo::UnsafeUsage> loadUnsafeUsageListFromXml(const tinyxml2::XMLElement *xmlElement);
|
CPPCHECKLIB std::list<FileInfo::UnsafeUsage> loadUnsafeUsageListFromXml(const tinyxml2::XMLElement *xmlElement);
|
||||||
}
|
}
|
||||||
|
|
|
@ -89,7 +89,7 @@ private:
|
||||||
// TODO string TEST_CASE(array_index_4);
|
// TODO string TEST_CASE(array_index_4);
|
||||||
TEST_CASE(array_index_6);
|
TEST_CASE(array_index_6);
|
||||||
TEST_CASE(array_index_7);
|
TEST_CASE(array_index_7);
|
||||||
// TODO CTU TEST_CASE(array_index_9);
|
// TODO ctu TEST_CASE(array_index_9);
|
||||||
TEST_CASE(array_index_11);
|
TEST_CASE(array_index_11);
|
||||||
TEST_CASE(array_index_12);
|
TEST_CASE(array_index_12);
|
||||||
TEST_CASE(array_index_13);
|
TEST_CASE(array_index_13);
|
||||||
|
@ -245,6 +245,8 @@ private:
|
||||||
TEST_CASE(negativeArraySize);
|
TEST_CASE(negativeArraySize);
|
||||||
|
|
||||||
// TODO TEST_CASE(pointerAddition1);
|
// TODO TEST_CASE(pointerAddition1);
|
||||||
|
|
||||||
|
TEST_CASE(ctu_1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -4114,6 +4116,53 @@ private:
|
||||||
"\n");
|
"\n");
|
||||||
ASSERT_EQUALS("error", errout.str());
|
ASSERT_EQUALS("error", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ctu(const char code[]) {
|
||||||
|
// Clear the error buffer..
|
||||||
|
errout.str("");
|
||||||
|
|
||||||
|
// Tokenize..
|
||||||
|
Tokenizer tokenizer(&settings0, this);
|
||||||
|
std::istringstream istr(code);
|
||||||
|
tokenizer.tokenize(istr, "test.cpp");
|
||||||
|
|
||||||
|
CTU::FileInfo *ctu = CTU::getFileInfo(&tokenizer);
|
||||||
|
|
||||||
|
// Check code..
|
||||||
|
std::list<Check::FileInfo*> fileInfo;
|
||||||
|
CheckBufferOverrun check(&tokenizer, &settings0, this);
|
||||||
|
fileInfo.push_back(check.getFileInfo(&tokenizer, &settings0));
|
||||||
|
check.analyseWholeProgram(ctu, fileInfo, settings0, *this);
|
||||||
|
while (!fileInfo.empty()) {
|
||||||
|
delete fileInfo.back();
|
||||||
|
fileInfo.pop_back();
|
||||||
|
}
|
||||||
|
delete ctu;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ctu_1() {
|
||||||
|
ctu("void dostuff(const char *p) {\n"
|
||||||
|
" p[-3] = 0;\n"
|
||||||
|
"}\n"
|
||||||
|
"\n"
|
||||||
|
"int main() {\n"
|
||||||
|
" char *s = malloc(4);\n"
|
||||||
|
" dostuff(s);\n"
|
||||||
|
" return 0;\n"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("[test.cpp:6] -> [test.cpp:7] -> [test.cpp:2]: (error) Buffer access out of bounds; buffer 'p' is accessed at offset -3.\n", errout.str());
|
||||||
|
|
||||||
|
ctu("void dostuff(const char *p) {\n"
|
||||||
|
" p[4] = 0;\n"
|
||||||
|
"}\n"
|
||||||
|
"\n"
|
||||||
|
"int main() {\n"
|
||||||
|
" char *s = malloc(4);\n"
|
||||||
|
" dostuff(s);\n"
|
||||||
|
" return 0;\n"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("[test.cpp:6] -> [test.cpp:7] -> [test.cpp:2]: (error) Buffer access out of bounds; 'p' buffer size is 4 and it is accessed at offset 4.\n", errout.str());
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
REGISTER_TEST(TestBufferOverrun)
|
REGISTER_TEST(TestBufferOverrun)
|
||||||
|
|
Loading…
Reference in New Issue