diff --git a/Makefile b/Makefile index ff990d696ae..8bfa89287a7 100644 --- a/Makefile +++ b/Makefile @@ -572,7 +572,7 @@ $(libcppdir)/checkstl.o: lib/checkstl.cpp lib/addoninfo.h lib/astutils.h lib/che $(libcppdir)/checkstring.o: lib/checkstring.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkstring.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkstring.cpp -$(libcppdir)/checktype.o: lib/checktype.cpp lib/addoninfo.h lib/check.h lib/checktype.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/sourcelocation.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/vfvalue.h +$(libcppdir)/checktype.o: lib/checktype.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checktype.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checktype.cpp $(libcppdir)/checkuninitvar.o: lib/checkuninitvar.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checknullpointer.h lib/checkuninitvar.h lib/color.h lib/config.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h diff --git a/lib/astutils.cpp b/lib/astutils.cpp index 4fae5b39b79..a762d500505 100644 --- a/lib/astutils.cpp +++ b/lib/astutils.cpp @@ -3725,3 +3725,39 @@ bool isExhaustiveSwitch(const Token *startbrace) return false; } + +bool isUnreachableOperand(const Token *tok) +{ + for (;;) + { + const Token *parent = tok->astParent(); + if (!parent) + break; + + if (parent->isBinaryOp()) { + const bool left = tok == parent->astOperand1(); + const Token *sibling = left ? parent->astOperand2() : parent->astOperand1(); + + // logical and + if (Token::simpleMatch(parent, "&&") && !left && sibling->hasKnownIntValue() + && !sibling->getKnownIntValue()) + return true; + + // logical or + if (Token::simpleMatch(parent, "||") && !left && sibling->hasKnownIntValue() + && sibling->getKnownIntValue()) + return true; + + // ternary + if (Token::simpleMatch(parent, ":") && Token::simpleMatch(parent->astParent(), "?")) { + const Token *condTok = parent->astParent()->astOperand1(); + if (condTok->hasKnownIntValue() && static_cast(condTok->getKnownIntValue()) != left) + return true; + } + } + + tok = parent; + } + + return false; +} diff --git a/lib/astutils.h b/lib/astutils.h index 5767786445a..f5ffc67da1b 100644 --- a/lib/astutils.h +++ b/lib/astutils.h @@ -448,4 +448,6 @@ bool isUnevaluated(const Token *tok); bool isExhaustiveSwitch(const Token *startbrace); +bool isUnreachableOperand(const Token *tok); + #endif // astutilsH diff --git a/lib/checktype.cpp b/lib/checktype.cpp index 9f3e0993868..5fc65b9a7c8 100644 --- a/lib/checktype.cpp +++ b/lib/checktype.cpp @@ -20,6 +20,7 @@ //--------------------------------------------------------------------------- #include "checktype.h" +#include "astutils.h" #include "errortypes.h" #include "mathlib.h" #include "platform.h" @@ -437,6 +438,8 @@ void CheckType::checkFloatToIntegerOverflow() // Explicit cast if (Token::Match(tok, "( %name%") && tok->astOperand1() && !tok->astOperand2()) { + if (isUnreachableOperand(tok)) + continue; vtint = tok->valueType(); vtfloat = tok->astOperand1()->valueType(); checkFloatToIntegerOverflow(tok, vtint, vtfloat, tok->astOperand1()->values()); @@ -444,12 +447,16 @@ void CheckType::checkFloatToIntegerOverflow() // Assignment else if (tok->str() == "=" && tok->astOperand1() && tok->astOperand2()) { + if (isUnreachableOperand(tok)) + continue; vtint = tok->astOperand1()->valueType(); vtfloat = tok->astOperand2()->valueType(); checkFloatToIntegerOverflow(tok, vtint, vtfloat, tok->astOperand2()->values()); } else if (tok->str() == "return" && tok->astOperand1() && tok->astOperand1()->valueType() && tok->astOperand1()->valueType()->isFloat()) { + if (isUnreachableOperand(tok)) + continue; const Scope *scope = tok->scope(); while (scope && scope->type != Scope::ScopeType::eLambda && scope->type != Scope::ScopeType::eFunction) scope = scope->nestedIn; diff --git a/oss-fuzz/Makefile b/oss-fuzz/Makefile index 65ab189ffce..a9e1b8b7e6a 100644 --- a/oss-fuzz/Makefile +++ b/oss-fuzz/Makefile @@ -259,7 +259,7 @@ $(libcppdir)/checkstl.o: ../lib/checkstl.cpp ../lib/addoninfo.h ../lib/astutils. $(libcppdir)/checkstring.o: ../lib/checkstring.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkstring.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/suppressions.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkstring.cpp -$(libcppdir)/checktype.o: ../lib/checktype.cpp ../lib/addoninfo.h ../lib/check.h ../lib/checktype.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/sourcelocation.h ../lib/standards.h ../lib/suppressions.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/valueflow.h ../lib/vfvalue.h +$(libcppdir)/checktype.o: ../lib/checktype.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checktype.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/suppressions.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/valueflow.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checktype.cpp $(libcppdir)/checkuninitvar.o: ../lib/checkuninitvar.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checknullpointer.h ../lib/checkuninitvar.h ../lib/color.h ../lib/config.h ../lib/ctu.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/suppressions.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h diff --git a/test/testtype.cpp b/test/testtype.cpp index 8d3f4acb421..f40cd4c0652 100644 --- a/test/testtype.cpp +++ b/test/testtype.cpp @@ -495,6 +495,44 @@ class TestType : public TestFixture { " return 1234.5;\n" "}", settingsDefault); ASSERT_EQUALS("[test.cpp:2]: (error) Undefined behaviour: float () to integer conversion overflow.\n", removeFloat(errout_str())); + + checkP("#define TEST(b, f) b ? 5000 : (unsigned short)f\n" // #11685 + "void f()\n" + "{\n" + " unsigned short u = TEST(true, 75000.0);\n" + "}\n", settingsDefault); + ASSERT_EQUALS("", errout_str()); + + checkP("#define TEST(b, f) b ? 5000 : (unsigned short)f\n" + "void f()\n" + "{\n" + " unsigned short u = TEST(false, 75000.0);\n" + "}\n", settingsDefault); + ASSERT_EQUALS("[test.cpp:4]: (error) Undefined behaviour: float () to integer conversion overflow.\n", removeFloat(errout_str())); + + check( "bool f(unsigned short x);\n" + "bool g() {\n" + " return false && f((unsigned short)75000.0);\n" + "}\n", settingsDefault); + ASSERT_EQUALS("", errout_str()); + + check( "bool f(unsigned short x);\n" + "bool g() {\n" + " return true && f((unsigned short)75000.0);\n" + "}\n", settingsDefault); + ASSERT_EQUALS("[test.cpp:3]: (error) Undefined behaviour: float () to integer conversion overflow.\n", removeFloat(errout_str())); + + check( "bool f(unsigned short x);\n" + "bool g() {\n" + " return true || f((unsigned short)75000.0);\n" + "}\n", settingsDefault); + ASSERT_EQUALS("", errout_str()); + + check( "bool f(unsigned short x);\n" + "bool g() {\n" + " return false || f((unsigned short)75000.0);\n" + "}\n", settingsDefault); + ASSERT_EQUALS("[test.cpp:3]: (error) Undefined behaviour: float () to integer conversion overflow.\n", removeFloat(errout_str())); } void integerOverflow() { // #11794