Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,14 +69,19 @@ void ExprEngine::performTrivialCopy(NodeBuilder &Bldr, ExplodedNode *Pred,

assert(ThisRD);
SVal V = Call.getArgSVal(0);
const Expr *VExpr = Call.getArgExpr(0);

// If the value being copied is not unknown, load from its location to get
// an aggregate rvalue.
if (std::optional<Loc> L = V.getAs<Loc>())
V = Pred->getState()->getSVal(*L);
else
assert(V.isUnknownOrUndef());
evalBind(Dst, CallExpr, Pred, ThisVal, V, true);

ExplodedNodeSet Tmp;
evalLocation(Tmp, CallExpr, VExpr, Pred, Pred->getState(), V, true);
for (ExplodedNode *N : Tmp)
evalBind(Dst, CallExpr, N, ThisVal, V, true);

PostStmt PS(CallExpr, LCtx);
for (ExplodedNode *N : Dst) {
Expand Down Expand Up @@ -1199,4 +1204,4 @@ void ExprEngine::VisitLambdaExpr(const LambdaExpr *LE, ExplodedNode *Pred,

// FIXME: Move all post/pre visits to ::Visit().
getCheckerManager().runCheckersForPostStmt(Dst, Tmp, LE, *this);
}
}
54 changes: 54 additions & 0 deletions clang/unittests/StaticAnalyzer/ExprEngineVisitTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
#include "llvm/Support/Casting.h"
#include "gtest/gtest.h"

using namespace clang;
Expand All @@ -27,6 +29,14 @@ void emitErrorReport(CheckerContext &C, const BugType &Bug,
}
}

inline std::string getMemRegionName(const SVal &Val) {
if (auto MemVal = llvm::dyn_cast<loc::MemRegionVal>(Val))
return MemVal->getRegion()->getDescriptiveName(false);
if (auto ComVal = llvm::dyn_cast<nonloc::LazyCompoundVal>(Val))
return ComVal->getRegion()->getDescriptiveName(false);
return "";
}

#define CREATE_EXPR_ENGINE_CHECKER(CHECKER_NAME, CALLBACK, STMT_TYPE, \
BUG_NAME) \
class CHECKER_NAME : public Checker<check::CALLBACK<STMT_TYPE>> { \
Expand All @@ -44,6 +54,21 @@ CREATE_EXPR_ENGINE_CHECKER(ExprEngineVisitPreChecker, PreStmt, GCCAsmStmt,
CREATE_EXPR_ENGINE_CHECKER(ExprEngineVisitPostChecker, PostStmt, GCCAsmStmt,
"GCCAsmStmtBug")

class MemAccessChecker : public Checker<check::Location, check::Bind> {
public:
void checkLocation(const SVal &Loc, bool IsLoad, const Stmt *S,
CheckerContext &C) const {
emitErrorReport(C, Bug, "checkLocation: Loc = " + getMemRegionName(Loc));
}

void checkBind(SVal Loc, SVal Val, const Stmt *S, CheckerContext &C) const {
emitErrorReport(C, Bug, "checkBind: Loc = " + getMemRegionName(Loc));
}

private:
const BugType Bug{this, "MemAccess"};
};

void addExprEngineVisitPreChecker(AnalysisASTConsumer &AnalysisConsumer,
AnalyzerOptions &AnOpts) {
AnOpts.CheckersAndPackages = {{"ExprEngineVisitPreChecker", true}};
Expand All @@ -62,6 +87,15 @@ void addExprEngineVisitPostChecker(AnalysisASTConsumer &AnalysisConsumer,
});
}

void addMemAccessChecker(AnalysisASTConsumer &AnalysisConsumer,
AnalyzerOptions &AnOpts) {
AnOpts.CheckersAndPackages = {{"MemAccessChecker", true}};
AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) {
Registry.addChecker<MemAccessChecker>("MemAccessChecker", "Desc",
"DocsURI");
});
}

TEST(ExprEngineVisitTest, checkPreStmtGCCAsmStmt) {
std::string Diags;
EXPECT_TRUE(runCheckerOnCode<addExprEngineVisitPreChecker>(R"(
Expand All @@ -84,4 +118,24 @@ TEST(ExprEngineVisitTest, checkPostStmtGCCAsmStmt) {
EXPECT_EQ(Diags, "ExprEngineVisitPostChecker: checkPostStmt<GCCAsmStmt>\n");
}

TEST(ExprEngineVisitTest, checkLocationAndBind) {
std::string Diags;
EXPECT_TRUE(runCheckerOnCode<addMemAccessChecker>(R"(
class MyClass{
public:
int Value;
};
extern MyClass MyClassWrite, MyClassRead;
void top() {
MyClassWrite = MyClassRead;
}
)",
Diags));

std::string RHSMsg = "checkLocation: Loc = MyClassRead";
std::string LHSMsg = "checkBind: Loc = MyClassWrite";
EXPECT_NE(Diags.find(RHSMsg), std::string::npos);
EXPECT_NE(Diags.find(LHSMsg), std::string::npos);
}

} // namespace