@@ -290,6 +290,44 @@ void CheckOther::suspiciousSemicolonError(const Token* tok)
290290 " Suspicious use of ; at the end of '" + (tok ? tok->str () : std::string ()) + " ' statement." , CWE398, Certainty::normal);
291291}
292292
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+ }
293331
294332// ---------------------------------------------------------------------------
295333// For C++ code, warn if C-style casts are used on pointer types
@@ -314,8 +352,11 @@ void CheckOther::warningOldStylePointerCast()
314352 tok = scope->bodyStart ;
315353 for (; tok && tok != scope->bodyEnd ; tok = tok->next ()) {
316354 // Old style pointer casting..
317- if (tok->str () != " (" )
355+ if (!tok->isCast () || tok->isBinaryOp ())
356+ continue ;
357+ if (isDangerousTypeConversion (tok))
318358 continue ;
359+ const Token* const errtok = tok;
319360 const Token* castTok = tok->next ();
320361 while (Token::Match (castTok, " const|volatile|class|struct|union|%type%|::" )) {
321362 castTok = castTok->next ();
@@ -332,7 +373,7 @@ void CheckOther::warningOldStylePointerCast()
332373 isRef = true ;
333374 castTok = castTok->next ();
334375 }
335- if ((!isPtr && !isRef) || !Token::Match (castTok, " ) (| %name%|%num%|% bool%|%char%|%str%|&" ))
376+ if ((!isPtr && !isRef) || !Token::Match (castTok, " ) (| %name%|%bool%|%char%|%str%|&" ))
336377 continue ;
337378
338379 if (Token::Match (tok->previous (), " %type%" ))
@@ -351,7 +392,7 @@ void CheckOther::warningOldStylePointerCast()
351392 continue ;
352393
353394 if (typeTok->tokType () == Token::eType || typeTok->tokType () == Token::eName)
354- cstyleCastError (tok , isPtr);
395+ cstyleCastError (errtok , isPtr);
355396 }
356397 }
357398}
@@ -367,6 +408,79 @@ void CheckOther::cstyleCastError(const Token *tok, bool isPtr)
367408 " which kind of cast is expected." , CWE398, Certainty::normal);
368409}
369410
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+
370484void CheckOther::suspiciousFloatingPointCast ()
371485{
372486 if (!mSettings ->severity .isEnabled (Severity::style) && !mSettings ->isPremiumEnabled (" suspiciousFloatingPointCast" ))
@@ -4393,6 +4507,8 @@ void CheckOther::runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger)
43934507
43944508 // Checks
43954509 checkOther.warningOldStylePointerCast ();
4510+ checkOther.warningDangerousTypeCast ();
4511+ checkOther.warningIntToPointerCast ();
43964512 checkOther.suspiciousFloatingPointCast ();
43974513 checkOther.invalidPointerCast ();
43984514 checkOther.checkCharVariable ();
@@ -4459,6 +4575,8 @@ void CheckOther::getErrorMessages(ErrorLogger *errorLogger, const Settings *sett
44594575 c.checkComparisonFunctionIsAlwaysTrueOrFalseError (nullptr , " isless" ," varName" ,false );
44604576 c.checkCastIntToCharAndBackError (nullptr , " func_name" );
44614577 c.cstyleCastError (nullptr );
4578+ c.dangerousTypeCastError (nullptr , true );
4579+ c.intToPointerCastError (nullptr , " decimal" );
44624580 c.suspiciousFloatingPointCastError (nullptr );
44634581 c.passedByValueError (nullptr , false );
44644582 c.constVariableError (nullptr , nullptr );
0 commit comments