diff --git a/Makefile b/Makefile index fe31997752f..60851b97a3f 100644 --- a/Makefile +++ b/Makefile @@ -621,7 +621,7 @@ test/testbool.o: test/testbool.cpp lib/astutils.h lib/check.h lib/checkbool.h li test/testboost.o: test/testboost.cpp lib/astutils.h lib/check.h lib/checkboost.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h test/testsuite.h $(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o test/testboost.o test/testboost.cpp -test/testbufferoverrun.o: test/testbufferoverrun.cpp externals/tinyxml2/tinyxml2.h lib/astutils.h lib/check.h lib/checkbufferoverrun.h lib/color.h lib/config.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h test/testsuite.h +test/testbufferoverrun.o: test/testbufferoverrun.cpp externals/simplecpp/simplecpp.h externals/tinyxml2/tinyxml2.h lib/astutils.h lib/check.h lib/checkbufferoverrun.h lib/color.h lib/config.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/preprocessor.h lib/settings.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h test/testsuite.h $(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o test/testbufferoverrun.o test/testbufferoverrun.cpp test/testbughuntingchecks.o: test/testbughuntingchecks.cpp lib/astutils.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/exprengine.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h test/testsuite.h diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 18718f1e97f..4642bb392f8 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -5224,8 +5224,12 @@ struct ConditionHandler { if (!top) return; - if (top->previous()->isExpandedMacro()) - return; + if (top->previous()->isExpandedMacro()) { + for (std::list* values : {&thenValues, &elseValues}) { + for (ValueFlow::Value& v : *values) + v.macro = true; + } + } if (!Token::Match(top->previous(), "if|while|for (")) return; @@ -7545,6 +7549,7 @@ ValueFlow::Value::Value(const Token* c, long long val, Bound b) varId(0), safe(false), conditional(false), + macro(false), defaultArg(false), indirect(0), path(0), diff --git a/lib/valueflow.h b/lib/valueflow.h index b6a1b1c1170..7a9a384de30 100644 --- a/lib/valueflow.h +++ b/lib/valueflow.h @@ -98,6 +98,7 @@ namespace ValueFlow { varId(0U), safe(false), conditional(false), + macro(false), defaultArg(false), indirect(0), path(0), @@ -346,6 +347,9 @@ namespace ValueFlow { /** Conditional value */ bool conditional; + /** Value is is from an expanded macro */ + bool macro; + /** Is this value passed as default parameter to the function? */ bool defaultArg; diff --git a/test/testbufferoverrun.cpp b/test/testbufferoverrun.cpp index d386e876dc8..a1473643325 100644 --- a/test/testbufferoverrun.cpp +++ b/test/testbufferoverrun.cpp @@ -22,14 +22,15 @@ #include "config.h" #include "ctu.h" #include "library.h" +#include "preprocessor.h" #include "settings.h" #include "testsuite.h" #include "tokenize.h" -#include #include +#include #include - +#include class TestBufferOverrun : public TestFixture { public: @@ -67,6 +68,45 @@ class TestBufferOverrun : public TestFixture { checkBufferOverrun.runChecks(&tokenizer, &settings, this); } + void checkP(const char code[], const char* filename = "test.cpp") + { + // Clear the error buffer.. + errout.str(""); + + Settings* settings = &settings0; + settings->severity.enable(Severity::style); + settings->severity.enable(Severity::warning); + settings->severity.enable(Severity::portability); + settings->severity.enable(Severity::performance); + settings->standards.c = Standards::CLatest; + settings->standards.cpp = Standards::CPPLatest; + settings->certainty.enable(Certainty::inconclusive); + settings->certainty.disable(Certainty::experimental); + + // Raw tokens.. + std::vector files(1, filename); + std::istringstream istr(code); + const simplecpp::TokenList tokens1(istr, files, files[0]); + + // Preprocess.. + simplecpp::TokenList tokens2(files); + std::map filedata; + simplecpp::preprocess(tokens2, tokens1, files, filedata, simplecpp::DUI()); + + Preprocessor preprocessor(*settings, nullptr); + preprocessor.setDirectives(tokens1); + + // Tokenizer.. + Tokenizer tokenizer(settings, this); + tokenizer.createTokens(std::move(tokens2)); + tokenizer.simplifyTokens1(""); + tokenizer.setPreprocessor(&preprocessor); + + // Check for buffer overruns.. + CheckBufferOverrun checkBufferOverrun(&tokenizer, settings, this); + checkBufferOverrun.runChecks(&tokenizer, settings, this); + } + void run() OVERRIDE { LOAD_LIB_2(settings0.library, "std.cfg"); @@ -136,6 +176,7 @@ class TestBufferOverrun : public TestFixture { TEST_CASE(array_index_57); // #10023 TEST_CASE(array_index_58); // #7524 TEST_CASE(array_index_59); // #10413 + TEST_CASE(array_index_60); // #10617, #9824 TEST_CASE(array_index_multidim); TEST_CASE(array_index_switch_in_for); TEST_CASE(array_index_for_in_for); // FP: #2634 @@ -1665,6 +1706,29 @@ class TestBufferOverrun : public TestFixture { ASSERT_EQUALS("", errout.str()); } + void array_index_60() + { + checkP("#define CKR(B) if (!(B)) { return -1; }\n" + "int f(int i) {\n" + " const int A[3] = {};\n" + " CKR(i < 3);\n" + " if (i > 0)\n" + " i = A[i];\n" + " return i;\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); + + checkP("#define ASSERT(expression, action) if (expression) {action;}\n" + "int array[5];\n" + "void func (int index) {\n" + " ASSERT(index > 5, return);\n" + " array[index]++;\n" + "}\n"); + ASSERT_EQUALS( + "[test.cpp:4] -> [test.cpp:5]: (warning) Either the condition 'index>5' is redundant or the array 'array[5]' is accessed at index 5, which is out of bounds.\n", + errout.str()); + } + void array_index_multidim() { check("void f()\n" "{\n"