12
12
#include " clang/StaticAnalyzer/Core/BugReporter/BugType.h"
13
13
#include " clang/StaticAnalyzer/Core/Checker.h"
14
14
#include " clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
15
+ #include " clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
16
+ #include " llvm/Support/Casting.h"
15
17
#include " gtest/gtest.h"
16
18
17
19
using namespace clang ;
@@ -44,6 +46,33 @@ CREATE_EXPR_ENGINE_CHECKER(ExprEngineVisitPreChecker, PreStmt, GCCAsmStmt,
44
46
CREATE_EXPR_ENGINE_CHECKER (ExprEngineVisitPostChecker, PostStmt, GCCAsmStmt,
45
47
" GCCAsmStmtBug" )
46
48
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
+
47
76
void addExprEngineVisitPreChecker (AnalysisASTConsumer &AnalysisConsumer,
48
77
AnalyzerOptions &AnOpts) {
49
78
AnOpts.CheckersAndPackages = {{" ExprEngineVisitPreChecker" , true }};
@@ -62,6 +91,15 @@ void addExprEngineVisitPostChecker(AnalysisASTConsumer &AnalysisConsumer,
62
91
});
63
92
}
64
93
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
+
65
103
TEST (ExprEngineVisitTest, checkPreStmtGCCAsmStmt) {
66
104
std::string Diags;
67
105
EXPECT_TRUE (runCheckerOnCode<addExprEngineVisitPreChecker>(R"(
@@ -84,4 +122,32 @@ TEST(ExprEngineVisitTest, checkPostStmtGCCAsmStmt) {
84
122
EXPECT_EQ (Diags, " ExprEngineVisitPostChecker: checkPostStmt<GCCAsmStmt>\n " );
85
123
}
86
124
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
+
87
153
} // namespace
0 commit comments