Skip to content

Commit 3af6626

Browse files
authored
ExprEngine hacks to test inlining (#2)
* Add analyzer option to control thread modeling * Add method if a call is to create a thread * Add special case for thread creation * Do horrible things to create a call event
1 parent 5ed42b8 commit 3af6626

File tree

3 files changed

+93
-0
lines changed

3 files changed

+93
-0
lines changed

clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,10 @@ ANALYZER_OPTION(
385385
"flex\" won't be analyzed.",
386386
true)
387387

388+
ANALYZER_OPTION(bool, ThreadAware, "thread-aware",
389+
"If enabled, enable thread API modeling to perform cross-thread analysis",
390+
true)
391+
388392
//===----------------------------------------------------------------------===//
389393
// Unsigned analyzer options.
390394
//===----------------------------------------------------------------------===//

clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ class ExprEngine {
137137
private:
138138
cross_tu::CrossTranslationUnitContext &CTU;
139139
bool IsCTUEnabled;
140+
bool IsThreadEnabled;
140141

141142
AnalysisManager &AMgr;
142143

@@ -807,6 +808,9 @@ class ExprEngine {
807808
const ExplodedNode *Pred,
808809
const EvalCallOptions &CallOpts = {});
809810

811+
/// Check if this is a call to create a thread
812+
bool isThread(CallEvent const &Call) const;
813+
810814
/// Checks whether our policies allow us to inline a non-POD type array
811815
/// construction.
812816
bool shouldInlineArrayConstruction(const ProgramStateRef State,
@@ -845,6 +849,9 @@ class ExprEngine {
845849
void ctuBifurcate(const CallEvent &Call, const Decl *D, NodeBuilder &Bldr,
846850
ExplodedNode *Pred, ProgramStateRef State);
847851

852+
void threadBifurcate(CallEvent const &Call, Decl const *D, NodeBuilder &Bldr,
853+
ExplodedNode *Pred, ProgramStateRef State);
854+
848855
/// Returns true if the CTU analysis is running its second phase.
849856
bool isSecondPhaseCTU() { return IsCTUEnabled && !Engine.getCTUWorkList(); }
850857

clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "llvm/Support/Casting.h"
2626
#include "llvm/Support/Compiler.h"
2727
#include "llvm/Support/SaveAndRestore.h"
28+
#include <clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h>
2829
#include <optional>
2930

3031
using namespace clang;
@@ -532,6 +533,71 @@ void ExprEngine::ctuBifurcate(const CallEvent &Call, const Decl *D,
532533
inlineCall(Engine.getWorkList(), Call, D, Bldr, Pred, State);
533534
}
534535

536+
// XXX: We only handle pthreads currently
537+
#pragma clang optimize off
538+
void ExprEngine::threadBifurcate(CallEvent const &Call, Decl const *D,
539+
NodeBuilder &Bldr, ExplodedNode *Pred,
540+
ProgramStateRef State) {
541+
// The declaration for pthread_create(3):
542+
/* int pthread_create(pthread_t *thread,
543+
const pthread_attr_t *attr,
544+
void *(*start_routine)(void *),
545+
void *arg);
546+
*/
547+
assert(Call.getNumArgs() == 4 && "pthread_create(3) should have 4 args");
548+
549+
// 1. Extract the expr for the thread's start routine
550+
auto const *SRExpr = Call.getArgExpr(2);
551+
assert(SRExpr && "start_routine should exist");
552+
auto const *SRInit = Call.getArgExpr(3);
553+
assert(SRInit && "start_routine should have an init param");
554+
555+
// 2. Convert the expr into a function pointer
556+
auto const SRV = Pred->getSVal(SRExpr);
557+
auto const *SRR = SRV.getAsRegion();
558+
assert(SRR && "start_routine should be a pointer");
559+
560+
FunctionDecl const *StartRoutine = nullptr;
561+
if (auto const *FR = dyn_cast<FunctionCodeRegion>(SRR))
562+
StartRoutine = dyn_cast<FunctionDecl>(FR->getDecl());
563+
564+
assert(StartRoutine && "start_routine should be a valid function pointer");
565+
assert(StartRoutine->hasBody() && "start_routine must be well defined");
566+
567+
// 3. Create a CallEvent for calling the function pointer
568+
569+
auto *SRCtx = AMgr.getAnalysisDeclContext(StartRoutine);
570+
571+
auto &CEMgr = State->getStateManager().getCallEventManager();
572+
auto const *LC = Pred->getLocationContext();
573+
574+
// We need to construct a fake CallExpr for the worker thread, since it doesn't exist
575+
576+
auto *srexpr = DeclRefExpr::Create(
577+
SRR->getContext(),
578+
NestedNameSpecifierLoc(),
579+
SourceLocation(),
580+
const_cast<FunctionDecl*>(StartRoutine),
581+
false,
582+
SourceLocation(),
583+
StartRoutine->getType(),
584+
VK_LValue);
585+
586+
CallExpr *srcall = CallExpr::Create(
587+
SRR->getContext(),
588+
srexpr,
589+
{const_cast<Expr*>(SRInit)},
590+
StartRoutine->getType(),
591+
VK_LValue,
592+
SourceLocation(),
593+
FPOptionsOverride());
594+
595+
auto call = CEMgr.getSimpleCall(srcall, State, LC, getCFGElementRef());
596+
597+
inlineCall(Engine.getWorkList(), *call, StartRoutine, Bldr, Pred, State);
598+
}
599+
#pragma clang optimize on
600+
535601
void ExprEngine::inlineCall(WorkList *WList, const CallEvent &Call,
536602
const Decl *D, NodeBuilder &Bldr,
537603
ExplodedNode *Pred, ProgramStateRef State) {
@@ -1144,6 +1210,14 @@ bool ExprEngine::shouldInlineCall(const CallEvent &Call, const Decl *D,
11441210
return true;
11451211
}
11461212

1213+
static const CallDescriptionSet ThreadCreateCalls {
1214+
{ CDM::CLibrary, {"pthread_create"}, 4},
1215+
};
1216+
1217+
bool ExprEngine::isThread(CallEvent const &Call) const {
1218+
return ThreadCreateCalls.contains(Call);
1219+
}
1220+
11471221
bool ExprEngine::shouldInlineArrayConstruction(const ProgramStateRef State,
11481222
const CXXConstructExpr *CE,
11491223
const LocationContext *LCtx) {
@@ -1241,6 +1315,14 @@ void ExprEngine::defaultEvalCall(NodeBuilder &Bldr, ExplodedNode *Pred,
12411315
RuntimeDefinition RD = Call->getRuntimeDefinition();
12421316
Call->setForeign(RD.isForeign());
12431317
const Decl *D = RD.getDecl();
1318+
1319+
// TODO: make this a proper mode
1320+
// Special case thread creation
1321+
if (isThread(*Call)) {
1322+
threadBifurcate(*Call, D, Bldr, Pred, State);
1323+
return;
1324+
}
1325+
12441326
if (shouldInlineCall(*Call, D, Pred, CallOpts)) {
12451327
if (RD.mayHaveOtherDefinitions()) {
12461328
AnalyzerOptions &Options = getAnalysisManager().options;

0 commit comments

Comments
 (0)