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

View File

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

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

View File

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