@@ -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
536538void 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
542601void ExprEngine::inlineCall (WorkList *WList, const CallEvent &Call,
543602 const Decl *D, NodeBuilder &Bldr,
0 commit comments