diff --git a/lib/exprengine.cpp b/lib/exprengine.cpp index 22f5733bd..e98955008 100644 --- a/lib/exprengine.cpp +++ b/lib/exprengine.cpp @@ -912,8 +912,20 @@ static ExprEngine::ValuePtr executeDot(const Token *tok, Data &data) if (!tok->astOperand1() || !tok->astOperand1()->varId()) return ExprEngine::ValuePtr(); std::shared_ptr structValue = std::dynamic_pointer_cast(data.getValue(tok->astOperand1()->varId(), nullptr, nullptr)); - if (!structValue) - return ExprEngine::ValuePtr(); + if (!structValue) { + if (tok->originalName() == "->") { + std::shared_ptr pointerValue = std::dynamic_pointer_cast(data.getValue(tok->astOperand1()->varId(), nullptr, nullptr)); + if (pointerValue) { + call(data.callbacks, tok->astOperand1(), pointerValue); + structValue = std::dynamic_pointer_cast(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()); } @@ -1045,8 +1057,19 @@ static void execute(const Token *start, const Token *end, Data &data) data.trackProgramState(tok); if (tok->variable() && tok->variable()->nameToken() == tok) { if (Token::Match(tok, "%varid% ; %varid% =", tok->varId())) { - tok = tok->tokAt(2); - continue; + // if variable is not used in assignment rhs then we do not need to create a "confusing" variable value.. + 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()) { data.assignValue(tok, tok->varId(), std::make_shared(data.getNewSymbolName(), tok->variable())); @@ -1127,10 +1150,16 @@ static ExprEngine::ValuePtr createVariableValue(const Variable &var, Data &data) const ValueType *valueType = var.valueType(); if (!valueType || valueType->type == ValueType::Type::UNKNOWN_TYPE) 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(); return ExprEngine::ValuePtr(); + } if (valueType->pointer > 0) { + if (var.isLocal()) + return std::make_shared(); ValueType vt(*valueType); vt.pointer = 0; auto range = getValueRangeFromValueType(data.getNewSymbolName(), &vt, *data.settings); @@ -1200,6 +1229,7 @@ void ExprEngine::runChecks(ErrorLogger *errorLogger, const Tokenizer *tokenizer, bool deref = false; deref |= tok->astParent()->isUnaryOp("*"); deref |= Token::simpleMatch(tok->astParent(), "["); + deref |= Token::simpleMatch(tok->astParent(), ".") && tok == tok->astParent()->astOperand1(); if (!deref) return; diff --git a/test/testexprengine.cpp b/test/testexprengine.cpp index 69de253ae..86fb0bbc7 100644 --- a/test/testexprengine.cpp +++ b/test/testexprengine.cpp @@ -66,6 +66,9 @@ private: TEST_CASE(localArrayInit2); TEST_CASE(localArrayUninit); + TEST_CASE(pointer1); + TEST_CASE(pointer2); + TEST_CASE(pointerAlias1); TEST_CASE(pointerAlias2); TEST_CASE(pointerAlias3); @@ -214,6 +217,14 @@ private: 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() { ASSERT_EQUALS("3", getRange("int f() { int x; int *p = &x; x = 3; return *p; }", "return*p")); } diff --git a/test/verify/juliet.py b/test/verify/juliet.py index a3b73e02c..53a421529 100644 --- a/test/verify/juliet.py +++ b/test/verify/juliet.py @@ -8,7 +8,10 @@ import sys import subprocess 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): ret = [] @@ -61,5 +64,5 @@ final_report += check('C/testcases/CWE476_*/*.c', 'verificationNullPointerDerefe print(final_report) assert final_report == ('CWE369 ok:456, fail:0\n' - 'CWE476 ok:186, fail:84\n') + 'CWE476 ok:234, fail:36\n')