33// Assumptions for pinning:
44// * args need to be pinned
55// * JL_ROOTING_ARGUMENT and JL_ROOTED_ARGUMENT will propagate pinning state as well.
6+ // * The checker may not consider alias for derived pointers in some cases.
7+ // * if f(x) returns a derived pointer from x, a = f(x); b = f(x); PTR_PIN(a); The checker will NOT find b as pinned.
8+ // * a = x->y; b = x->y; PTR_PIN(a); The checker will find b as pinned.
9+ // * Need to see if this affects correctness.
610
711#include " clang/Frontend/FrontendActions.h"
812#include " clang/StaticAnalyzer/Checkers/SValExplainer.h"
@@ -96,6 +100,7 @@ class GCChecker
96100 llvm::dbgs () << ((P == TransitivelyPinned) ? " TransitivelyPinned"
97101 : (P == Pinned) ? " Pinned"
98102 : (P == NotPinned) ? " NotPinned"
103+ : (P == Moved) ? " Moved"
99104 : " Error" );
100105 llvm::dbgs () << " ," ;
101106 if (S == Rooted)
@@ -325,6 +330,7 @@ class GCChecker
325330 SymbolRef getSymbolForResult (const Expr *Result, const ValueState *OldValS,
326331 ProgramStateRef &State, CheckerContext &C) const ;
327332 void validateValue (const GCChecker::ValueState* VS, CheckerContext &C, SymbolRef Sym, const char *message) const ;
333+ void validateValueRootnessOnly (const GCChecker::ValueState* VS, CheckerContext &C, SymbolRef Sym, const char *message) const ;
328334 void validateValue (const GCChecker::ValueState* VS, CheckerContext &C, SymbolRef Sym, const char *message, SourceRange range) const ;
329335 int validateValueInner (const GCChecker::ValueState* VS) const ;
330336 GCChecker::ValueState getRootedFromRegion (const MemRegion *Region, const PinState *PS, int Depth) const ;
@@ -401,13 +407,16 @@ SymbolRef GCChecker::walkToRoot(callback f, const ProgramStateRef &State,
401407 const MemRegion *Region) {
402408 if (!Region)
403409 return nullptr ;
410+ logWithDump (" - walkToRoot, Region" , Region);
404411 while (true ) {
405412 const SymbolicRegion *SR = Region->getSymbolicBase ();
406413 if (!SR) {
407414 return nullptr ;
408415 }
409416 SymbolRef Sym = SR->getSymbol ();
410417 const ValueState *OldVState = State->get <GCValueMap>(Sym);
418+ logWithDump (" - walkToRoot, Sym" , Sym);
419+ logWithDump (" - walkToRoot, OldVState" , OldVState);
411420 if (f (Sym, OldVState)) {
412421 if (const SymbolRegionValue *SRV = dyn_cast<SymbolRegionValue>(Sym)) {
413422 Region = SRV->getRegion ();
@@ -468,6 +477,15 @@ void GCChecker::validateValue(const ValueState* VS, CheckerContext &C, SymbolRef
468477 }
469478}
470479
480+ void GCChecker::validateValueRootnessOnly (const ValueState* VS, CheckerContext &C, SymbolRef Sym, const char *message) const {
481+ int v = validateValueInner (VS);
482+ if (v == FREED) {
483+ GCChecker::report_value_error (C, Sym, (std::string (message) + " GCed" ).c_str ());
484+ } else if (v == MOVED) {
485+ // We don't care if it is moved
486+ }
487+ }
488+
471489void GCChecker::validateValue (const ValueState* VS, CheckerContext &C, SymbolRef Sym, const char *message) const {
472490 int v = validateValueInner (VS);
473491 if (v == FREED) {
@@ -1106,7 +1124,11 @@ bool GCChecker::processPotentialSafepoint(const CallEvent &Call,
11061124 if (RetSym == I.getKey ())
11071125 continue ;
11081126 if (I.getData ().isNotPinned ()) {
1109- State = State->set <GCValueMap>(I.getKey (), ValueState::getMoved (I.getData ()));
1127+ logWithDump (" - move unpinned values, Sym" , I.getKey ());
1128+ logWithDump (" - move unpinned values, VS" , I.getData ());
1129+ auto NewVS = ValueState::getMoved (I.getData ());
1130+ State = State->set <GCValueMap>(I.getKey (), NewVS);
1131+ logWithDump (" - move unpinned values, NewVS" , NewVS);
11101132 DidChange = true ;
11111133 }
11121134 }
@@ -1178,6 +1200,8 @@ bool GCChecker::processAllocationOfResult(const CallEvent &Call,
11781200 Call.getOriginExpr (), C.getLocationContext (), QT, C.blockCount ());
11791201 State = State->BindExpr (Call.getOriginExpr (), C.getLocationContext (), S);
11801202 Sym = S.getAsSymbol ();
1203+ logWithDump (" - conjureSymbolVal, S" , S);
1204+ logWithDump (" - conjureSymbolVal, Sym" , Sym);
11811205 }
11821206 if (isGloballyRootedType (QT))
11831207 State = State->set <GCValueMap>(Sym, ValueState::getRooted (nullptr , ValueState::pinState (isGloballyTransitivelyPinnedType (QT)), -1 ));
@@ -1231,8 +1255,11 @@ bool GCChecker::processAllocationOfResult(const CallEvent &Call,
12311255 const MemRegion *Region = Test.getAsRegion ();
12321256 const ValueState *OldVState =
12331257 getValStateForRegion (C.getASTContext (), State, Region);
1234- if (OldVState)
1235- NewVState = *OldVState;
1258+ if (OldVState) {
1259+ NewVState = ValueState::inheritState (*OldVState);
1260+ logWithDump (" - jl_propagates_root, OldVState" , *OldVState);
1261+ logWithDump (" - jl_propagates_root, NewVState" , NewVState);
1262+ }
12361263 break ;
12371264 }
12381265 }
@@ -1360,6 +1387,7 @@ void GCChecker::checkDerivingExpr(const Expr *Result, const Expr *Parent,
13601387 SymbolRef OldSym = ParentVal.getAsSymbol (true );
13611388 const MemRegion *Region = C.getSVal (Parent).getAsRegion ();
13621389 const ValueState *OldValS = OldSym ? State->get <GCValueMap>(OldSym) : nullptr ;
1390+ logWithDump (" - Region" , Region);
13631391 logWithDump (" - OldSym" , OldSym);
13641392 logWithDump (" - OldValS" , OldValS);
13651393 SymbolRef NewSym = getSymbolForResult (Result, OldValS, State, C);
@@ -1369,6 +1397,7 @@ void GCChecker::checkDerivingExpr(const Expr *Result, const Expr *Parent,
13691397 logWithDump (" - NewSym" , NewSym);
13701398 // NewSym might already have a better root
13711399 const ValueState *NewValS = State->get <GCValueMap>(NewSym);
1400+ logWithDump (" - NewValS" , NewValS);
13721401 if (Region) {
13731402 const VarRegion *VR = Region->getAs <VarRegion>();
13741403 bool inheritedState = false ;
@@ -1418,8 +1447,9 @@ void GCChecker::checkDerivingExpr(const Expr *Result, const Expr *Parent,
14181447 validateValue (OldValS, C, OldSym, " Creating derivative of value that may have been" );
14191448 if (!OldValS->isPotentiallyFreed () && ResultTracked) {
14201449 logWithDump (" - Set as OldValS, Sym" , NewSym);
1421- logWithDump (" - Set as OldValS, VS" , OldValS);
1422- C.addTransition (State->set <GCValueMap>(NewSym, *OldValS));
1450+ auto InheritVS = ValueState::inheritState (*OldValS);
1451+ logWithDump (" - Set as OldValS, InheritVS" , InheritVS);
1452+ C.addTransition (State->set <GCValueMap>(NewSym, InheritVS));
14231453 return ;
14241454 }
14251455}
@@ -1739,6 +1769,13 @@ bool GCChecker::evalCall(const CallEvent &Call, CheckerContext &C) const {
17391769 report_error (C, " Can not understand this pin." );
17401770 return true ;
17411771 }
1772+
1773+ const ValueState *OldVS = C.getState ()->get <GCValueMap>(Sym);
1774+ if (OldVS && OldVS->isMoved ()) {
1775+ report_error (C, " Attempt to PIN a value that is already moved." );
1776+ return true ;
1777+ }
1778+
17421779 auto MRV = Arg.getAs <loc::MemRegionVal>();
17431780 if (!MRV) {
17441781 report_error (C, " PTR_PIN with something other than a local variable" );
@@ -1747,7 +1784,6 @@ bool GCChecker::evalCall(const CallEvent &Call, CheckerContext &C) const {
17471784 const MemRegion *Region = MRV->getRegion ();
17481785 auto State = C.getState ()->set <GCPinMap>(Region, PinState::getPin (CurrentDepth));
17491786 logWithDump (" - Pin region" , Region);
1750- const ValueState *OldVS = State->get <GCValueMap>(Sym);
17511787 State = State->set <GCValueMap>(Sym, ValueState::getPinned (*OldVS));
17521788 logWithDump (" - Pin value" , Sym);
17531789 C.addTransition (State);
@@ -1899,8 +1935,11 @@ void GCChecker::checkBind(SVal LVal, SVal RVal, const clang::Stmt *S,
18991935 const ValueState *ValSP = nullptr ;
19001936 ValueState ValS;
19011937 if (rootRegionIfGlobal (R->getBaseRegion (), State, C, &ValS)) {
1938+ logWithDump (" - rootRegionIfGlobal, base" , R->getBaseRegion ());
19021939 ValSP = &ValS;
1940+ logWithDump (" - rootRegionIfGlobal ValSP" , ValSP);
19031941 } else {
1942+ logWithDump (" - getValStateForRegion" , R);
19041943 ValSP = getValStateForRegion (C.getASTContext (), State, R);
19051944 }
19061945 if (ValSP && ValSP->isRooted ()) {
@@ -1910,8 +1949,9 @@ void GCChecker::checkBind(SVal LVal, SVal RVal, const clang::Stmt *S,
19101949 RValState->RootDepth < ValSP->RootDepth ) {
19111950 logWithDump (" - No need to set ValState, current ValState" , RValState);
19121951 } else {
1913- logWithDump (" - Set ValState, current ValState" , ValSP);
1914- C.addTransition (State->set <GCValueMap>(Sym, *ValSP));
1952+ auto InheritVS = ValueState::inheritState (*ValSP);
1953+ logWithDump (" - Set ValState, InheritVS" , InheritVS);
1954+ C.addTransition (State->set <GCValueMap>(Sym, InheritVS));
19151955 }
19161956 }
19171957 } else {
@@ -2008,42 +2048,55 @@ void GCChecker::checkLocation(SVal SLoc, bool IsLoad, const Stmt *S,
20082048 // Loading from a root produces a rooted symbol. TODO: Can we do something
20092049 // better than this.
20102050 if (IsLoad && (RS = State->get <GCRootMap>(SLoc.getAsRegion ()))) {
2051+ logWithDump (" - IsLoad, RS" , RS);
20112052 SymbolRef LoadedSym =
20122053 State->getSVal (SLoc.getAs <Loc>().getValue ()).getAsSymbol ();
20132054 if (LoadedSym) {
20142055 const ValueState *ValS = State->get <GCValueMap>(LoadedSym);
2056+ logWithDump (" - IsLoad, LoadedSym" , LoadedSym);
2057+ logWithDump (" - IsLoad, ValS" , ValS);
20152058 if (!ValS || !ValS->isRooted () || ValS->RootDepth > RS->RootedAtDepth ) {
2059+ auto NewVS = getRootedFromRegion (SLoc.getAsRegion (), State->get <GCPinMap>(SLoc.getAsRegion ()), RS->RootedAtDepth );
2060+ logWithDump (" - IsLoad, NewVS" , NewVS);
20162061 DidChange = true ;
2017- State = State->set <GCValueMap>(
2018- LoadedSym,
2019- getRootedFromRegion (SLoc.getAsRegion (), State->get <GCPinMap>(SLoc.getAsRegion ()), RS->RootedAtDepth ));
2062+ State = State->set <GCValueMap>(LoadedSym, NewVS);
20202063 }
20212064 }
20222065 }
2066+ logWithDump (" - getAsRegion()" , SLoc.getAsRegion ());
20232067 // If it's just the symbol by itself, let it be. We allow dead pointer to be
20242068 // passed around, so long as they're not accessed. However, we do want to
20252069 // start tracking any globals that may have been accessed.
20262070 if (rootRegionIfGlobal (SLoc.getAsRegion (), State, C)) {
20272071 C.addTransition (State);
2072+ log (" - rootRegionIfGlobal" );
20282073 return ;
20292074 }
20302075 SymbolRef SymByItself = SLoc.getAsSymbol (false );
2076+ logWithDump (" - SymByItself" , SymByItself);
20312077 if (SymByItself) {
20322078 DidChange &&C.addTransition (State);
20332079 return ;
20342080 }
20352081 // This will walk backwards until it finds the base symbol
20362082 SymbolRef Sym = SLoc.getAsSymbol (true );
2083+ logWithDump (" - Sym" , Sym);
20372084 if (!Sym) {
20382085 DidChange &&C.addTransition (State);
20392086 return ;
20402087 }
20412088 const ValueState *VState = State->get <GCValueMap>(Sym);
2089+ logWithDump (" - VState" , VState);
20422090 if (!VState) {
20432091 DidChange &&C.addTransition (State);
20442092 return ;
20452093 }
2046- validateValue (VState, C, Sym, " Trying to access value which may have been" );
2094+ // If this is the sym, we verify both rootness and pinning. Otherwise, it may be the parent sym and we only care about the rootness.
2095+ if (SymByItself == Sym) {
2096+ validateValue (VState, C, Sym, " Trying to access value which may have been" );
2097+ } else {
2098+ validateValueRootnessOnly (VState, C, Sym, " Trying to access value which may have been" );
2099+ }
20472100 DidChange &&C.addTransition (State);
20482101}
20492102
0 commit comments