ExprEngine: Fix NULL pointer dereference tests
This commit is contained in:
parent
bf8f96255b
commit
60e1cf8b8d
|
@ -912,8 +912,20 @@ static ExprEngine::ValuePtr executeDot(const Token *tok, Data &data)
|
||||||
if (!tok->astOperand1() || !tok->astOperand1()->varId())
|
if (!tok->astOperand1() || !tok->astOperand1()->varId())
|
||||||
return ExprEngine::ValuePtr();
|
return ExprEngine::ValuePtr();
|
||||||
std::shared_ptr<ExprEngine::StructValue> structValue = std::dynamic_pointer_cast<ExprEngine::StructValue>(data.getValue(tok->astOperand1()->varId(), nullptr, nullptr));
|
std::shared_ptr<ExprEngine::StructValue> structValue = std::dynamic_pointer_cast<ExprEngine::StructValue>(data.getValue(tok->astOperand1()->varId(), nullptr, nullptr));
|
||||||
if (!structValue)
|
if (!structValue) {
|
||||||
return ExprEngine::ValuePtr();
|
if (tok->originalName() == "->") {
|
||||||
|
std::shared_ptr<ExprEngine::PointerValue> pointerValue = std::dynamic_pointer_cast<ExprEngine::PointerValue>(data.getValue(tok->astOperand1()->varId(), nullptr, nullptr));
|
||||||
|
if (pointerValue) {
|
||||||
|
call(data.callbacks, tok->astOperand1(), pointerValue);
|
||||||
|
structValue = std::dynamic_pointer_cast<ExprEngine::StructValue>(pointerValue->data);
|
||||||
|
} else {
|
||||||
|
call(data.callbacks, tok->astOperand1(), data.getValue(tok->astOperand1()->varId(), nullptr, nullptr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!structValue)
|
||||||
|
return ExprEngine::ValuePtr();
|
||||||
|
}
|
||||||
|
call(data.callbacks, tok->astOperand1(), structValue);
|
||||||
return structValue->getValueOfMember(tok->astOperand2()->str());
|
return structValue->getValueOfMember(tok->astOperand2()->str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1045,8 +1057,19 @@ static void execute(const Token *start, const Token *end, Data &data)
|
||||||
data.trackProgramState(tok);
|
data.trackProgramState(tok);
|
||||||
if (tok->variable() && tok->variable()->nameToken() == tok) {
|
if (tok->variable() && tok->variable()->nameToken() == tok) {
|
||||||
if (Token::Match(tok, "%varid% ; %varid% =", tok->varId())) {
|
if (Token::Match(tok, "%varid% ; %varid% =", tok->varId())) {
|
||||||
tok = tok->tokAt(2);
|
// if variable is not used in assignment rhs then we do not need to create a "confusing" variable value..
|
||||||
continue;
|
bool foundInRhs = false;
|
||||||
|
visitAstNodes(tok->tokAt(3)->astOperand2(), [&](const Token *rhs) {
|
||||||
|
if (rhs->varId()==tok->varId()) {
|
||||||
|
foundInRhs = true;
|
||||||
|
return ChildrenToVisit::done;
|
||||||
|
}
|
||||||
|
return ChildrenToVisit::op1_and_op2;
|
||||||
|
});
|
||||||
|
if (!foundInRhs) {
|
||||||
|
tok = tok->tokAt(2);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (tok->variable()->isArray()) {
|
if (tok->variable()->isArray()) {
|
||||||
data.assignValue(tok, tok->varId(), std::make_shared<ExprEngine::ArrayValue>(data.getNewSymbolName(), tok->variable()));
|
data.assignValue(tok, tok->varId(), std::make_shared<ExprEngine::ArrayValue>(data.getNewSymbolName(), tok->variable()));
|
||||||
|
@ -1127,10 +1150,16 @@ static ExprEngine::ValuePtr createVariableValue(const Variable &var, Data &data)
|
||||||
const ValueType *valueType = var.valueType();
|
const ValueType *valueType = var.valueType();
|
||||||
if (!valueType || valueType->type == ValueType::Type::UNKNOWN_TYPE)
|
if (!valueType || valueType->type == ValueType::Type::UNKNOWN_TYPE)
|
||||||
valueType = var.nameToken()->valueType();
|
valueType = var.nameToken()->valueType();
|
||||||
if (!valueType || valueType->type == ValueType::Type::UNKNOWN_TYPE)
|
if (!valueType || valueType->type == ValueType::Type::UNKNOWN_TYPE) {
|
||||||
|
// variable with unknown type
|
||||||
|
if (var.isLocal() && var.isPointer() && !var.isArray())
|
||||||
|
return std::make_shared<ExprEngine::UninitValue>();
|
||||||
return ExprEngine::ValuePtr();
|
return ExprEngine::ValuePtr();
|
||||||
|
}
|
||||||
|
|
||||||
if (valueType->pointer > 0) {
|
if (valueType->pointer > 0) {
|
||||||
|
if (var.isLocal())
|
||||||
|
return std::make_shared<ExprEngine::UninitValue>();
|
||||||
ValueType vt(*valueType);
|
ValueType vt(*valueType);
|
||||||
vt.pointer = 0;
|
vt.pointer = 0;
|
||||||
auto range = getValueRangeFromValueType(data.getNewSymbolName(), &vt, *data.settings);
|
auto range = getValueRangeFromValueType(data.getNewSymbolName(), &vt, *data.settings);
|
||||||
|
@ -1200,6 +1229,7 @@ void ExprEngine::runChecks(ErrorLogger *errorLogger, const Tokenizer *tokenizer,
|
||||||
bool deref = false;
|
bool deref = false;
|
||||||
deref |= tok->astParent()->isUnaryOp("*");
|
deref |= tok->astParent()->isUnaryOp("*");
|
||||||
deref |= Token::simpleMatch(tok->astParent(), "[");
|
deref |= Token::simpleMatch(tok->astParent(), "[");
|
||||||
|
deref |= Token::simpleMatch(tok->astParent(), ".") && tok == tok->astParent()->astOperand1();
|
||||||
if (!deref)
|
if (!deref)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
|
@ -66,6 +66,9 @@ private:
|
||||||
TEST_CASE(localArrayInit2);
|
TEST_CASE(localArrayInit2);
|
||||||
TEST_CASE(localArrayUninit);
|
TEST_CASE(localArrayUninit);
|
||||||
|
|
||||||
|
TEST_CASE(pointer1);
|
||||||
|
TEST_CASE(pointer2);
|
||||||
|
|
||||||
TEST_CASE(pointerAlias1);
|
TEST_CASE(pointerAlias1);
|
||||||
TEST_CASE(pointerAlias2);
|
TEST_CASE(pointerAlias2);
|
||||||
TEST_CASE(pointerAlias3);
|
TEST_CASE(pointerAlias3);
|
||||||
|
@ -214,6 +217,14 @@ private:
|
||||||
ASSERT_EQUALS("?", getRange("int f() { int arr[10]; return arr[4]; }", "arr[4]"));
|
ASSERT_EQUALS("?", getRange("int f() { int arr[10]; return arr[4]; }", "arr[4]"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void pointer1() {
|
||||||
|
ASSERT_EQUALS("?", getRange("int f() { int *x; x = x; }", "x=x"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void pointer2() {
|
||||||
|
ASSERT_EQUALS("?", getRange("int f() { sometype *x; x = x; }", "x=x"));
|
||||||
|
}
|
||||||
|
|
||||||
void pointerAlias1() {
|
void pointerAlias1() {
|
||||||
ASSERT_EQUALS("3", getRange("int f() { int x; int *p = &x; x = 3; return *p; }", "return*p"));
|
ASSERT_EQUALS("3", getRange("int f() { int x; int *p = &x; x = 3; return *p; }", "return*p"));
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,10 @@ import sys
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
JULIET_PATH = os.path.expanduser('~/juliet')
|
JULIET_PATH = os.path.expanduser('~/juliet')
|
||||||
CPPCHECK_PATH = '../../cppcheck'
|
if sys.argv[0] in ('test/verify/juliet.py', './test/verify/juliet.py'):
|
||||||
|
CPPCHECK_PATH = './cppcheck'
|
||||||
|
else:
|
||||||
|
CPPCHECK_PATH = '../../cppcheck'
|
||||||
|
|
||||||
def get_files(juliet_path:str, test_cases:str):
|
def get_files(juliet_path:str, test_cases:str):
|
||||||
ret = []
|
ret = []
|
||||||
|
@ -61,5 +64,5 @@ final_report += check('C/testcases/CWE476_*/*.c', 'verificationNullPointerDerefe
|
||||||
print(final_report)
|
print(final_report)
|
||||||
|
|
||||||
assert final_report == ('CWE369 ok:456, fail:0\n'
|
assert final_report == ('CWE369 ok:456, fail:0\n'
|
||||||
'CWE476 ok:186, fail:84\n')
|
'CWE476 ok:234, fail:36\n')
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue