Fix 10238: FP knownConditionTrueFalse std::string from const char* assumed non-empty (#3288)
This commit is contained in:
parent
537fb5bcd9
commit
a14922ed85
|
@ -6307,25 +6307,60 @@ static void valueFlowIteratorInfer(TokenList *tokenlist, const Settings *setting
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::vector<ValueFlow::Value> getInitListSize(const Token* tok,
|
static std::vector<ValueFlow::Value> getContainerValues(const Token* tok)
|
||||||
const Library::Container* container,
|
|
||||||
bool known = true)
|
|
||||||
{
|
{
|
||||||
std::vector<const Token*> args = getArguments(tok);
|
std::vector<ValueFlow::Value> values;
|
||||||
if ((args.size() == 1 && astIsContainer(args[0]) && args[0]->valueType()->container == container) ||
|
if (tok) {
|
||||||
(args.size() == 2 && astIsIterator(args[0]) && astIsIterator(args[1]))) {
|
std::copy_if(tok->values().begin(),
|
||||||
std::vector<ValueFlow::Value> values;
|
tok->values().end(),
|
||||||
std::copy_if(args[0]->values().begin(),
|
|
||||||
args[0]->values().end(),
|
|
||||||
std::back_inserter(values),
|
std::back_inserter(values),
|
||||||
std::mem_fn(&ValueFlow::Value::isContainerSizeValue));
|
std::mem_fn(&ValueFlow::Value::isContainerSizeValue));
|
||||||
return values;
|
|
||||||
}
|
}
|
||||||
ValueFlow::Value value(args.size());
|
return values;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ValueFlow::Value makeContainerSizeValue(std::size_t s, bool known = true)
|
||||||
|
{
|
||||||
|
ValueFlow::Value value(s);
|
||||||
value.valueType = ValueFlow::Value::ValueType::CONTAINER_SIZE;
|
value.valueType = ValueFlow::Value::ValueType::CONTAINER_SIZE;
|
||||||
if (known)
|
if (known)
|
||||||
value.setKnown();
|
value.setKnown();
|
||||||
return {value};
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::vector<ValueFlow::Value> makeContainerSizeValue(const Token* tok, bool known = true)
|
||||||
|
{
|
||||||
|
if (tok->hasKnownIntValue())
|
||||||
|
return {makeContainerSizeValue(tok->values().front().intvalue, known)};
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::vector<ValueFlow::Value> getInitListSize(const Token* tok,
|
||||||
|
const Library::Container* container,
|
||||||
|
bool known = true)
|
||||||
|
{
|
||||||
|
std::vector<const Token*> args = getArguments(tok);
|
||||||
|
// Strings dont use an init list
|
||||||
|
if (!args.empty() && container->stdStringLike) {
|
||||||
|
if (astIsIntegral(args[0], false)) {
|
||||||
|
if (args.size() > 1)
|
||||||
|
return {makeContainerSizeValue(args[0], known)};
|
||||||
|
} else if (astIsPointer(args[0])) {
|
||||||
|
// TODO: Try to read size of string literal
|
||||||
|
if (args.size() == 2 && astIsIntegral(args[1], false))
|
||||||
|
return {makeContainerSizeValue(args[1], known)};
|
||||||
|
} else if (astIsContainer(args[0])) {
|
||||||
|
if (args.size() == 1)
|
||||||
|
return getContainerValues(args[0]);
|
||||||
|
if (args.size() == 3)
|
||||||
|
return {makeContainerSizeValue(args[2], known)};
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
} else if ((args.size() == 1 && astIsContainer(args[0]) && args[0]->valueType()->container == container) ||
|
||||||
|
(args.size() == 2 && astIsIterator(args[0]) && astIsIterator(args[1]))) {
|
||||||
|
return getContainerValues(args[0]);
|
||||||
|
}
|
||||||
|
return {makeContainerSizeValue(args.size(), known)};
|
||||||
}
|
}
|
||||||
|
|
||||||
static void valueFlowContainerSize(TokenList *tokenlist, SymbolDatabase* symboldatabase, ErrorLogger * /*errorLogger*/, const Settings *settings)
|
static void valueFlowContainerSize(TokenList *tokenlist, SymbolDatabase* symboldatabase, ErrorLogger * /*errorLogger*/, const Settings *settings)
|
||||||
|
|
|
@ -527,6 +527,16 @@ private:
|
||||||
" return (*pv).at(42);\n"
|
" return (*pv).at(42);\n"
|
||||||
"}\n");
|
"}\n");
|
||||||
ASSERT_EQUALS("test.cpp:4:error:Out of bounds access in expression '(*pv).at(42)' because '*pv' is empty and 'at' may be non-zero.\n", errout.str());
|
ASSERT_EQUALS("test.cpp:4:error:Out of bounds access in expression '(*pv).at(42)' because '*pv' is empty and 'at' may be non-zero.\n", errout.str());
|
||||||
|
|
||||||
|
checkNormal("std::string f(const char* DirName) {\n"
|
||||||
|
" if (DirName == nullptr)\n"
|
||||||
|
" return {};\n"
|
||||||
|
" std::string Name{ DirName };\n"
|
||||||
|
" if (!Name.empty() && Name.back() != '\\')\n"
|
||||||
|
" Name += '\\';\n"
|
||||||
|
" return Name;\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void outOfBoundsIndexExpression() {
|
void outOfBoundsIndexExpression() {
|
||||||
|
|
Loading…
Reference in New Issue