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)
|
if (idx->hasKnownIntValue() && idx->getKnownIntValue() == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
ValueFlow::Value v = getLifetimeObjValue(obj);
|
std::vector<ValueFlow::Value> values = getLifetimeObjValues(obj, false, true);
|
||||||
if (!v.isLocalLifetimeValue())
|
for(const ValueFlow::Value& v:values) {
|
||||||
continue;
|
if (v.lifetimeKind != ValueFlow::Value::LifetimeKind::Address)
|
||||||
if (v.lifetimeKind != ValueFlow::Value::LifetimeKind::Address)
|
continue;
|
||||||
continue;
|
const Variable *var = v.tokvalue->variable();
|
||||||
const Variable *var = v.tokvalue->variable();
|
if (var->isReference())
|
||||||
if (var->isReference())
|
continue;
|
||||||
continue;
|
if (var->isRValueReference())
|
||||||
if (var->isRValueReference())
|
continue;
|
||||||
continue;
|
if (var->isArray())
|
||||||
if (var->isArray())
|
continue;
|
||||||
continue;
|
if (var->isPointer()) {
|
||||||
if (var->isPointer())
|
if (!var->valueType())
|
||||||
continue;
|
continue;
|
||||||
objectIndexError(tok, &v, idx->hasKnownIntValue());
|
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 <algorithm>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
#include <cstdint>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
|
@ -2703,11 +2704,11 @@ std::string lifetimeMessage(const Token *tok, const ValueFlow::Value *val, Error
|
||||||
return msg;
|
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) {
|
auto pred = [&](const ValueFlow::Value &v) {
|
||||||
if (!v.isLocalLifetimeValue())
|
if (!v.isLocalLifetimeValue() && !(subfunction && v.isSubFunctionLifetimeValue()))
|
||||||
return false;
|
return false;
|
||||||
if (!inconclusive && v.isInconclusive())
|
if (!inconclusive && v.isInconclusive())
|
||||||
return false;
|
return false;
|
||||||
|
@ -2715,16 +2716,19 @@ ValueFlow::Value getLifetimeObjValue(const Token *tok, bool inconclusive)
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
auto it = std::find_if(tok->values().begin(), tok->values().end(), pred);
|
std::copy_if(tok->values().begin(), tok->values().end(), std::back_inserter(result), 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{};
|
|
||||||
return result;
|
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)
|
std::vector<LifetimeToken> getLifetimeTokens(const Token* tok, bool escape, ValueFlow::Value::ErrorPath errorPath, int depth)
|
||||||
{
|
{
|
||||||
if (!tok)
|
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 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
|
#endif // valueflowH
|
||||||
|
|
|
@ -4484,6 +4484,18 @@ private:
|
||||||
" return m[1][1];\n"
|
" return m[1][1];\n"
|
||||||
"}\n");
|
"}\n");
|
||||||
ASSERT_EQUALS("", errout.str());
|
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