ValueFlow: Better info for buffer size values

This commit is contained in:
Daniel Marjamäki 2019-03-17 19:02:36 +01:00
parent 19e9e42dd7
commit 3c85d8a8ac
3 changed files with 28 additions and 29 deletions

View File

@ -60,25 +60,13 @@ static const CWE CWE788(788U); // Access of Memory Location After End of Buffer
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
static std::vector<Dimension> getDynamicDimensions(const Token *tok, MathLib::bigint typeSize) static const ValueFlow::Value *getBufferSizeValue(const Token *tok)
{ {
if (typeSize == 0) {
const std::vector<Dimension> dimensions;
return dimensions;
}
for (const ValueFlow::Value &value : tok->values()) { for (const ValueFlow::Value &value : tok->values()) {
if (!value.isBufferSizeValue()) if (value.isBufferSizeValue())
continue; return &value;
Dimension dim;
dim.tok = nullptr;
dim.num = value.intvalue / typeSize;
dim.known = value.isKnown();
const std::vector<Dimension> dimensions{dim};
return dimensions;
} }
return nullptr;
const std::vector<Dimension> dimensions;
return dimensions;
} }
static size_t getMinFormatStringOutputLength(const std::vector<const Token*> &parameters, unsigned int formatStringArgNr) static size_t getMinFormatStringOutputLength(const std::vector<const Token*> &parameters, unsigned int formatStringArgNr)
@ -218,6 +206,7 @@ void CheckBufferOverrun::arrayIndex()
continue; continue;
std::vector<Dimension> dimensions; std::vector<Dimension> dimensions;
ErrorPath errorPath;
bool mightBeLarger; bool mightBeLarger;
@ -232,7 +221,15 @@ void CheckBufferOverrun::arrayIndex()
dimensions.emplace_back(dim); dimensions.emplace_back(dim);
mightBeLarger = false; mightBeLarger = false;
} else if (array->valueType() && array->valueType()->pointer >= 1 && array->valueType()->isIntegral()) { } else if (array->valueType() && array->valueType()->pointer >= 1 && array->valueType()->isIntegral()) {
dimensions = getDynamicDimensions(array, array->valueType()->typeSize(*mSettings)); const ValueFlow::Value *value = getBufferSizeValue(array);
if (!value)
continue;
errorPath = value->errorPath;
Dimension dim;
dim.known = value->isKnown();
dim.tok = nullptr;
dim.num = value->intvalue / array->valueType()->typeSize(*mSettings);
dimensions.emplace_back(dim);
mightBeLarger = false; mightBeLarger = false;
} }
@ -326,22 +323,24 @@ size_t CheckBufferOverrun::getBufferSize(const Token *bufTok) const
if (!bufTok->valueType()) if (!bufTok->valueType())
return 0; return 0;
const Variable *var = bufTok->variable(); const Variable *var = bufTok->variable();
if (!var || var->dimensions().empty()) {
const ValueFlow::Value *value = getBufferSizeValue(bufTok);
if (value)
return value->intvalue;
}
if (!var) if (!var)
return 0; return 0;
const MathLib::bigint typeSize = bufTok->valueType()->typeSize(*mSettings);
std::vector<Dimension> dimensions;
if (!var->dimensions().empty())
dimensions = var->dimensions();
else
dimensions = getDynamicDimensions(bufTok, typeSize);
if (dimensions.empty())
return 0;
MathLib::bigint dim = 1; MathLib::bigint dim = 1;
for (const Dimension &d : dimensions) for (const Dimension &d : var->dimensions())
dim *= d.num; dim *= d.num;
if (var->isPointerArray()) if (var->isPointerArray())
return dim * mSettings->sizeof_pointer; return dim * mSettings->sizeof_pointer;
const MathLib::bigint typeSize = bufTok->valueType()->typeSize(*mSettings);
return dim * typeSize; return dim * typeSize;
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
@ -372,8 +371,6 @@ static bool checkBufferSize(const Token *ftok, const Library::ArgumentChecks::Mi
if (arg && arg2 && arg->hasKnownIntValue() && arg2->hasKnownIntValue()) if (arg && arg2 && arg->hasKnownIntValue() && arg2->hasKnownIntValue())
return (arg->getKnownIntValue() * arg2->getKnownIntValue()) <= bufferSize; return (arg->getKnownIntValue() * arg2->getKnownIntValue()) <= bufferSize;
break; break;
case Library::ArgumentChecks::MinSize::Type::VALUE:
return minsize.value <= bufferSize;
case Library::ArgumentChecks::MinSize::Type::NONE: case Library::ArgumentChecks::MinSize::Type::NONE:
break; break;
}; };

View File

@ -5038,6 +5038,7 @@ static void valueFlowDynamicBufferSize(TokenList *tokenlist, SymbolDatabase *sym
continue; continue;
ValueFlow::Value value(sizeArg->getKnownIntValue()); ValueFlow::Value value(sizeArg->getKnownIntValue());
value.errorPath.emplace_back(tok->tokAt(2), "Assign " + tok->strAt(1) + ", buffer with size " + MathLib::toString(value.intvalue));
value.valueType = ValueFlow::Value::ValueType::BUFFER_SIZE; value.valueType = ValueFlow::Value::ValueType::BUFFER_SIZE;
value.setKnown(); value.setKnown();
const std::list<ValueFlow::Value> values{value}; const std::list<ValueFlow::Value> values{value};

View File

@ -3601,7 +3601,8 @@ private:
"void bar(char *p) {\n" "void bar(char *p) {\n"
" strncpy(p, str, 100);\n" " strncpy(p, str, 100);\n"
"}\n", false); "}\n", false);
ASSERT_EQUALS("[test.cpp:4]: (warning, inconclusive) The buffer 'str' may not be null-terminated after the call to strncpy().\n", errout.str()); ASSERT_EQUALS("[test.cpp:4]: (warning, inconclusive) The buffer 'str' may not be null-terminated after the call to strncpy().\n"
"[test.cpp:8]: (warning, inconclusive) The buffer 'p' may not be null-terminated after the call to strncpy().\n", errout.str());
} }
void terminateStrncpy4() { void terminateStrncpy4() {