diff --git a/Makefile b/Makefile
index 5d53dfe38..ca87d358d 100644
--- a/Makefile
+++ b/Makefile
@@ -201,6 +201,7 @@ LIBOBJ = $(libcppdir)/analyzerinfo.o \
$(libcppdir)/platform.o \
$(libcppdir)/preprocessor.o \
$(libcppdir)/programmemory.o \
+ $(libcppdir)/reverseanalyzer.o \
$(libcppdir)/settings.o \
$(libcppdir)/suppressions.o \
$(libcppdir)/symboldatabase.o \
@@ -508,7 +509,7 @@ $(libcppdir)/errortypes.o: lib/errortypes.cpp lib/config.h lib/errortypes.h
$(libcppdir)/exprengine.o: lib/exprengine.cpp lib/astutils.h lib/bughuntingchecks.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/symboldatabase.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o $(libcppdir)/exprengine.o $(libcppdir)/exprengine.cpp
-$(libcppdir)/forwardanalyzer.o: lib/forwardanalyzer.cpp lib/astutils.h lib/config.h lib/errortypes.h lib/forwardanalyzer.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/utils.h lib/valueflow.h lib/valueptr.h
+$(libcppdir)/forwardanalyzer.o: lib/forwardanalyzer.cpp lib/analyzer.h lib/astutils.h lib/config.h lib/errortypes.h lib/forwardanalyzer.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/utils.h lib/valueflow.h lib/valueptr.h
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o $(libcppdir)/forwardanalyzer.o $(libcppdir)/forwardanalyzer.cpp
$(libcppdir)/importproject.o: lib/importproject.cpp externals/picojson.h externals/tinyxml/tinyxml2.h lib/config.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/path.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
@@ -538,6 +539,9 @@ $(libcppdir)/preprocessor.o: lib/preprocessor.cpp externals/simplecpp/simplecpp.
$(libcppdir)/programmemory.o: lib/programmemory.cpp lib/astutils.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/programmemory.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/utils.h lib/valueflow.h
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o $(libcppdir)/programmemory.o $(libcppdir)/programmemory.cpp
+$(libcppdir)/reverseanalyzer.o: lib/reverseanalyzer.cpp lib/analyzer.h lib/astutils.h lib/config.h lib/errortypes.h lib/forwardanalyzer.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/reverseanalyzer.h lib/settings.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/utils.h lib/valueflow.h lib/valueptr.h
+ $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o $(libcppdir)/reverseanalyzer.o $(libcppdir)/reverseanalyzer.cpp
+
$(libcppdir)/settings.o: lib/settings.cpp lib/config.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/timer.h lib/utils.h lib/valueflow.h
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o $(libcppdir)/settings.o $(libcppdir)/settings.cpp
@@ -565,7 +569,7 @@ $(libcppdir)/tokenlist.o: lib/tokenlist.cpp externals/simplecpp/simplecpp.h lib/
$(libcppdir)/utils.o: lib/utils.cpp lib/config.h lib/utils.h
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o $(libcppdir)/utils.o $(libcppdir)/utils.cpp
-$(libcppdir)/valueflow.o: lib/valueflow.cpp lib/astutils.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/forwardanalyzer.h lib/importproject.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/programmemory.h lib/settings.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/valueptr.h
+$(libcppdir)/valueflow.o: lib/valueflow.cpp lib/analyzer.h lib/astutils.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/forwardanalyzer.h lib/importproject.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/programmemory.h lib/reverseanalyzer.h lib/settings.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/valueptr.h
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o $(libcppdir)/valueflow.o $(libcppdir)/valueflow.cpp
cli/cmdlineparser.o: cli/cmdlineparser.cpp cli/cmdlineparser.h cli/cppcheckexecutor.h cli/filelister.h cli/threadexecutor.h externals/tinyxml/tinyxml2.h lib/check.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/timer.h lib/utils.h
diff --git a/lib/analyzer.h b/lib/analyzer.h
new file mode 100644
index 000000000..60f8bd359
--- /dev/null
+++ b/lib/analyzer.h
@@ -0,0 +1,110 @@
+/*
+ * Cppcheck - A tool for static C/C++ code analysis
+ * Copyright (C) 2007-2020 Cppcheck team.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#ifndef analyzerH
+#define analyzerH
+
+#include
+#include
+
+class Token;
+template
+class ValuePtr;
+
+struct Analyzer {
+ struct Action {
+
+ Action() : mFlag(0) {}
+
+ // cppcheck-suppress noExplicitConstructor
+ Action(unsigned int f) : mFlag(f) {}
+
+ enum {
+ None = 0,
+ Read = (1 << 0),
+ Write = (1 << 1),
+ Invalid = (1 << 2),
+ Inconclusive = (1 << 3),
+ Match = (1 << 4),
+ Idempotent = (1 << 5),
+ };
+
+ void set(unsigned int f, bool state = true) { mFlag = state ? mFlag | f : mFlag & ~f; }
+
+ bool get(unsigned int f) const { return ((mFlag & f) != 0); }
+
+ bool isRead() const { return get(Read); }
+
+ bool isWrite() const { return get(Write); }
+
+ bool isInvalid() const { return get(Invalid); }
+
+ bool isInconclusive() const { return get(Inconclusive); }
+
+ bool isNone() const { return mFlag == None; }
+
+ bool isModified() const { return isWrite() || isInvalid(); }
+
+ bool isIdempotent() const { return get(Idempotent); }
+
+ bool matches() const { return get(Match); }
+
+ Action& operator|=(Action a)
+ {
+ set(a.mFlag);
+ return *this;
+ }
+
+ friend Action operator|(Action a, Action b)
+ {
+ a |= b;
+ return a;
+ }
+
+ friend bool operator==(Action a, Action b) { return a.mFlag == b.mFlag; }
+
+ friend bool operator!=(Action a, Action b) { return a.mFlag != b.mFlag; }
+
+ private:
+ unsigned int mFlag;
+ };
+
+ enum class Direction { Forward, Reverse };
+
+ /// Analyze a token
+ virtual Action analyze(const Token* tok, Direction d) const = 0;
+ /// Update the state of the value
+ virtual void update(Token* tok, Action a, Direction d) = 0;
+ /// Try to evaluate the value of a token(most likely a condition)
+ virtual std::vector evaluate(const Token* tok) const = 0;
+ /// Lower any values to possible
+ virtual bool lowerToPossible() = 0;
+ /// Lower any values to inconclusive
+ virtual bool lowerToInconclusive() = 0;
+ /// If the analysis is unsure whether to update a scope, this will return true if the analysis should bifurcate the scope
+ virtual bool updateScope(const Token* endBlock, bool modified) const = 0;
+ /// If the value is conditional
+ virtual bool isConditional() const = 0;
+ /// The condition that will be assumed during analysis
+ virtual void assume(const Token* tok, bool state, const Token* at = nullptr) = 0;
+ /// Return analyzer for expression at token
+ virtual ValuePtr reanalyze(Token* tok, const std::string& msg = "") const = 0;
+ virtual ~Analyzer() {}
+};
+
+#endif
diff --git a/lib/astutils.cpp b/lib/astutils.cpp
index 4c3bbc648..9f12df3d0 100644
--- a/lib/astutils.cpp
+++ b/lib/astutils.cpp
@@ -306,6 +306,18 @@ static bool hasToken(const Token * startTok, const Token * stopTok, const Token
return false;
}
+template )>
+static T* previousBeforeAstLeftmostLeafGeneric(T* tok)
+{
+ T* leftmostLeaf = tok;
+ while (leftmostLeaf && leftmostLeaf->astOperand1())
+ leftmostLeaf = leftmostLeaf->astOperand1();
+ return leftmostLeaf->previous();
+}
+
+const Token* previousBeforeAstLeftmostLeaf(const Token* tok) { return previousBeforeAstLeftmostLeafGeneric(tok); }
+Token* previousBeforeAstLeftmostLeaf(Token* tok) { return previousBeforeAstLeftmostLeafGeneric(tok); }
+
template )>
static T* nextAfterAstRightmostLeafGeneric(T* tok)
{
diff --git a/lib/astutils.h b/lib/astutils.h
index 3171d65fd..ce15d33c3 100644
--- a/lib/astutils.h
+++ b/lib/astutils.h
@@ -90,6 +90,9 @@ const Token * astIsVariableComparison(const Token *tok, const std::string &comp,
bool isTemporary(bool cpp, const Token* tok, const Library* library, bool unknown = false);
+const Token* previousBeforeAstLeftmostLeaf(const Token* tok);
+Token* previousBeforeAstLeftmostLeaf(Token* tok);
+
const Token * nextAfterAstRightmostLeaf(const Token * tok);
Token* nextAfterAstRightmostLeaf(Token* tok);
diff --git a/lib/checknullpointer.cpp b/lib/checknullpointer.cpp
index 11cebd655..9da2180f9 100644
--- a/lib/checknullpointer.cpp
+++ b/lib/checknullpointer.cpp
@@ -205,7 +205,9 @@ bool CheckNullPointer::isPointerDeRef(const Token *tok, bool &unknown, const Set
return false;
}
- if (Token::Match(tok, "%name% ("))
+ // If its a function pointer then check if its called
+ if (tok->variable() && tok->variable()->isPointer() && Token::Match(tok->variable()->nameToken(), "%name% ) (") &&
+ Token::Match(tok, "%name% ("))
return true;
if (Token::Match(tok, "%var% = %var% .") &&
diff --git a/lib/checksizeof.cpp b/lib/checksizeof.cpp
index bfa401161..411c22205 100644
--- a/lib/checksizeof.cpp
+++ b/lib/checksizeof.cpp
@@ -177,6 +177,9 @@ void CheckSizeof::checkSizeofForPointerSize()
while (Token::Match(variable2, "%var% ::|."))
variable2 = variable2->tokAt(2);
+ if (!variable)
+ continue;
+
// Ensure the variables are in the symbol database
// Also ensure the variables are pointers
// Only keep variables which are pointers
diff --git a/lib/cppcheck.vcxproj b/lib/cppcheck.vcxproj
index 2d7fa3217..7a8fd9464 100644
--- a/lib/cppcheck.vcxproj
+++ b/lib/cppcheck.vcxproj
@@ -101,6 +101,7 @@
+
diff --git a/lib/forwardanalyzer.cpp b/lib/forwardanalyzer.cpp
index 318c21b43..a4e9a26f0 100644
--- a/lib/forwardanalyzer.cpp
+++ b/lib/forwardanalyzer.cpp
@@ -10,12 +10,12 @@
struct ForwardTraversal {
enum class Progress { Continue, Break, Skip };
- ForwardTraversal(const ValuePtr& analyzer, const Settings* settings)
- : analyzer(analyzer), settings(settings), actions(ForwardAnalyzer::Action::None), analyzeOnly(false)
+ ForwardTraversal(const ValuePtr& analyzer, const Settings* settings)
+ : analyzer(analyzer), settings(settings), actions(Analyzer::Action::None), analyzeOnly(false)
{}
- ValuePtr analyzer;
+ ValuePtr analyzer;
const Settings* settings;
- ForwardAnalyzer::Action actions;
+ Analyzer::Action actions;
bool analyzeOnly;
bool stopUpdates() {
@@ -25,12 +25,9 @@ struct ForwardTraversal {
std::pair evalCond(const Token* tok) {
std::vector result = analyzer->evaluate(tok);
- bool checkThen = std::any_of(result.begin(), result.end(), [](int x) {
- return x;
- });
- bool checkElse = std::any_of(result.begin(), result.end(), [](int x) {
- return !x;
- });
+ // TODO: We should convert to bool
+ bool checkThen = std::any_of(result.begin(), result.end(), [](int x) { return x == 1; });
+ bool checkElse = std::any_of(result.begin(), result.end(), [](int x) { return x == 0; });
return std::make_pair(checkThen, checkElse);
}
@@ -124,10 +121,10 @@ struct ForwardTraversal {
}
Progress update(Token* tok) {
- ForwardAnalyzer::Action action = analyzer->analyze(tok);
+ Analyzer::Action action = analyzer->analyze(tok, Analyzer::Direction::Forward);
actions |= action;
if (!action.isNone() && !analyzeOnly)
- analyzer->update(tok, action);
+ analyzer->update(tok, action, Analyzer::Direction::Forward);
if (action.isInconclusive() && !analyzer->lowerToInconclusive())
return Progress::Break;
if (action.isInvalid())
@@ -153,19 +150,21 @@ struct ForwardTraversal {
}
template
- T* findRange(T* start, const Token* end, std::function pred) {
+ T* findRange(T* start, const Token* end, std::function pred)
+ {
for (T* tok = start; tok && tok != end; tok = tok->next()) {
- ForwardAnalyzer::Action action = analyzer->analyze(tok);
+ Analyzer::Action action = analyzer->analyze(tok, Analyzer::Direction::Forward);
if (pred(action))
return tok;
}
return nullptr;
}
- ForwardAnalyzer::Action analyzeRecursive(const Token* start) {
- ForwardAnalyzer::Action result = ForwardAnalyzer::Action::None;
- std::function