Fix issue 8650: ValueFlow: Track if pointer is created by '&' operator (#3011)

This commit is contained in:
Paul Fultz II 2021-01-05 09:56:38 -06:00 committed by GitHub
parent 8897ad3408
commit e004731f1c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 50 additions and 25 deletions

View File

@ -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;
}
}
}
}

View File

@ -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)

View File

@ -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

View File

@ -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());
}
};