Skip to content

Commit b3627e0

Browse files
committed
Do horrible things to create a call event
1 parent a96dec3 commit b3627e0

File tree

1 file changed

+60
-1
lines changed

1 file changed

+60
-1
lines changed

clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -533,11 +533,70 @@ void ExprEngine::ctuBifurcate(const CallEvent &Call, const Decl *D,
533533
inlineCall(Engine.getWorkList(), Call, D, Bldr, Pred, State);
534534
}
535535

536+
// XXX: We only handle pthreads currently
537+
#pragma clang optimize off
536538
void ExprEngine::threadBifurcate(CallEvent const &Call, Decl const *D,
537539
NodeBuilder &Bldr, ExplodedNode *Pred,
538540
ProgramStateRef State) {
539-
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);
540598
}
599+
#pragma clang optimize on
541600

542601
void ExprEngine::inlineCall(WorkList *WList, const CallEvent &Call,
543602
const Decl *D, NodeBuilder &Bldr,

0 commit comments

Comments
 (0)