Skip to content

Commit 6dab97d

Browse files
author
Your Name
committed
Merge
2 parents 9933641 + bcd74c7 commit 6dab97d

48 files changed

Lines changed: 957 additions & 372 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
*.gcno
33
*.gch
44
*.o
5+
*.a
56
*.pyc
67
/cppcheck
78
/cppcheck.exe

AUTHORS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,7 @@ Samuel Degrande
369369
Samuel Poláček
370370
Sandeep Dutta
371371
Savvas Etairidis
372+
Sayed Kaif
372373
Scott Ehlert
373374
Scott Furry
374375
Seafarix Ltd.

lib/analyzer.h

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -153,9 +153,13 @@ struct Analyzer {
153153
struct Assume {
154154
enum Flags : std::uint8_t {
155155
None = 0,
156-
Quiet = (1 << 0),
157-
Absolute = (1 << 1),
158-
ContainerEmpty = (1 << 2),
156+
Quiet = (1u << 0),
157+
Absolute = (1u << 1),
158+
ContainerEmpty = (1u << 2),
159+
// The branch this condition guards is not traversed yet (a separate path walks it), so
160+
// the assume must not record the program state at the branch boundaries - they would be
161+
// premature. When unset, the branch has been traversed and control is leaving it.
162+
Pending = (1u << 3),
159163
};
160164
};
161165

lib/astutils.cpp

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2230,6 +2230,8 @@ bool isEscapeFunction(const Token* ftok, const Library& library)
22302230
{
22312231
if (!Token::Match(ftok, "%name% ("))
22322232
return false;
2233+
if (Token::Match(ftok, "exit|abort"))
2234+
return true;
22332235
const Function* function = ftok->function();
22342236
if (function) {
22352237
if (function->isEscapeFunction())
@@ -2334,14 +2336,14 @@ bool isWithinScope(const Token* tok, const Variable* var, ScopeType type)
23342336
return false;
23352337
}
23362338

2337-
bool isVariableChangedByFunctionCall(const Token *tok, int indirect, nonneg int varid, const Settings &settings, bool *inconclusive)
2339+
bool isVariableChangedByFunctionCall(const Token *tok, int indirect, nonneg int varid, const Library &library, bool *inconclusive)
23382340
{
23392341
if (!tok)
23402342
return false;
23412343
if (tok->varId() == varid)
2342-
return isVariableChangedByFunctionCall(tok, indirect, settings, inconclusive);
2343-
return isVariableChangedByFunctionCall(tok->astOperand1(), indirect, varid, settings, inconclusive) ||
2344-
isVariableChangedByFunctionCall(tok->astOperand2(), indirect, varid, settings, inconclusive);
2344+
return isVariableChangedByFunctionCall(tok, indirect, library, inconclusive);
2345+
return isVariableChangedByFunctionCall(tok->astOperand1(), indirect, varid, library, inconclusive) ||
2346+
isVariableChangedByFunctionCall(tok->astOperand2(), indirect, varid, library, inconclusive);
23452347
}
23462348

23472349
bool isScopeBracket(const Token* tok)
@@ -2522,7 +2524,7 @@ bool isMutableExpression(const Token* tok)
25222524
return true;
25232525
}
25242526

2525-
bool isVariableChangedByFunctionCall(const Token *tok, int indirect, const Settings &settings, bool *inconclusive)
2527+
bool isVariableChangedByFunctionCall(const Token *tok, int indirect, const Library &library, bool *inconclusive)
25262528
{
25272529
if (!tok)
25282530
return false;
@@ -2562,13 +2564,13 @@ bool isVariableChangedByFunctionCall(const Token *tok, int indirect, const Setti
25622564

25632565
if (!tok->function() && !tok->variable() && tok->isName()) {
25642566
// Check if direction (in, out, inout) is specified in the library configuration and use that
2565-
const Library::ArgumentChecks::Direction argDirection = settings.library.getArgDirection(tok, 1 + argnr, indirect);
2567+
const Library::ArgumentChecks::Direction argDirection = library.getArgDirection(tok, 1 + argnr, indirect);
25662568
if (argDirection == Library::ArgumentChecks::Direction::DIR_IN)
25672569
return false;
25682570
if (argDirection == Library::ArgumentChecks::Direction::DIR_OUT || argDirection == Library::ArgumentChecks::Direction::DIR_INOUT)
25692571
return true;
25702572

2571-
const bool requireNonNull = settings.library.isnullargbad(tok, 1 + argnr);
2573+
const bool requireNonNull = library.isnullargbad(tok, 1 + argnr);
25722574
if (Token::simpleMatch(tok->tokAt(-2), "std :: tie"))
25732575
return true;
25742576
// if the library says 0 is invalid
@@ -2796,7 +2798,7 @@ bool isVariableChanged(const Token *tok, int indirect, const Settings &settings,
27962798
if (indirect == 0 && astIsLHS(tok2) && Token::Match(ptok, ". %var%") && astIsPointer(ptok->next()))
27972799
pindirect = 1;
27982800
bool inconclusive = false;
2799-
bool isChanged = isVariableChangedByFunctionCall(ptok, pindirect, settings, &inconclusive);
2801+
bool isChanged = isVariableChangedByFunctionCall(ptok, pindirect, settings.library, &inconclusive);
28002802
isChanged |= inconclusive;
28012803
if (isChanged)
28022804
return true;
@@ -3421,7 +3423,7 @@ bool isConstVarExpression(const Token *tok, const std::function<bool(const Token
34213423
return false;
34223424
}
34233425

3424-
static ExprUsage getFunctionUsage(const Token* tok, int indirect, const Settings& settings)
3426+
static ExprUsage getFunctionUsage(const Token* tok, int indirect, const Library& library)
34253427
{
34263428
const bool addressOf = tok->astParent() && tok->astParent()->isUnaryOp("&");
34273429

@@ -3483,14 +3485,14 @@ static ExprUsage getFunctionUsage(const Token* tok, int indirect, const Settings
34833485
} else if (ftok->str() == "{") {
34843486
return indirect == 0 ? ExprUsage::Used : ExprUsage::Inconclusive;
34853487
} else {
3486-
const bool isnullbad = settings.library.isnullargbad(ftok, argnr + 1);
3488+
const bool isnullbad = library.isnullargbad(ftok, argnr + 1);
34873489
if (indirect == 0 && astIsPointer(tok) && !addressOf && isnullbad)
34883490
return ExprUsage::Used;
34893491
bool hasIndirect = false;
3490-
const bool isuninitbad = settings.library.isuninitargbad(ftok, argnr + 1, indirect, &hasIndirect);
3492+
const bool isuninitbad = library.isuninitargbad(ftok, argnr + 1, indirect, &hasIndirect);
34913493
if (isuninitbad && (!addressOf || isnullbad))
34923494
return ExprUsage::Used;
3493-
const Library::ArgumentChecks::Direction argDirection = settings.library.getArgDirection(ftok, argnr + 1, indirect);
3495+
const Library::ArgumentChecks::Direction argDirection = library.getArgDirection(ftok, argnr + 1, indirect);
34943496
if (argDirection == Library::ArgumentChecks::Direction::DIR_IN) // TODO: DIR_INOUT?
34953497
return ExprUsage::Used;
34963498
if (argDirection == Library::ArgumentChecks::Direction::DIR_OUT)
@@ -3560,7 +3562,7 @@ ExprUsage getExprUsage(const Token* tok, int indirect, const Settings& settings)
35603562
(astIsLHS(tok) || Token::simpleMatch(parent, "( )")))
35613563
return ExprUsage::Used;
35623564
}
3563-
return getFunctionUsage(tok, indirect, settings);
3565+
return getFunctionUsage(tok, indirect, settings.library);
35643566
}
35653567

35663568
static void getLHSVariablesRecursive(std::vector<const Variable*>& vars, const Token* tok)

lib/astutils.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -327,20 +327,20 @@ bool isMutableExpression(const Token* tok);
327327
*
328328
* @param tok ast tree
329329
* @param varid Variable Id
330-
* @param settings program settings
330+
* @param library library configurations
331331
* @param inconclusive pointer to output variable which indicates that the answer of the question is inconclusive
332332
*/
333-
bool isVariableChangedByFunctionCall(const Token *tok, int indirect, nonneg int varid, const Settings &settings, bool *inconclusive);
333+
bool isVariableChangedByFunctionCall(const Token *tok, int indirect, nonneg int varid, const Library &library, bool *inconclusive);
334334

335335
/** Is variable changed by function call?
336336
* In case the answer of the question is inconclusive, e.g. because the function declaration is not known
337337
* the return value is false and the output parameter inconclusive is set to true
338338
*
339-
* @param tok token of variable in function call
340-
* @param settings program settings
339+
* @param tok token of variable in function call
340+
* @param library library configurations
341341
* @param inconclusive pointer to output variable which indicates that the answer of the question is inconclusive
342342
*/
343-
CPPCHECKLIB bool isVariableChangedByFunctionCall(const Token *tok, int indirect, const Settings &settings, bool *inconclusive);
343+
CPPCHECKLIB bool isVariableChangedByFunctionCall(const Token *tok, int indirect, const Library &library, bool *inconclusive);
344344

345345
/** Is variable changed in block of code? */
346346
CPPCHECKLIB bool isVariableChanged(const Token *start, const Token *end, nonneg int exprid, bool globalvar, const Settings &settings, int depth = 20);

lib/checkautovariables.cpp

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -139,14 +139,14 @@ static bool isAutoVarArray(const Token *tok)
139139
return false;
140140
}
141141

142-
static bool isLocalContainerBuffer(const Token* tok, const Settings& settings)
142+
static bool isLocalContainerBuffer(const Token* tok, const Library& library)
143143
{
144144
if (!tok)
145145
return false;
146146

147147
// x+y
148148
if (tok->str() == "+")
149-
return isLocalContainerBuffer(tok->astOperand1(), settings) || isLocalContainerBuffer(tok->astOperand2(), settings);
149+
return isLocalContainerBuffer(tok->astOperand1(), library) || isLocalContainerBuffer(tok->astOperand2(), library);
150150

151151
if (tok->str() != "(" || !Token::simpleMatch(tok->astOperand1(), "."))
152152
return false;
@@ -157,7 +157,7 @@ static bool isLocalContainerBuffer(const Token* tok, const Settings& settings)
157157
if (!var || !var->isLocal() || var->isStatic())
158158
return false;
159159

160-
const Library::Container::Yield yield = astContainerYield(tok, settings.library);
160+
const Library::Container::Yield yield = astContainerYield(tok, library);
161161

162162
return yield == Library::Container::Yield::BUFFER || yield == Library::Container::Yield::BUFFER_NT;
163163
}
@@ -233,8 +233,8 @@ void CheckAutoVariablesImpl::assignFunctionArg()
233233
}
234234
}
235235

236-
static bool isAutoVariableRHS(const Token* tok, const Settings& settings) {
237-
return isAddressOfLocalVariable(tok) || isAutoVarArray(tok) || isLocalContainerBuffer(tok, settings);
236+
static bool isAutoVariableRHS(const Token* tok, const Library& library) {
237+
return isAddressOfLocalVariable(tok) || isAutoVarArray(tok) || isLocalContainerBuffer(tok, library);
238238
}
239239

240240
static bool hasOverloadedAssignment(const Token* tok, bool& inconclusive)
@@ -257,7 +257,7 @@ static bool hasOverloadedAssignment(const Token* tok, bool& inconclusive)
257257
return true;
258258
}
259259

260-
static bool isMemberAssignment(const Token* tok, const Token*& rhs, const Settings& settings)
260+
static bool isMemberAssignment(const Token* tok, const Token*& rhs, const Library& library)
261261
{
262262
const Token *endBracket = nullptr;
263263
if (!Token::Match(tok, "[;{}] %var% . %var%")) {
@@ -274,7 +274,7 @@ static bool isMemberAssignment(const Token* tok, const Token*& rhs, const Settin
274274
assign = assign->astParent();
275275
if (!Token::simpleMatch(assign, "="))
276276
return false;
277-
if (!isAutoVariableRHS(assign->astOperand2(), settings))
277+
if (!isAutoVariableRHS(assign->astOperand2(), library))
278278
return false;
279279
rhs = assign->astOperand2();
280280
return true;
@@ -295,23 +295,23 @@ void CheckAutoVariablesImpl::autoVariables()
295295
}
296296
// Critical assignment
297297
const Token* rhs{};
298-
if (Token::Match(tok, "[;{}] %var% =") && isRefPtrArg(tok->next()) && isAutoVariableRHS(tok->tokAt(2)->astOperand2(), mSettings)) {
298+
if (Token::Match(tok, "[;{}] %var% =") && isRefPtrArg(tok->next()) && isAutoVariableRHS(tok->tokAt(2)->astOperand2(), mSettings.library)) {
299299
checkAutoVariableAssignment(tok->next(), false);
300-
} else if (Token::Match(tok, "[;{}] * %var% =") && isPtrArg(tok->tokAt(2)) && isAutoVariableRHS(tok->tokAt(3)->astOperand2(), mSettings)) {
300+
} else if (Token::Match(tok, "[;{}] * %var% =") && isPtrArg(tok->tokAt(2)) && isAutoVariableRHS(tok->tokAt(3)->astOperand2(), mSettings.library)) {
301301
const Token* lhs = tok->tokAt(2);
302302
bool inconclusive = false;
303303
if (!hasOverloadedAssignment(lhs, inconclusive) || (printInconclusive && inconclusive))
304304
checkAutoVariableAssignment(tok->next(), inconclusive);
305305
tok = tok->tokAt(4);
306-
} else if (isMemberAssignment(tok, rhs, mSettings)) {
306+
} else if (isMemberAssignment(tok, rhs, mSettings.library)) {
307307
const Token* lhs = tok->tokAt(3);
308308
bool inconclusive = false;
309309
if (!hasOverloadedAssignment(lhs, inconclusive) || (printInconclusive && inconclusive))
310310
checkAutoVariableAssignment(tok->next(), inconclusive);
311311
tok = rhs;
312312
} else if (Token::Match(tok, "[;{}] %var% [") && Token::simpleMatch(tok->linkAt(2), "] =") &&
313313
(isPtrArg(tok->next()) || isArrayArg(tok->next(), mSettings)) &&
314-
isAutoVariableRHS(tok->linkAt(2)->next()->astOperand2(), mSettings)) {
314+
isAutoVariableRHS(tok->linkAt(2)->next()->astOperand2(), mSettings.library)) {
315315
errorAutoVariableAssignment(tok->next(), false);
316316
}
317317
// Invalid pointer deallocation

lib/checkbufferoverrun.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ static int getMinFormatStringOutputLength(const std::vector<const Token*> &param
133133
case 's':
134134
parameterLength = 0;
135135
if (inputArgNr < parameters.size())
136-
parameterLength = ValueFlow::valueFlowGetStrLength(parameters[inputArgNr], settings);
136+
parameterLength = ValueFlow::valueFlowGetStrLength(parameters[inputArgNr], settings.library);
137137

138138
handleNextParameter = true;
139139
break;
@@ -1088,8 +1088,12 @@ void CheckBufferOverrunImpl::objectIndex()
10881088
for (const ValueFlow::Value& v:values) {
10891089
if (v.lifetimeKind != ValueFlow::Value::LifetimeKind::Address && v.lifetimeKind != ValueFlow::Value::LifetimeKind::Object)
10901090
continue;
1091-
const Token* varTok = nextAfterAstRightmostLeaf(v.tokvalue->astParent());
1092-
varTok = varTok ? varTok->previous() : nullptr;
1091+
const Token* varTok = v.tokvalue;
1092+
if (Token::simpleMatch(varTok->astParent(), ".")) {
1093+
varTok = varTok->astParent();
1094+
while (Token::simpleMatch(varTok, "."))
1095+
varTok = varTok->astOperand2();
1096+
}
10931097
const Variable *var = varTok ? varTok->variable() : nullptr;
10941098
if (!var)
10951099
continue;

lib/checkclass.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1059,7 +1059,7 @@ void CheckClassImpl::initializeVarList(const Function &func, std::list<const Fun
10591059
tok2 = tok2->next();
10601060
if (tok2->str() == "&")
10611061
tok2 = tok2->next();
1062-
if (isVariableChangedByFunctionCall(tok2, tok2->strAt(-1) == "&", tok2->varId(), mSettings, nullptr))
1062+
if (isVariableChangedByFunctionCall(tok2, tok2->strAt(-1) == "&", tok2->varId(), mSettings.library, nullptr))
10631063
assignVar(usage, tok2->varId());
10641064
}
10651065
}

lib/checkio.cpp

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
// CVE ID used:
4949
static const CWE CWE119(119U); // Improper Restriction of Operations within the Bounds of a Memory Buffer
5050
static const CWE CWE398(398U); // Indicator of Poor Code Quality
51+
static const CWE CWE474(474U); // Use of Function with Inconsistent Implementations
5152
static const CWE CWE664(664U); // Improper Control of a Resource Through its Lifetime
5253
static const CWE CWE685(685U); // Function Call With Incorrect Number of Arguments
5354
static const CWE CWE686(686U); // Function Call With Incorrect Argument Type
@@ -111,6 +112,8 @@ namespace {
111112
nonneg int op_indent{};
112113
enum class AppendMode : std::uint8_t { UNKNOWN_AM, APPEND, APPEND_EX };
113114
AppendMode append_mode = AppendMode::UNKNOWN_AM;
115+
enum class ReadMode : std::uint8_t { READ_TEXT, READ_BIN };
116+
ReadMode read_mode = ReadMode::READ_BIN;
114117
std::string filename;
115118
explicit Filepointer(OpenMode mode_ = OpenMode::UNKNOWN_OM)
116119
: mode(mode_) {}
@@ -183,6 +186,7 @@ void CheckIOImpl::checkFileUsage()
183186
}
184187
} else if (Token::Match(tok, "%name% (") && tok->previous() && (!tok->previous()->isName() || Token::Match(tok->previous(), "return|throw"))) {
185188
std::string mode;
189+
bool isftell = false;
186190
const Token* fileTok = nullptr;
187191
const Token* fileNameTok = nullptr;
188192
Filepointer::Operation operation = Filepointer::Operation::NONE;
@@ -266,6 +270,9 @@ void CheckIOImpl::checkFileUsage()
266270
fileTok = tok->tokAt(2);
267271
if ((tok->str() == "ungetc" || tok->str() == "ungetwc") && fileTok)
268272
fileTok = fileTok->nextArgument();
273+
else if (tok->str() == "ftell") {
274+
isftell = true;
275+
}
269276
operation = Filepointer::Operation::UNIMPORTANT;
270277
} else if (!Token::Match(tok, "if|for|while|catch|switch") && !mSettings.library.isFunctionConst(tok->str(), true)) {
271278
const Token* const end2 = tok->linkAt(1);
@@ -321,10 +328,15 @@ void CheckIOImpl::checkFileUsage()
321328
f.append_mode = Filepointer::AppendMode::APPEND_EX;
322329
else
323330
f.append_mode = Filepointer::AppendMode::APPEND;
331+
}
332+
else if (mode.find('r') != std::string::npos &&
333+
mode.find('t') != std::string::npos) {
334+
f.read_mode = Filepointer::ReadMode::READ_TEXT;
324335
} else
325336
f.append_mode = Filepointer::AppendMode::UNKNOWN_AM;
326337
f.mode_indent = indent;
327338
break;
339+
328340
case Filepointer::Operation::POSITIONING:
329341
if (f.mode == OpenMode::CLOSED)
330342
useClosedFileError(tok);
@@ -357,6 +369,8 @@ void CheckIOImpl::checkFileUsage()
357369
case Filepointer::Operation::UNIMPORTANT:
358370
if (f.mode == OpenMode::CLOSED)
359371
useClosedFileError(tok);
372+
if (isftell && f.read_mode == Filepointer::ReadMode::READ_TEXT && printPortability)
373+
ftellFileError(tok);
360374
break;
361375
case Filepointer::Operation::UNKNOWN_OP:
362376
f.mode = OpenMode::UNKNOWN_OM;
@@ -424,6 +438,12 @@ void CheckIOImpl::seekOnAppendedFileError(const Token *tok)
424438
"seekOnAppendedFile", "Repositioning operation performed on a file opened in append mode has no effect.", CWE398, Certainty::normal);
425439
}
426440

441+
void CheckIOImpl::ftellFileError(const Token *tok)
442+
{
443+
reportError(tok, Severity::portability,
444+
"ftellTextModeFile", "ftell() result is unspecified when file is opened in mode \"t\"", CWE474, Certainty::normal);
445+
}
446+
427447
void CheckIOImpl::incompatibleFileOpenError(const Token *tok, const std::string &filename)
428448
{
429449
reportError(tok, Severity::warning,
@@ -855,7 +875,7 @@ void CheckIOImpl::checkFormatString(const Token * const tok,
855875
// Perform type checks
856876
ArgumentInfo argInfo(argListTok, mSettings, mTokenizer->isCPP());
857877

858-
if ((argInfo.typeToken && !argInfo.isLibraryType(mSettings)) || *i == ']') {
878+
if ((argInfo.typeToken && !argInfo.isLibraryType(mSettings.library)) || *i == ']') {
859879
if (scan) {
860880
std::string specifier;
861881
bool done = false;
@@ -1857,9 +1877,9 @@ bool CheckIOImpl::ArgumentInfo::isKnownType() const
18571877
return typeToken->isStandardType() || Token::Match(typeToken, "std :: string|wstring");
18581878
}
18591879

1860-
bool CheckIOImpl::ArgumentInfo::isLibraryType(const Settings &settings) const
1880+
bool CheckIOImpl::ArgumentInfo::isLibraryType(const Library &library) const
18611881
{
1862-
return typeToken && typeToken->isStandardType() && settings.library.podtype(typeToken->str());
1882+
return typeToken && typeToken->isStandardType() && library.podtype(typeToken->str());
18631883
}
18641884

18651885
void CheckIOImpl::wrongPrintfScanfArgumentsError(const Token* tok,

0 commit comments

Comments
 (0)