@@ -3265,19 +3265,82 @@ void CheckOther::unusedLabelError(const Token* tok, bool inSwitch, bool hasIfdef
3265
3265
Certainty::normal );
3266
3266
}
3267
3267
3268
+ static bool checkEvaluationOrderC (const Token * tok, const Token * tok2, const Token * parent, const Settings & settings, bool & selfAssignmentError)
3269
+ {
3270
+ // self assignment..
3271
+ if (tok2 == tok && tok->str () == " =" && parent->str () == " =" && isSameExpression (false , tok->astOperand1 (), parent->astOperand1 (), settings.library , true , false )) {
3272
+ if (settings.severity .isEnabled (Severity::warning) && isSameExpression (true , tok->astOperand1 (), parent->astOperand1 (), settings.library , true , false ))
3273
+ selfAssignmentError = true ;
3274
+ return false ;
3275
+ }
3276
+ // Is expression used?
3277
+ bool foundError = false ;
3278
+ visitAstNodes ((parent->astOperand1 () != tok2) ? parent->astOperand1 () : parent->astOperand2 (), [&](const Token *tok3) {
3279
+ if (tok3->str () == " &" && !tok3->astOperand2 ())
3280
+ return ChildrenToVisit::none; // don't handle address-of for now
3281
+ if (tok3->str () == " (" && Token::simpleMatch (tok3->previous (), " sizeof" ))
3282
+ return ChildrenToVisit::none; // don't care about sizeof usage
3283
+ if (isSameExpression (false , tok->astOperand1 (), tok3, settings.library , true , false ))
3284
+ foundError = true ;
3285
+ return foundError ? ChildrenToVisit::done : ChildrenToVisit::op1_and_op2;
3286
+ });
3268
3287
3269
- void CheckOther::checkEvaluationOrder ()
3288
+ return foundError;
3289
+ }
3290
+
3291
+ static bool checkEvaluationOrderCpp11 (const Token * tok, const Token * tok2, const Token * parent, const Settings & settings)
3270
3292
{
3271
- // This checker is not written according to C++11 sequencing rules
3272
- if (mTokenizer ->isCPP () && mSettings ->standards .cpp >= Standards::CPP11)
3273
- return ;
3293
+ if (tok->isAssignmentOp ()) // TODO check assignment
3294
+ return false ;
3295
+ if (tok->previous () == tok->astOperand1 () && parent->isArithmeticalOp () && parent->isBinaryOp ()) {
3296
+ if (parent->astParent () && parent->astParent ()->isAssignmentOp () && isSameExpression (false , tok->astOperand1 (), parent->astParent ()->astOperand1 (), settings.library , true , false ))
3297
+ return true ;
3298
+ }
3299
+ bool foundUndefined{false };
3300
+ visitAstNodes ((parent->astOperand1 () != tok2) ? parent->astOperand1 () : parent->astOperand2 (), [&](const Token *tok3) {
3301
+ if (tok3->str () == " &" && !tok3->astOperand2 ())
3302
+ return ChildrenToVisit::none; // don't handle address-of for now
3303
+ if (tok3->str () == " (" && Token::simpleMatch (tok3->previous (), " sizeof" ))
3304
+ return ChildrenToVisit::none; // don't care about sizeof usage
3305
+ if (isSameExpression (false , tok->astOperand1 (), tok3, settings.library , true , false ))
3306
+ foundUndefined = true ;
3307
+ return foundUndefined ? ChildrenToVisit::done : ChildrenToVisit::op1_and_op2;
3308
+ });
3274
3309
3275
- logChecker (" CheckOther::checkEvaluationOrder" ); // C/C++03
3310
+ return foundUndefined;
3311
+ }
3276
3312
3313
+ static bool checkEvaluationOrderCpp17 (const Token * tok, const Token * tok2, const Token * parent, const Settings & settings, bool & foundUnspecified)
3314
+ {
3315
+ if (tok->isAssignmentOp ())
3316
+ return false ;
3317
+ bool foundUndefined{false };
3318
+ visitAstNodes ((parent->astOperand1 () != tok2) ? parent->astOperand1 () : parent->astOperand2 (), [&](const Token *tok3) {
3319
+ if (tok3->str () == " &" && !tok3->astOperand2 ())
3320
+ return ChildrenToVisit::none; // don't handle address-of for now
3321
+ if (tok3->str () == " (" && Token::simpleMatch (tok3->previous (), " sizeof" ))
3322
+ return ChildrenToVisit::none; // don't care about sizeof usage
3323
+ if (isSameExpression (false , tok->astOperand1 (), tok3, settings.library , true , false ) && parent->isArithmeticalOp () && parent->isBinaryOp ())
3324
+ foundUndefined = true ;
3325
+ if (tok3->tokType () == Token::eIncDecOp && isSameExpression (false , tok->astOperand1 (), tok3->astOperand1 (), settings.library , true , false )) {
3326
+ if (parent->isArithmeticalOp () && parent->isBinaryOp ())
3327
+ foundUndefined = true ;
3328
+ else
3329
+ foundUnspecified = true ;
3330
+ }
3331
+ return (foundUndefined || foundUnspecified) ? ChildrenToVisit::done : ChildrenToVisit::op1_and_op2;
3332
+ });
3333
+
3334
+ return foundUndefined || foundUnspecified;
3335
+ }
3336
+
3337
+ void CheckOther::checkEvaluationOrder ()
3338
+ {
3339
+ logChecker (" CheckOther::checkEvaluationOrder" );
3277
3340
const SymbolDatabase *symbolDatabase = mTokenizer ->getSymbolDatabase ();
3278
3341
for (const Scope * functionScope : symbolDatabase->functionScopes ) {
3279
3342
for (const Token* tok = functionScope->bodyStart ; tok != functionScope->bodyEnd ; tok = tok->next ()) {
3280
- if (tok->tokType () != Token::eIncDecOp && !tok->isAssignmentOp ())
3343
+ if (! tok->isIncDecOp () && !tok->isAssignmentOp ())
3281
3344
continue ;
3282
3345
if (!tok->astOperand1 ())
3283
3346
continue ;
@@ -3308,43 +3371,36 @@ void CheckOther::checkEvaluationOrder()
3308
3371
if (parent->str () == " (" && parent->astOperand2 ())
3309
3372
break ;
3310
3373
3311
- // self assignment..
3312
- if (tok2 == tok &&
3313
- tok->str () == " =" &&
3314
- parent->str () == " =" &&
3315
- isSameExpression (false , tok->astOperand1 (), parent->astOperand1 (), mSettings ->library , true , false )) {
3316
- if (mSettings ->severity .isEnabled (Severity::warning) &&
3317
- isSameExpression (true , tok->astOperand1 (), parent->astOperand1 (), mSettings ->library , true , false ))
3318
- selfAssignmentError (parent, tok->astOperand1 ()->expressionString ());
3319
- break ;
3374
+ bool foundError{false }, foundUnspecified{false }, bSelfAssignmentError{false };
3375
+ if (mTokenizer ->isCPP () && mSettings ->standards .cpp >= Standards::CPP11) {
3376
+ if (mSettings ->standards .cpp >= Standards::CPP17)
3377
+ foundError = checkEvaluationOrderCpp17 (tok, tok2, parent, *mSettings , foundUnspecified);
3378
+ else
3379
+ foundError = checkEvaluationOrderCpp11 (tok, tok2, parent, *mSettings );
3320
3380
}
3321
-
3322
- // Is expression used?
3323
- bool foundError = false ;
3324
- visitAstNodes ((parent->astOperand1 () != tok2) ? parent->astOperand1 () : parent->astOperand2 (),
3325
- [&](const Token *tok3) {
3326
- if (tok3->str () == " &" && !tok3->astOperand2 ())
3327
- return ChildrenToVisit::none; // don't handle address-of for now
3328
- if (tok3->str () == " (" && Token::simpleMatch (tok3->previous (), " sizeof" ))
3329
- return ChildrenToVisit::none; // don't care about sizeof usage
3330
- if (isSameExpression (false , tok->astOperand1 (), tok3, mSettings ->library , true , false ))
3331
- foundError = true ;
3332
- return foundError ? ChildrenToVisit::done : ChildrenToVisit::op1_and_op2;
3333
- });
3381
+ else
3382
+ foundError = checkEvaluationOrderC (tok, tok2, parent, *mSettings , bSelfAssignmentError);
3334
3383
3335
3384
if (foundError) {
3336
- unknownEvaluationOrder (parent);
3385
+ unknownEvaluationOrder (parent, foundUnspecified);
3386
+ break ;
3387
+ }
3388
+ if (bSelfAssignmentError) {
3389
+ selfAssignmentError (parent, tok->astOperand1 ()->expressionString ());
3337
3390
break ;
3338
3391
}
3339
3392
}
3340
3393
}
3341
3394
}
3342
3395
}
3343
3396
3344
- void CheckOther::unknownEvaluationOrder (const Token* tok)
3397
+ void CheckOther::unknownEvaluationOrder (const Token* tok, bool isUnspecifiedBehavior )
3345
3398
{
3346
- reportError (tok, Severity::error, " unknownEvaluationOrder" ,
3347
- " Expression '" + (tok ? tok->expressionString () : std::string (" x = x++;" )) + " ' depends on order of evaluation of side effects" , CWE768, Certainty::normal );
3399
+ isUnspecifiedBehavior ?
3400
+ reportError (tok, Severity::portability, " unknownEvaluationOrder" ,
3401
+ " Expression '" + (tok ? tok->expressionString () : std::string (" x++, x++" )) + " ' depends on order of evaluation of side effects. Behavior is Unspecified according to c++17" , CWE768, Certainty::normal )
3402
+ : reportError (tok, Severity::error, " unknownEvaluationOrder" ,
3403
+ " Expression '" + (tok ? tok->expressionString () : std::string (" x = x++;" )) + " ' depends on order of evaluation of side effects" , CWE768, Certainty::normal );
3348
3404
}
3349
3405
3350
3406
void CheckOther::checkAccessOfMovedVariable ()
0 commit comments