1212#include " clang/StaticAnalyzer/Core/BugReporter/BugType.h"
1313#include " clang/StaticAnalyzer/Core/Checker.h"
1414#include " clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
15+ #include " clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
16+ #include " llvm/Support/Casting.h"
1517#include " gtest/gtest.h"
1618
1719using namespace clang ;
@@ -44,6 +46,33 @@ CREATE_EXPR_ENGINE_CHECKER(ExprEngineVisitPreChecker, PreStmt, GCCAsmStmt,
4446CREATE_EXPR_ENGINE_CHECKER (ExprEngineVisitPostChecker, PostStmt, GCCAsmStmt,
4547 " GCCAsmStmtBug" )
4648
49+ class MemAccessChecker : public Checker <check::Location, check::Bind> {
50+ public:
51+ void checkLocation (const SVal &Loc, bool IsLoad, const Stmt *S,
52+ CheckerContext &C) const {
53+ emitErrorReport (C, Bug,
54+ " checkLocation: Loc = " + dumpToString (Loc) +
55+ " , Stmt = " + S->getStmtClassName ());
56+ }
57+
58+ void checkBind (SVal Loc, SVal Val, const Stmt *S, CheckerContext &C) const {
59+ emitErrorReport (C, Bug,
60+ " checkBind: Loc = " + dumpToString (Loc) +
61+ " , Val = " + dumpToString (Val) +
62+ " , Stmt = " + S->getStmtClassName ());
63+ }
64+
65+ private:
66+ const BugType Bug{this , " MemAccess" };
67+
68+ std::string dumpToString (SVal V) const {
69+ std::string StrBuf;
70+ llvm::raw_string_ostream StrStream{StrBuf};
71+ V.dumpToStream (StrStream);
72+ return StrBuf;
73+ }
74+ };
75+
4776void addExprEngineVisitPreChecker (AnalysisASTConsumer &AnalysisConsumer,
4877 AnalyzerOptions &AnOpts) {
4978 AnOpts.CheckersAndPackages = {{" ExprEngineVisitPreChecker" , true }};
@@ -62,6 +91,15 @@ void addExprEngineVisitPostChecker(AnalysisASTConsumer &AnalysisConsumer,
6291 });
6392}
6493
94+ void addMemAccessChecker (AnalysisASTConsumer &AnalysisConsumer,
95+ AnalyzerOptions &AnOpts) {
96+ AnOpts.CheckersAndPackages = {{" MemAccessChecker" , true }};
97+ AnalysisConsumer.AddCheckerRegistrationFn ([](CheckerRegistry &Registry) {
98+ Registry.addChecker <MemAccessChecker>(" MemAccessChecker" , " Desc" ,
99+ " DocsURI" );
100+ });
101+ }
102+
65103TEST (ExprEngineVisitTest, checkPreStmtGCCAsmStmt) {
66104 std::string Diags;
67105 EXPECT_TRUE (runCheckerOnCode<addExprEngineVisitPreChecker>(R"(
@@ -84,4 +122,32 @@ TEST(ExprEngineVisitTest, checkPostStmtGCCAsmStmt) {
84122 EXPECT_EQ (Diags, " ExprEngineVisitPostChecker: checkPostStmt<GCCAsmStmt>\n " );
85123}
86124
125+ TEST (ExprEngineVisitTest, checkLocationAndBind) {
126+ std::string Diags;
127+ EXPECT_TRUE (runCheckerOnCode<addMemAccessChecker>(R"(
128+ class MyClass{
129+ public:
130+ int Value;
131+ };
132+ extern MyClass MyClassWrite, MyClassRead;
133+ void top() {
134+ MyClassWrite = MyClassRead;
135+ }
136+ )" ,
137+ Diags));
138+
139+ std::string LocMsg = " checkLocation: Loc = lazyCompoundVal{0x0,MyClassRead}, "
140+ " Stmt = ImplicitCastExpr" ;
141+ std::string BindMsg =
142+ " checkBind: Loc = &MyClassWrite, Val = lazyCompoundVal{0x0,MyClassRead}, "
143+ " Stmt = CXXOperatorCallExpr" ;
144+ std::size_t LocPos = Diags.find (LocMsg);
145+ std::size_t BindPos = Diags.find (BindMsg);
146+ EXPECT_NE (LocPos, std::string::npos);
147+ EXPECT_NE (BindPos, std::string::npos);
148+ // Check order: first checkLocation is called, then checkBind.
149+ // In the diagnosis, however, the messages appear in reverse order.
150+ EXPECT_TRUE (LocPos > BindPos);
151+ }
152+
87153} // namespace
0 commit comments