@@ -290,6 +290,44 @@ void CheckOther::suspiciousSemicolonError(const Token* tok)
290
290
" Suspicious use of ; at the end of '" + (tok ? tok->str () : std::string ()) + " ' statement." , CWE398, Certainty::normal);
291
291
}
292
292
293
+ /* * @brief would it make sense to use dynamic_cast instead of C style cast? */
294
+ static bool isDangerousTypeConversion (const Token* const tok)
295
+ {
296
+ const Token* from = tok->astOperand1 ();
297
+ if (!from)
298
+ return false ;
299
+ if (!tok->valueType () || !from->valueType ())
300
+ return false ;
301
+ if (tok->valueType ()->typeScope != nullptr &&
302
+ tok->valueType ()->typeScope == from->valueType ()->typeScope )
303
+ return false ;
304
+ if (tok->valueType ()->type == from->valueType ()->type &&
305
+ tok->valueType ()->isPrimitive ())
306
+ return false ;
307
+ // cast from derived object to base object is safe..
308
+ if (tok->valueType ()->typeScope && from->valueType ()->typeScope ) {
309
+ const Type* fromType = from->valueType ()->typeScope ->definedType ;
310
+ const Type* toType = tok->valueType ()->typeScope ->definedType ;
311
+ if (fromType && toType && fromType->isDerivedFrom (toType->name ()))
312
+ return false ;
313
+ }
314
+ const bool refcast = (tok->valueType ()->reference != Reference::None);
315
+ if (!refcast && tok->valueType ()->pointer == 0 )
316
+ return false ;
317
+ if (!refcast && from->valueType ()->pointer == 0 )
318
+ return false ;
319
+
320
+ if (tok->valueType ()->type == ValueType::Type::VOID || from->valueType ()->type == ValueType::Type::VOID)
321
+ return false ;
322
+ if (tok->valueType ()->pointer == 0 && tok->valueType ()->isIntegral ())
323
+ // ok: (uintptr_t)ptr;
324
+ return false ;
325
+ if (from->valueType ()->pointer == 0 && from->valueType ()->isIntegral ())
326
+ // ok: (int *)addr;
327
+ return false ;
328
+
329
+ return true ;
330
+ }
293
331
294
332
// ---------------------------------------------------------------------------
295
333
// For C++ code, warn if C-style casts are used on pointer types
@@ -314,8 +352,11 @@ void CheckOther::warningOldStylePointerCast()
314
352
tok = scope->bodyStart ;
315
353
for (; tok && tok != scope->bodyEnd ; tok = tok->next ()) {
316
354
// Old style pointer casting..
317
- if (tok->str () != " (" )
355
+ if (!tok->isCast () || tok->isBinaryOp ())
356
+ continue ;
357
+ if (isDangerousTypeConversion (tok))
318
358
continue ;
359
+ const Token* const errtok = tok;
319
360
const Token* castTok = tok->next ();
320
361
while (Token::Match (castTok, " const|volatile|class|struct|union|%type%|::" )) {
321
362
castTok = castTok->next ();
@@ -332,7 +373,7 @@ void CheckOther::warningOldStylePointerCast()
332
373
isRef = true ;
333
374
castTok = castTok->next ();
334
375
}
335
- if ((!isPtr && !isRef) || !Token::Match (castTok, " ) (| %name%|%num%|% bool%|%char%|%str%|&" ))
376
+ if ((!isPtr && !isRef) || !Token::Match (castTok, " ) (| %name%|%bool%|%char%|%str%|&" ))
336
377
continue ;
337
378
338
379
if (Token::Match (tok->previous (), " %type%" ))
@@ -351,7 +392,7 @@ void CheckOther::warningOldStylePointerCast()
351
392
continue ;
352
393
353
394
if (typeTok->tokType () == Token::eType || typeTok->tokType () == Token::eName)
354
- cstyleCastError (tok , isPtr);
395
+ cstyleCastError (errtok , isPtr);
355
396
}
356
397
}
357
398
}
@@ -367,6 +408,79 @@ void CheckOther::cstyleCastError(const Token *tok, bool isPtr)
367
408
" which kind of cast is expected." , CWE398, Certainty::normal);
368
409
}
369
410
411
+ void CheckOther::warningDangerousTypeCast ()
412
+ {
413
+ // Only valid on C++ code
414
+ if (!mTokenizer ->isCPP ())
415
+ return ;
416
+ if (!mSettings ->severity .isEnabled (Severity::warning) && !mSettings ->isPremiumEnabled (" cstyleCast" ))
417
+ return ;
418
+
419
+ logChecker (" CheckOther::warningDangerousTypeCast" ); // warning,c++
420
+
421
+ const SymbolDatabase *symbolDatabase = mTokenizer ->getSymbolDatabase ();
422
+ for (const Scope * scope : symbolDatabase->functionScopes ) {
423
+ const Token* tok;
424
+ if (scope->function && scope->function ->isConstructor ())
425
+ tok = scope->classDef ;
426
+ else
427
+ tok = scope->bodyStart ;
428
+ for (; tok && tok != scope->bodyEnd ; tok = tok->next ()) {
429
+ // Old style pointer casting..
430
+ if (!tok->isCast () || tok->isBinaryOp ())
431
+ continue ;
432
+
433
+ if (isDangerousTypeConversion (tok))
434
+ dangerousTypeCastError (tok, tok->valueType ()->pointer > 0 );
435
+ }
436
+ }
437
+ }
438
+
439
+ void CheckOther::dangerousTypeCastError (const Token *tok, bool isPtr)
440
+ {
441
+ // const std::string type = isPtr ? "pointer" : "reference";
442
+ (void )isPtr;
443
+ reportError (tok, Severity::warning, " dangerousTypeCast" ,
444
+ " Potentially invalid type conversion in old-style C cast, clarify/fix with C++ cast" ,
445
+ CWE398, Certainty::normal);
446
+ }
447
+
448
+ void CheckOther::warningIntToPointerCast ()
449
+ {
450
+ if (!mSettings ->severity .isEnabled (Severity::portability) && !mSettings ->isPremiumEnabled (" cstyleCast" ))
451
+ return ;
452
+
453
+ logChecker (" CheckOther::warningIntToPointerCast" ); // portability
454
+
455
+ for (const Token* tok = mTokenizer ->tokens (); tok; tok = tok->next ()) {
456
+ // pointer casting..
457
+ if (!tok->isCast ())
458
+ continue ;
459
+ const Token* from = tok->astOperand2 () ? tok->astOperand2 () : tok->astOperand1 ();
460
+ if (!from || !from->isNumber ())
461
+ continue ;
462
+ if (!tok->valueType () || tok->valueType ()->pointer == 0 )
463
+ continue ;
464
+ if (!MathLib::isIntHex (from->str ()) && from->getKnownIntValue () != 0 ) {
465
+ std::string format;
466
+ if (MathLib::isDec (from->str ()))
467
+ format = " decimal" ;
468
+ else if (MathLib::isOct (from->str ()))
469
+ format = " octal" ;
470
+ else
471
+ continue ;
472
+ intToPointerCastError (tok, format);
473
+ }
474
+ }
475
+ }
476
+
477
+ void CheckOther::intToPointerCastError (const Token *tok, const std::string& format)
478
+ {
479
+ reportError (tok, Severity::portability, " intToPointerCast" ,
480
+ " Casting non-zero " + format + " integer literal to pointer." ,
481
+ CWE398, Certainty::normal);
482
+ }
483
+
370
484
void CheckOther::suspiciousFloatingPointCast ()
371
485
{
372
486
if (!mSettings ->severity .isEnabled (Severity::style) && !mSettings ->isPremiumEnabled (" suspiciousFloatingPointCast" ))
@@ -4393,6 +4507,8 @@ void CheckOther::runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger)
4393
4507
4394
4508
// Checks
4395
4509
checkOther.warningOldStylePointerCast ();
4510
+ checkOther.warningDangerousTypeCast ();
4511
+ checkOther.warningIntToPointerCast ();
4396
4512
checkOther.suspiciousFloatingPointCast ();
4397
4513
checkOther.invalidPointerCast ();
4398
4514
checkOther.checkCharVariable ();
@@ -4459,6 +4575,8 @@ void CheckOther::getErrorMessages(ErrorLogger *errorLogger, const Settings *sett
4459
4575
c.checkComparisonFunctionIsAlwaysTrueOrFalseError (nullptr , " isless" ," varName" ,false );
4460
4576
c.checkCastIntToCharAndBackError (nullptr , " func_name" );
4461
4577
c.cstyleCastError (nullptr );
4578
+ c.dangerousTypeCastError (nullptr , true );
4579
+ c.intToPointerCastError (nullptr , " decimal" );
4462
4580
c.suspiciousFloatingPointCastError (nullptr );
4463
4581
c.passedByValueError (nullptr , false );
4464
4582
c.constVariableError (nullptr , nullptr );
0 commit comments