Fix issue 8650: ValueFlow: Track if pointer is created by '&' operator (#3011)
This commit is contained in:
parent
8897ad3408
commit
e004731f1c
|
@ -889,21 +889,28 @@ void CheckBufferOverrun::objectIndex()
|
|||
if (idx->hasKnownIntValue() && idx->getKnownIntValue() == 0)
|
||||
continue;
|
||||
|
||||
ValueFlow::Value v = getLifetimeObjValue(obj);
|
||||
if (!v.isLocalLifetimeValue())
|
||||
continue;
|
||||
if (v.lifetimeKind != ValueFlow::Value::LifetimeKind::Address)
|
||||
continue;
|
||||
const Variable *var = v.tokvalue->variable();
|
||||
if (var->isReference())
|
||||
continue;
|
||||
if (var->isRValueReference())
|
||||
continue;
|
||||
if (var->isArray())
|
||||
continue;
|
||||
if (var->isPointer())
|
||||
continue;
|
||||
objectIndexError(tok, &v, idx->hasKnownIntValue());
|
||||
std::vector<ValueFlow::Value> values = getLifetimeObjValues(obj, false, true);
|
||||
for(const ValueFlow::Value& v:values) {
|
||||
if (v.lifetimeKind != ValueFlow::Value::LifetimeKind::Address)
|
||||
continue;
|
||||
const Variable *var = v.tokvalue->variable();
|
||||
if (var->isReference())
|
||||
continue;
|
||||
if (var->isRValueReference())
|
||||
continue;
|
||||
if (var->isArray())
|
||||
continue;
|
||||
if (var->isPointer()) {
|
||||
if (!var->valueType())
|
||||
continue;
|
||||
if (!obj->valueType())
|
||||
continue;
|
||||
if (var->valueType()->pointer > obj->valueType()->pointer)
|
||||
continue;
|
||||
}
|
||||
objectIndexError(tok, &v, idx->hasKnownIntValue());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -98,6 +98,7 @@
|
|||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <functional>
|
||||
#include <iterator>
|
||||
|
@ -2703,11 +2704,11 @@ std::string lifetimeMessage(const Token *tok, const ValueFlow::Value *val, Error
|
|||
return msg;
|
||||
}
|
||||
|
||||
ValueFlow::Value getLifetimeObjValue(const Token *tok, bool inconclusive)
|
||||
std::vector<ValueFlow::Value> getLifetimeObjValues(const Token *tok, bool inconclusive, bool subfunction)
|
||||
{
|
||||
ValueFlow::Value result;
|
||||
std::vector<ValueFlow::Value> result;
|
||||
auto pred = [&](const ValueFlow::Value &v) {
|
||||
if (!v.isLocalLifetimeValue())
|
||||
if (!v.isLocalLifetimeValue() && !(subfunction && v.isSubFunctionLifetimeValue()))
|
||||
return false;
|
||||
if (!inconclusive && v.isInconclusive())
|
||||
return false;
|
||||
|
@ -2715,16 +2716,19 @@ ValueFlow::Value getLifetimeObjValue(const Token *tok, bool inconclusive)
|
|||
return false;
|
||||
return true;
|
||||
};
|
||||
auto it = std::find_if(tok->values().begin(), tok->values().end(), pred);
|
||||
if (it == tok->values().end())
|
||||
return result;
|
||||
result = *it;
|
||||
// There should only be one lifetime
|
||||
if (std::find_if(std::next(it), tok->values().end(), pred) != tok->values().end())
|
||||
return ValueFlow::Value{};
|
||||
std::copy_if(tok->values().begin(), tok->values().end(), std::back_inserter(result), pred);
|
||||
return result;
|
||||
}
|
||||
|
||||
ValueFlow::Value getLifetimeObjValue(const Token *tok, bool inconclusive)
|
||||
{
|
||||
std::vector<ValueFlow::Value> values = getLifetimeObjValues(tok, inconclusive, false);
|
||||
// There should only be one lifetime
|
||||
if (values.size() != 1)
|
||||
return ValueFlow::Value{};
|
||||
return values.front();
|
||||
}
|
||||
|
||||
std::vector<LifetimeToken> getLifetimeTokens(const Token* tok, bool escape, ValueFlow::Value::ErrorPath errorPath, int depth)
|
||||
{
|
||||
if (!tok)
|
||||
|
|
|
@ -401,4 +401,6 @@ std::string lifetimeMessage(const Token *tok, const ValueFlow::Value *val, Value
|
|||
|
||||
CPPCHECKLIB ValueFlow::Value getLifetimeObjValue(const Token *tok, bool inconclusive = false);
|
||||
|
||||
CPPCHECKLIB std::vector<ValueFlow::Value> getLifetimeObjValues(const Token *tok, bool inconclusive = false, bool subfunction = false);
|
||||
|
||||
#endif // valueflowH
|
||||
|
|
|
@ -4484,6 +4484,18 @@ private:
|
|||
" return m[1][1];\n"
|
||||
"}\n");
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
|
||||
check("void print(char** test);\n"
|
||||
"int main(){\n"
|
||||
" char* test = \"abcdef\";\n"
|
||||
" print(&test);\n"
|
||||
" return 0;\n"
|
||||
"}\n"
|
||||
"void print(char** test){\n"
|
||||
" for(int i=0;i<strlen(*test);i++)\n"
|
||||
" printf(\"%c\",*test[i]);\n"
|
||||
"}\n");
|
||||
ASSERT_EQUALS("[test.cpp:4] -> [test.cpp:4] -> [test.cpp:9]: (warning) The address of local variable 'test' might be accessed at non-zero index.\n", errout.str());
|
||||
}
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue