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> getContainerValues(const Token* tok)
|
||||
{
|
||||
std::vector<ValueFlow::Value> values;
|
||||
if (tok) {
|
||||
std::copy_if(tok->values().begin(),
|
||||
tok->values().end(),
|
||||
std::back_inserter(values),
|
||||
std::mem_fn(&ValueFlow::Value::isContainerSizeValue));
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
static ValueFlow::Value makeContainerSizeValue(std::size_t s, bool known = true)
|
||||
{
|
||||
ValueFlow::Value value(s);
|
||||
value.valueType = ValueFlow::Value::ValueType::CONTAINER_SIZE;
|
||||
if (known)
|
||||
value.setKnown();
|
||||
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);
|
||||
if ((args.size() == 1 && astIsContainer(args[0]) && args[0]->valueType()->container == container) ||
|
||||
(args.size() == 2 && astIsIterator(args[0]) && astIsIterator(args[1]))) {
|
||||
std::vector<ValueFlow::Value> values;
|
||||
std::copy_if(args[0]->values().begin(),
|
||||
args[0]->values().end(),
|
||||
std::back_inserter(values),
|
||||
std::mem_fn(&ValueFlow::Value::isContainerSizeValue));
|
||||
return values;
|
||||
// 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)};
|
||||
}
|
||||
ValueFlow::Value value(args.size());
|
||||
value.valueType = ValueFlow::Value::ValueType::CONTAINER_SIZE;
|
||||
if (known)
|
||||
value.setKnown();
|
||||
return {value};
|
||||
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)
|
||||
|
|
|
@ -527,6 +527,16 @@ private:
|
|||
" return (*pv).at(42);\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());
|
||||
|
||||
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() {
|
||||
|
|
Loading…
Reference in New Issue