Skip to content

Commit 74b0803

Browse files
committed
Fix #13521 (Duplicate warnings nullPointerOutOfMemory and ctunullpointer)
1 parent cdf9d6d commit 74b0803

8 files changed

+149
-42
lines changed

lib/checkbufferoverrun.cpp

+9-9
Original file line numberDiff line numberDiff line change
@@ -914,7 +914,7 @@ namespace
914914
};
915915
}
916916

917-
bool CheckBufferOverrun::isCtuUnsafeBufferUsage(const Settings &settings, const Token *argtok, MathLib::bigint *offset, int type)
917+
bool CheckBufferOverrun::isCtuUnsafeBufferUsage(const Settings &settings, const Token *argtok, CTU::FileInfo::Value *offset, int type)
918918
{
919919
if (!offset)
920920
return false;
@@ -931,16 +931,16 @@ bool CheckBufferOverrun::isCtuUnsafeBufferUsage(const Settings &settings, const
931931
return false;
932932
if (!indexTok->hasKnownIntValue())
933933
return false;
934-
*offset = indexTok->getKnownIntValue() * argtok->valueType()->typeSize(settings.platform);
934+
offset->value = indexTok->getKnownIntValue() * argtok->valueType()->typeSize(settings.platform);
935935
return true;
936936
}
937937

938-
bool CheckBufferOverrun::isCtuUnsafeArrayIndex(const Settings &settings, const Token *argtok, MathLib::bigint *offset)
938+
bool CheckBufferOverrun::isCtuUnsafeArrayIndex(const Settings &settings, const Token *argtok, CTU::FileInfo::Value *offset)
939939
{
940940
return isCtuUnsafeBufferUsage(settings, argtok, offset, 1);
941941
}
942942

943-
bool CheckBufferOverrun::isCtuUnsafePointerArith(const Settings &settings, const Token *argtok, MathLib::bigint *offset)
943+
bool CheckBufferOverrun::isCtuUnsafePointerArith(const Settings &settings, const Token *argtok, CTU::FileInfo::Value* offset)
944944
{
945945
return isCtuUnsafeBufferUsage(settings, argtok, offset, 2);
946946
}
@@ -1030,14 +1030,14 @@ bool CheckBufferOverrun::analyseWholeProgram1(const std::map<std::string, std::l
10301030

10311031
if (type == 1) {
10321032
errorId = "ctuArrayIndex";
1033-
if (unsafeUsage.value > 0)
1034-
errmsg = "Array index out of bounds; '" + unsafeUsage.myArgumentName + "' buffer size is " + MathLib::toString(functionCall->callArgValue) + " and it is accessed at offset " + MathLib::toString(unsafeUsage.value) + ".";
1033+
if (unsafeUsage.value.value > 0)
1034+
errmsg = "Array index out of bounds; '" + unsafeUsage.myArgumentName + "' buffer size is " + MathLib::toString(functionCall->callArgValue.value) + " and it is accessed at offset " + MathLib::toString(unsafeUsage.value.value) + ".";
10351035
else
1036-
errmsg = "Array index out of bounds; buffer '" + unsafeUsage.myArgumentName + "' is accessed at offset " + MathLib::toString(unsafeUsage.value) + ".";
1037-
cwe = (unsafeUsage.value > 0) ? CWE_BUFFER_OVERRUN : CWE_BUFFER_UNDERRUN;
1036+
errmsg = "Array index out of bounds; buffer '" + unsafeUsage.myArgumentName + "' is accessed at offset " + MathLib::toString(unsafeUsage.value.value) + ".";
1037+
cwe = (unsafeUsage.value.value > 0) ? CWE_BUFFER_OVERRUN : CWE_BUFFER_UNDERRUN;
10381038
} else {
10391039
errorId = "ctuPointerArith";
1040-
errmsg = "Pointer arithmetic overflow; '" + unsafeUsage.myArgumentName + "' buffer size is " + MathLib::toString(functionCall->callArgValue);
1040+
errmsg = "Pointer arithmetic overflow; '" + unsafeUsage.myArgumentName + "' buffer size is " + MathLib::toString(functionCall->callArgValue.value);
10411041
cwe = CWE_POINTER_ARITHMETIC_OVERFLOW;
10421042
}
10431043

lib/checkbufferoverrun.h

+3-3
Original file line numberDiff line numberDiff line change
@@ -107,9 +107,9 @@ class CPPCHECKLIB CheckBufferOverrun : public Check {
107107
ValueFlow::Value getBufferSize(const Token *bufTok) const;
108108

109109
// CTU
110-
static bool isCtuUnsafeBufferUsage(const Settings &settings, const Token *argtok, MathLib::bigint *offset, int type);
111-
static bool isCtuUnsafeArrayIndex(const Settings &settings, const Token *argtok, MathLib::bigint *offset);
112-
static bool isCtuUnsafePointerArith(const Settings &settings, const Token *argtok, MathLib::bigint *offset);
110+
static bool isCtuUnsafeBufferUsage(const Settings &settings, const Token *argtok, CTU::FileInfo::Value *offset, int type);
111+
static bool isCtuUnsafeArrayIndex(const Settings &settings, const Token *argtok, CTU::FileInfo::Value *offset);
112+
static bool isCtuUnsafePointerArith(const Settings &settings, const Token *argtok, CTU::FileInfo::Value *offset);
113113

114114
Check::FileInfo * loadFileInfoFromXml(const tinyxml2::XMLElement *xmlElement) const override;
115115
static bool analyseWholeProgram1(const std::map<std::string, std::list<const CTU::FileInfo::CallBase *>> &callsMap, const CTU::FileInfo::UnsafeUsage &unsafeUsage,

lib/checknullpointer.cpp

+18-4
Original file line numberDiff line numberDiff line change
@@ -583,7 +583,7 @@ void CheckNullPointer::redundantConditionWarning(const Token* tok, const ValueFl
583583
}
584584

585585
// NOLINTNEXTLINE(readability-non-const-parameter) - used as callback so we need to preserve the signature
586-
static bool isUnsafeUsage(const Settings &settings, const Token *vartok, MathLib::bigint *value)
586+
static bool isUnsafeUsage(const Settings &settings, const Token *vartok, CTU::FileInfo::Value *value)
587587
{
588588
(void)value;
589589
bool unknown = false;
@@ -659,22 +659,36 @@ bool CheckNullPointer::analyseWholeProgram(const CTU::FileInfo &ctu, const std::
659659
if (warning == 1 && !settings.severity.isEnabled(Severity::warning))
660660
break;
661661

662+
std::uint8_t unknownFunctionReturn = 0;
662663
const std::list<ErrorMessage::FileLocation> &locationList =
663664
CTU::FileInfo::getErrorPath(CTU::FileInfo::InvalidValueType::null,
664665
unsafeUsage,
665666
callsMap,
666667
"Dereferencing argument ARG that is null",
667668
nullptr,
668669
warning,
669-
settings.maxCtuDepth);
670+
settings.maxCtuDepth,
671+
&unknownFunctionReturn);
670672
if (locationList.empty())
671673
continue;
672674

675+
std::string id = "ctunullpointer";
676+
std::string message = "Null pointer dereference: " + unsafeUsage.myArgumentName;
677+
if (unknownFunctionReturn == (std::uint8_t)ValueFlow::Value::UnknownFunctionReturn::outOfMemory) {
678+
id += "OutOfMemory";
679+
warning = 1;
680+
message = "If memory allocation fails, then there is a possible null pointer dereference: " + unsafeUsage.myArgumentName;
681+
} else if (unknownFunctionReturn == (std::uint8_t)ValueFlow::Value::UnknownFunctionReturn::outOfResources) {
682+
id += "OutOfResources";
683+
warning = 1;
684+
message = "If resource allocation fails, then there is a possible null pointer dereference: " + unsafeUsage.myArgumentName;
685+
}
686+
673687
const ErrorMessage errmsg(locationList,
674688
fi->file0,
675689
warning ? Severity::warning : Severity::error,
676-
"Null pointer dereference: " + unsafeUsage.myArgumentName,
677-
"ctunullpointer",
690+
message,
691+
id,
678692
CWE_NULL_POINTER_DEREFERENCE, Certainty::normal);
679693
errorLogger.reportErr(errmsg);
680694

lib/checkuninitvar.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -1722,6 +1722,10 @@ namespace
17221722
};
17231723
}
17241724

1725+
static bool isVariableUsage(const Settings &settings, const Token *argtok, CTU::FileInfo::Value *value) {
1726+
return isVariableUsage(settings, argtok, &value->value);
1727+
}
1728+
17251729
Check::FileInfo *CheckUninitVar::getFileInfo(const Tokenizer &tokenizer, const Settings &settings) const
17261730
{
17271731
const std::list<CTU::FileInfo::UnsafeUsage> &unsafeUsage = CTU::getUnsafeUsage(tokenizer, settings, ::isVariableUsage);

lib/ctu.cpp

+34-21
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ static constexpr char ATTR_CALL_ARGNR[] = "call-argnr";
4545
static constexpr char ATTR_CALL_ARGEXPR[] = "call-argexpr";
4646
static constexpr char ATTR_CALL_ARGVALUETYPE[] = "call-argvaluetype";
4747
static constexpr char ATTR_CALL_ARGVALUE[] = "call-argvalue";
48+
static constexpr char ATTR_CALL_UNKNOWN_FUNCTION_RETURN[] = "call-argvalue-ufr";
4849
static constexpr char ATTR_WARNING[] = "warning";
4950
static constexpr char ATTR_LOC_FILENAME[] = "file";
5051
static constexpr char ATTR_LOC_LINENR[] = "line";
@@ -54,6 +55,7 @@ static constexpr char ATTR_MY_ID[] = "my-id";
5455
static constexpr char ATTR_MY_ARGNR[] = "my-argnr";
5556
static constexpr char ATTR_MY_ARGNAME[] = "my-argname";
5657
static constexpr char ATTR_VALUE[] = "value";
58+
static constexpr char ATTR_UNKNOWN_FUNCTION_RETURN[] = "ufr";
5759

5860
std::string CTU::getFunctionId(const Tokenizer &tokenizer, const Function *function)
5961
{
@@ -102,7 +104,8 @@ std::string CTU::FileInfo::FunctionCall::toXmlString() const
102104
<< toBaseXmlString()
103105
<< " " << ATTR_CALL_ARGEXPR << "=\"" << ErrorLogger::toxml(callArgumentExpression) << "\""
104106
<< " " << ATTR_CALL_ARGVALUETYPE << "=\"" << static_cast<int>(callValueType) << "\""
105-
<< " " << ATTR_CALL_ARGVALUE << "=\"" << callArgValue << "\"";
107+
<< " " << ATTR_CALL_ARGVALUE << "=\"" << callArgValue.value << "\""
108+
<< " " << ATTR_CALL_UNKNOWN_FUNCTION_RETURN << "=\"" << (int)callArgValue.unknownFunctionReturn << "\"";
106109
if (warning)
107110
out << " " << ATTR_WARNING << "=\"true\"";
108111
if (callValuePath.empty())
@@ -141,7 +144,8 @@ std::string CTU::FileInfo::UnsafeUsage::toString() const
141144
<< " " << ATTR_LOC_FILENAME << "=\"" << ErrorLogger::toxml(location.fileName) << '\"'
142145
<< " " << ATTR_LOC_LINENR << "=\"" << location.lineNumber << '\"'
143146
<< " " << ATTR_LOC_COLUMN << "=\"" << location.column << '\"'
144-
<< " " << ATTR_VALUE << "=\"" << value << "\""
147+
<< " " << ATTR_VALUE << "=\"" << value.value << "\""
148+
<< " " << ATTR_UNKNOWN_FUNCTION_RETURN << "=\"" << (int)value.unknownFunctionReturn << "\""
145149
<< "/>\n";
146150
return out.str();
147151
}
@@ -201,7 +205,8 @@ bool CTU::FileInfo::FunctionCall::loadFromXml(const tinyxml2::XMLElement *xmlEle
201205
bool error=false;
202206
callArgumentExpression = readAttrString(xmlElement, ATTR_CALL_ARGEXPR, &error);
203207
callValueType = (ValueFlow::Value::ValueType)readAttrInt(xmlElement, ATTR_CALL_ARGVALUETYPE, &error);
204-
callArgValue = readAttrInt(xmlElement, ATTR_CALL_ARGVALUE, &error);
208+
callArgValue.value = readAttrInt(xmlElement, ATTR_CALL_ARGVALUE, &error);
209+
callArgValue.unknownFunctionReturn = readAttrInt(xmlElement, ATTR_CALL_UNKNOWN_FUNCTION_RETURN, &error);
205210
const char *w = xmlElement->Attribute(ATTR_WARNING);
206211
warning = w && std::strcmp(w, "true") == 0;
207212
for (const tinyxml2::XMLElement *e2 = xmlElement->FirstChildElement(); !error && e2; e2 = e2->NextSiblingElement()) {
@@ -267,7 +272,8 @@ std::list<CTU::FileInfo::UnsafeUsage> CTU::loadUnsafeUsageListFromXml(const tiny
267272
unsafeUsage.location.fileName = readAttrString(e, ATTR_LOC_FILENAME, &error);
268273
unsafeUsage.location.lineNumber = readAttrInt(e, ATTR_LOC_LINENR, &error);
269274
unsafeUsage.location.column = readAttrInt(e, ATTR_LOC_COLUMN, &error);
270-
unsafeUsage.value = readAttrInt(e, ATTR_VALUE, &error);
275+
unsafeUsage.value.value = readAttrInt(e, ATTR_VALUE, &error);
276+
unsafeUsage.value.unknownFunctionReturn = readAttrInt(e, ATTR_UNKNOWN_FUNCTION_RETURN, &error);
271277

272278
if (!error)
273279
ret.push_back(std::move(unsafeUsage));
@@ -342,7 +348,7 @@ CTU::FileInfo *CTU::getFileInfo(const Tokenizer &tokenizer)
342348
functionCall.location = FileInfo::Location(tokenizer,tok);
343349
functionCall.callArgNr = argnr + 1;
344350
functionCall.callArgumentExpression = argtok->expressionString();
345-
functionCall.callArgValue = value.intvalue;
351+
functionCall.callArgValue = value;
346352
functionCall.warning = !value.errorSeverity();
347353
for (const ErrorPathItem &i : value.errorPath) {
348354
const std::string& file = tokenizer.list.file(i.first);
@@ -364,7 +370,7 @@ CTU::FileInfo *CTU::getFileInfo(const Tokenizer &tokenizer)
364370
functionCall.callArgNr = argnr + 1;
365371
functionCall.callArgumentExpression = argtok->expressionString();
366372
const auto typeSize = argtok->valueType()->typeSize(tokenizer.getSettings().platform);
367-
functionCall.callArgValue = typeSize > 0 ? argtok->variable()->dimension(0) * typeSize : -1;
373+
functionCall.callArgValue.value = typeSize > 0 ? argtok->variable()->dimension(0) * typeSize : -1;
368374
functionCall.warning = false;
369375
fileInfo->functionCalls.push_back(std::move(functionCall));
370376
}
@@ -377,7 +383,7 @@ CTU::FileInfo *CTU::getFileInfo(const Tokenizer &tokenizer)
377383
functionCall.location = FileInfo::Location(tokenizer, tok);
378384
functionCall.callArgNr = argnr + 1;
379385
functionCall.callArgumentExpression = argtok->expressionString();
380-
functionCall.callArgValue = argtok->astOperand1()->valueType()->typeSize(tokenizer.getSettings().platform);
386+
functionCall.callArgValue.value = argtok->astOperand1()->valueType()->typeSize(tokenizer.getSettings().platform);
381387
functionCall.warning = false;
382388
fileInfo->functionCalls.push_back(std::move(functionCall));
383389
}
@@ -411,7 +417,8 @@ CTU::FileInfo *CTU::getFileInfo(const Tokenizer &tokenizer)
411417
functionCall.callFunctionName = tok->astOperand1()->expressionString();
412418
functionCall.location = FileInfo::Location(tokenizer, tok);
413419
functionCall.callArgNr = argnr + 1;
414-
functionCall.callArgValue = 0;
420+
functionCall.callArgValue = v;
421+
functionCall.callArgValue.value = 0;
415422
functionCall.callArgumentExpression = argtok->expressionString();
416423
functionCall.warning = false;
417424
fileInfo->functionCalls.push_back(std::move(functionCall));
@@ -436,9 +443,9 @@ CTU::FileInfo *CTU::getFileInfo(const Tokenizer &tokenizer)
436443
return fileInfo;
437444
}
438445

439-
static std::list<std::pair<const Token *, MathLib::bigint>> getUnsafeFunction(const Settings &settings, const Scope *scope, int argnr, bool (*isUnsafeUsage)(const Settings &settings, const Token *argtok, MathLib::bigint *value))
446+
static std::vector<std::pair<const Token *, CTU::FileInfo::Value>> getUnsafeFunction(const Settings &settings, const Scope *scope, int argnr, bool (*isUnsafeUsage)(const Settings &settings, const Token *argtok, CTU::FileInfo::Value *value))
440447
{
441-
std::list<std::pair<const Token *, MathLib::bigint>> ret;
448+
std::vector<std::pair<const Token *, CTU::FileInfo::Value>> ret;
442449
const Variable * const argvar = scope->function->getArgumentVar(argnr);
443450
if (!argvar->isArrayOrPointer() && !argvar->isReference())
444451
return ret;
@@ -459,7 +466,7 @@ static std::list<std::pair<const Token *, MathLib::bigint>> getUnsafeFunction(co
459466
}
460467
if (tok2->variable() != argvar)
461468
continue;
462-
MathLib::bigint value = 0;
469+
CTU::FileInfo::Value value;
463470
if (!isUnsafeUsage(settings, tok2, &value))
464471
return ret; // TODO: Is this a read? then continue..
465472
ret.emplace_back(tok2, value);
@@ -468,7 +475,7 @@ static std::list<std::pair<const Token *, MathLib::bigint>> getUnsafeFunction(co
468475
return ret;
469476
}
470477

471-
std::list<CTU::FileInfo::UnsafeUsage> CTU::getUnsafeUsage(const Tokenizer &tokenizer, const Settings &settings, bool (*isUnsafeUsage)(const Settings &settings, const Token *argtok, MathLib::bigint *value))
478+
std::list<CTU::FileInfo::UnsafeUsage> CTU::getUnsafeUsage(const Tokenizer &tokenizer, const Settings &settings, bool (*isUnsafeUsage)(const Settings &settings, const Token *argtok, CTU::FileInfo::Value *value))
472479
{
473480
std::list<CTU::FileInfo::UnsafeUsage> unsafeUsage;
474481

@@ -482,9 +489,9 @@ std::list<CTU::FileInfo::UnsafeUsage> CTU::getUnsafeUsage(const Tokenizer &token
482489

483490
// "Unsafe" functions unconditionally reads data before it is written..
484491
for (int argnr = 0; argnr < function->argCount(); ++argnr) {
485-
for (const std::pair<const Token *, MathLib::bigint> &v : getUnsafeFunction(settings, &scope, argnr, isUnsafeUsage)) {
492+
for (const std::pair<const Token *, CTU::FileInfo::Value> &v : getUnsafeFunction(settings, &scope, argnr, isUnsafeUsage)) {
486493
const Token *tok = v.first;
487-
const MathLib::bigint val = v.second;
494+
const CTU::FileInfo::Value val = v.second;
488495
unsafeUsage.emplace_back(CTU::getFunctionId(tokenizer, function), argnr+1, tok->str(), CTU::FileInfo::Location(tokenizer,tok), val);
489496
}
490497
}
@@ -520,7 +527,7 @@ static bool findPath(const std::string &callId,
520527
continue;
521528
switch (invalidValue) {
522529
case CTU::FileInfo::InvalidValueType::null:
523-
if (functionCall->callValueType != ValueFlow::Value::ValueType::INT || functionCall->callArgValue != 0)
530+
if (functionCall->callValueType != ValueFlow::Value::ValueType::INT || functionCall->callArgValue.value != 0)
524531
continue;
525532
break;
526533
case CTU::FileInfo::InvalidValueType::uninit:
@@ -530,7 +537,7 @@ static bool findPath(const std::string &callId,
530537
case CTU::FileInfo::InvalidValueType::bufferOverflow:
531538
if (functionCall->callValueType != ValueFlow::Value::ValueType::BUFFER_SIZE)
532539
continue;
533-
if (unsafeValue < 0 || (unsafeValue >= functionCall->callArgValue && functionCall->callArgValue >= 0))
540+
if (unsafeValue < 0 || (unsafeValue >= functionCall->callArgValue.value && functionCall->callArgValue.value >= 0))
534541
break;
535542
continue;
536543
}
@@ -557,14 +564,20 @@ std::list<ErrorMessage::FileLocation> CTU::FileInfo::getErrorPath(InvalidValueTy
557564
const char info[],
558565
const FunctionCall ** const functionCallPtr,
559566
bool warning,
560-
int maxCtuDepth)
567+
int maxCtuDepth,
568+
std::uint8_t *unknownFunctionReturn)
561569
{
562-
std::list<ErrorMessage::FileLocation> locationList;
563-
564570
const CTU::FileInfo::CallBase *path[10] = {nullptr};
565571

566-
if (!findPath(unsafeUsage.myId, unsafeUsage.myArgNr, unsafeUsage.value, invalidValue, callsMap, path, 0, warning, maxCtuDepth))
567-
return locationList;
572+
if (!findPath(unsafeUsage.myId, unsafeUsage.myArgNr, unsafeUsage.value.value, invalidValue, callsMap, path, 0, warning, maxCtuDepth))
573+
return {};
574+
575+
if (unknownFunctionReturn && path[0] && dynamic_cast<const CTU::FileInfo::FunctionCall *>(path[0])) {
576+
const auto* v = dynamic_cast<const CTU::FileInfo::FunctionCall *>(path[0]);
577+
*unknownFunctionReturn = v->callArgValue.unknownFunctionReturn;
578+
}
579+
580+
std::list<ErrorMessage::FileLocation> locationList;
568581

569582
const std::string value1 = (invalidValue == InvalidValueType::null) ? "null" : "uninitialized";
570583

0 commit comments

Comments
 (0)