Skip to content

Commit cb6a02d

Browse files
authored
Resolve FunctionDecl from start_routine function pointer in pthread_create(3) (#1)
* Declare new thread modeling checker * WIP Impl thread modeling checker * Resolve the function decl from a function pointer
1 parent 7c72941 commit cb6a02d

File tree

3 files changed

+90
-0
lines changed

3 files changed

+90
-0
lines changed

clang/include/clang/StaticAnalyzer/Checkers/Checkers.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,10 @@ def TrustReturnsNonnullChecker : Checker<"TrustReturnsNonnull">,
383383
"are not null">,
384384
Documentation<NotDocumented>;
385385

386+
def ThreadModeling : Checker<"Thread">,
387+
HelpText<"Make threaded code available to other checkers.">,
388+
Documentation<NotDocumented>;
389+
386390
} // end "apiModeling"
387391

388392
//===----------------------------------------------------------------------===//

clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ add_clang_library(clangStaticAnalyzerCheckers
112112
Taint.cpp
113113
TaintTesterChecker.cpp
114114
TestAfterDivZeroChecker.cpp
115+
ThreadModeling.cpp
115116
TraversalChecker.cpp
116117
TrustNonnullChecker.cpp
117118
TrustReturnsNonnullChecker.cpp
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
2+
3+
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
4+
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
5+
#include "clang/StaticAnalyzer/Core/Checker.h"
6+
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
7+
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
8+
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
9+
10+
#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
11+
12+
using namespace clang;
13+
using namespace ento;
14+
15+
#pragma clang optimize off
16+
17+
namespace {
18+
19+
// Since we are looking to extract the arguments, go with pre call for now
20+
class ThreadModeling : public Checker<check::PreCall> {
21+
22+
const CallDescriptionSet ThreadCreateCalls {
23+
{ CDM::CLibrary, {"pthread_create"}, 4},
24+
};
25+
26+
const FunctionDecl *GetFunctionDecl(SVal V, CheckerContext &C) const;
27+
public:
28+
void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
29+
};
30+
31+
} // end anonymous namespace
32+
33+
34+
void ThreadModeling::checkPreCall(const CallEvent &Call, CheckerContext &C) const {
35+
if (!ThreadCreateCalls.contains(Call)) {
36+
return;
37+
}
38+
39+
// 1. Get the `start_routine` argument
40+
ProgramStateRef State = C.getState();
41+
const FunctionDecl *CreateCall = reinterpret_cast<const FunctionDecl*>(Call.getDecl());
42+
43+
// 2. Extract the start_routine parameter
44+
/* int pthread_create(pthread_t *restrict thread,
45+
const pthread_attr_t *restrict attr,
46+
void *(*start_routine)(void *),
47+
void *restrict arg);
48+
*/
49+
assert(Call.getNumArgs() == 4 && "pthread_create(3) should have 4 arguments");
50+
Expr const *StartRoutineExpr = Call.getArgExpr(2);
51+
assert(StartRoutineExpr && "start_routine should exist"); // XXX: might fail if in diff TU?
52+
53+
// 3. Get the function pointer for `start_routine`
54+
SVal const SRV = C.getSVal(StartRoutineExpr);
55+
MemRegion const *SRR = SRV.getAsRegion();
56+
assert(SRR && "start_routine should be a pointer");
57+
58+
// 4. Resolve FunctionDecl from pointer
59+
FunctionDecl const *StartRoutine = nullptr;
60+
61+
if (auto const *FR = dyn_cast<FunctionCodeRegion>(SRR)) {
62+
StartRoutine = dyn_cast<FunctionDecl>(FR->getDecl());
63+
} // XXX: Can the function pointer be a different region type? (e.g. SymbolicRegion)
64+
assert(StartRoutine && "start_routine be a valid function pointer");
65+
66+
// 5. Get AST (single TU for now)
67+
// 6. Resolve AST to Call
68+
// 7. Inline Call
69+
70+
71+
}
72+
73+
const FunctionDecl *ThreadModeling::GetFunctionDecl(SVal V, CheckerContext &C) const {
74+
if (const FunctionDecl *FD = V.getAsFunctionDecl())
75+
return FD;
76+
return nullptr;
77+
}
78+
79+
void clang::ento::registerThreadModeling(CheckerManager &Mgr) {
80+
Mgr.registerChecker<ThreadModeling>();
81+
}
82+
83+
bool clang::ento::shouldRegisterThreadModeling(const CheckerManager &) {
84+
return true;
85+
}

0 commit comments

Comments
 (0)