Extend lifetimes to subfunctions
This commit is contained in:
parent
efa113db55
commit
bb37b07def
|
@ -511,28 +511,31 @@ void CheckAutoVariables::checkVarLifetimeScope(const Token * start, const Token
|
|||
}
|
||||
}
|
||||
for (const ValueFlow::Value& val:tok->values()) {
|
||||
if (!val.isLocalLifetimeValue())
|
||||
if (!val.isLocalLifetimeValue() && !val.isSubFunctionLifetimeValue())
|
||||
continue;
|
||||
for (const LifetimeToken& lt :getLifetimeTokens(getParentLifetime(val.tokvalue))) {
|
||||
const Token * tokvalue = lt.token;
|
||||
if (Token::Match(tok->astParent(), "return|throw")) {
|
||||
if (getPointerDepth(tok) < getPointerDepth(tokvalue))
|
||||
continue;
|
||||
if (!isLifetimeBorrowed(tok, mSettings))
|
||||
continue;
|
||||
if ((tokvalue->variable() && !isEscapedReference(tokvalue->variable()) &&
|
||||
isInScope(tokvalue->variable()->nameToken(), scope)) ||
|
||||
isDeadTemporary(mTokenizer->isCPP(), tokvalue, tok, &mSettings->library)) {
|
||||
errorReturnDanglingLifetime(tok, &val);
|
||||
if (val.isLocalLifetimeValue()) {
|
||||
if (Token::Match(tok->astParent(), "return|throw")) {
|
||||
if (getPointerDepth(tok) < getPointerDepth(tokvalue))
|
||||
continue;
|
||||
if (!isLifetimeBorrowed(tok, mSettings))
|
||||
continue;
|
||||
if ((tokvalue->variable() && !isEscapedReference(tokvalue->variable()) &&
|
||||
isInScope(tokvalue->variable()->nameToken(), scope)) ||
|
||||
isDeadTemporary(mTokenizer->isCPP(), tokvalue, tok, &mSettings->library)) {
|
||||
errorReturnDanglingLifetime(tok, &val);
|
||||
break;
|
||||
}
|
||||
} else if (tokvalue->variable() && isDeadScope(tokvalue->variable()->nameToken(), tok->scope())) {
|
||||
errorInvalidLifetime(tok, &val);
|
||||
break;
|
||||
} else if (!tokvalue->variable() && isDeadTemporary(mTokenizer->isCPP(), tokvalue, tok, &mSettings->library)) {
|
||||
errorDanglingTemporaryLifetime(tok, &val);
|
||||
break;
|
||||
}
|
||||
} else if (tokvalue->variable() && isDeadScope(tokvalue->variable()->nameToken(), tok->scope())) {
|
||||
errorInvalidLifetime(tok, &val);
|
||||
break;
|
||||
} else if (!tokvalue->variable() && isDeadTemporary(mTokenizer->isCPP(), tokvalue, tok, &mSettings->library)) {
|
||||
errorDanglingTemporaryLifetime(tok, &val);
|
||||
break;
|
||||
} else if (tokvalue->variable() && isInScope(tokvalue->variable()->nameToken(), tok->scope())) {
|
||||
}
|
||||
if (tokvalue->variable() && (isInScope(tokvalue->variable()->nameToken(), tok->scope()) || (val.isSubFunctionLifetimeValue() && tokvalue->variable()->isLocal()))) {
|
||||
const Variable * var = nullptr;
|
||||
const Token * tok2 = tok;
|
||||
if (Token::simpleMatch(tok->astParent(), "=")) {
|
||||
|
|
|
@ -3874,6 +3874,10 @@ static void valueFlowLifetime(TokenList *tokenlist, SymbolDatabase*, ErrorLogger
|
|||
valueFlowForwardLifetime(tok, tokenlist, errorLogger, settings);
|
||||
}
|
||||
}
|
||||
// Forward any lifetimes
|
||||
else if (std::any_of(tok->values().begin(), tok->values().end(), std::mem_fn(&ValueFlow::Value::isLifetimeValue))) {
|
||||
valueFlowForwardLifetime(tok, tokenlist, errorLogger, settings);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5437,8 +5441,6 @@ static void valueFlowSubFunction(TokenList* tokenlist, SymbolDatabase* symboldat
|
|||
// passing value(s) to function
|
||||
std::list<ValueFlow::Value> argvalues(getFunctionArgumentValues(argtok));
|
||||
|
||||
// Don't forward lifetime values
|
||||
argvalues.remove_if(std::mem_fn(&ValueFlow::Value::isLifetimeValue));
|
||||
// Don't forward container sizes for now since programmemory can't evaluate conditions
|
||||
argvalues.remove_if(std::mem_fn(&ValueFlow::Value::isContainerSizeValue));
|
||||
|
||||
|
@ -5459,6 +5461,9 @@ static void valueFlowSubFunction(TokenList* tokenlist, SymbolDatabase* symboldat
|
|||
"' value is " +
|
||||
v.infoString());
|
||||
v.path = 256 * v.path + id;
|
||||
// Change scope of lifetime values
|
||||
if (v.isLifetimeValue())
|
||||
v.lifetimeScope = ValueFlow::Value::LifetimeScope::SubFunction;
|
||||
}
|
||||
|
||||
// passed values are not "known"..
|
||||
|
@ -6649,6 +6654,7 @@ void ValueFlow::setValues(TokenList *tokenlist, SymbolDatabase* symboldatabase,
|
|||
valueFlowSwitchVariable(tokenlist, symboldatabase, errorLogger, settings);
|
||||
valueFlowForLoop(tokenlist, symboldatabase, errorLogger, settings);
|
||||
valueFlowSubFunction(tokenlist, symboldatabase, errorLogger, settings);
|
||||
valueFlowLifetime(tokenlist, symboldatabase, errorLogger, settings);
|
||||
valueFlowFunctionDefaultParameter(tokenlist, symboldatabase, errorLogger, settings);
|
||||
valueFlowUninit(tokenlist, symboldatabase, errorLogger, settings);
|
||||
if (tokenlist->isCPP()) {
|
||||
|
|
|
@ -217,6 +217,10 @@ namespace ValueFlow {
|
|||
return valueType == ValueType::LIFETIME && lifetimeScope == LifetimeScope::Argument;
|
||||
}
|
||||
|
||||
bool isSubFunctionLifetimeValue() const {
|
||||
return valueType == ValueType::LIFETIME && lifetimeScope == LifetimeScope::SubFunction;
|
||||
}
|
||||
|
||||
bool isNonValue() const {
|
||||
return isMovedValue() || isUninitValue() || isLifetimeValue();
|
||||
}
|
||||
|
@ -263,7 +267,7 @@ namespace ValueFlow {
|
|||
|
||||
enum class LifetimeKind {Object, SubObject, Lambda, Iterator, Address} lifetimeKind;
|
||||
|
||||
enum class LifetimeScope { Local, Argument } lifetimeScope;
|
||||
enum class LifetimeScope { Local, Argument, SubFunction } lifetimeScope;
|
||||
|
||||
static const char* toString(MoveKind moveKind);
|
||||
|
||||
|
|
|
@ -2156,6 +2156,18 @@ private:
|
|||
" std::sort(x.begin(), x.end());\n"
|
||||
"}\n");
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
|
||||
check("struct A {\n"
|
||||
" std::vector<int*> v;\n"
|
||||
" void add(int* i) {\n"
|
||||
" v.push_back(i);\n"
|
||||
" }\n"
|
||||
" void f() {\n"
|
||||
" int i = 0;\n"
|
||||
" add(&i);\n"
|
||||
" }\n"
|
||||
"};\n");
|
||||
ASSERT_EQUALS("[test.cpp:8] -> [test.cpp:8] -> [test.cpp:4] -> [test.cpp:7] -> [test.cpp:4]: (error) Non-local variable 'v' will use object that points to local variable 'i'.\n", errout.str());
|
||||
}
|
||||
|
||||
void danglingLifetime() {
|
||||
|
|
Loading…
Reference in New Issue