3
3
// Assumptions for pinning:
4
4
// * args need to be pinned
5
5
// * 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.
6
10
7
11
#include " clang/Frontend/FrontendActions.h"
8
12
#include " clang/StaticAnalyzer/Checkers/SValExplainer.h"
@@ -96,6 +100,7 @@ class GCChecker
96
100
llvm::dbgs () << ((P == TransitivelyPinned) ? " TransitivelyPinned"
97
101
: (P == Pinned) ? " Pinned"
98
102
: (P == NotPinned) ? " NotPinned"
103
+ : (P == Moved) ? " Moved"
99
104
: " Error" );
100
105
llvm::dbgs () << " ," ;
101
106
if (S == Rooted)
@@ -325,6 +330,7 @@ class GCChecker
325
330
SymbolRef getSymbolForResult (const Expr *Result, const ValueState *OldValS,
326
331
ProgramStateRef &State, CheckerContext &C) const ;
327
332
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 ;
328
334
void validateValue (const GCChecker::ValueState* VS, CheckerContext &C, SymbolRef Sym, const char *message, SourceRange range) const ;
329
335
int validateValueInner (const GCChecker::ValueState* VS) const ;
330
336
GCChecker::ValueState getRootedFromRegion (const MemRegion *Region, const PinState *PS, int Depth) const ;
@@ -401,13 +407,16 @@ SymbolRef GCChecker::walkToRoot(callback f, const ProgramStateRef &State,
401
407
const MemRegion *Region) {
402
408
if (!Region)
403
409
return nullptr ;
410
+ logWithDump (" - walkToRoot, Region" , Region);
404
411
while (true ) {
405
412
const SymbolicRegion *SR = Region->getSymbolicBase ();
406
413
if (!SR) {
407
414
return nullptr ;
408
415
}
409
416
SymbolRef Sym = SR->getSymbol ();
410
417
const ValueState *OldVState = State->get <GCValueMap>(Sym);
418
+ logWithDump (" - walkToRoot, Sym" , Sym);
419
+ logWithDump (" - walkToRoot, OldVState" , OldVState);
411
420
if (f (Sym, OldVState)) {
412
421
if (const SymbolRegionValue *SRV = dyn_cast<SymbolRegionValue>(Sym)) {
413
422
Region = SRV->getRegion ();
@@ -468,6 +477,15 @@ void GCChecker::validateValue(const ValueState* VS, CheckerContext &C, SymbolRef
468
477
}
469
478
}
470
479
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
+
471
489
void GCChecker::validateValue (const ValueState* VS, CheckerContext &C, SymbolRef Sym, const char *message) const {
472
490
int v = validateValueInner (VS);
473
491
if (v == FREED) {
@@ -1106,7 +1124,11 @@ bool GCChecker::processPotentialSafepoint(const CallEvent &Call,
1106
1124
if (RetSym == I.getKey ())
1107
1125
continue ;
1108
1126
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);
1110
1132
DidChange = true ;
1111
1133
}
1112
1134
}
@@ -1178,6 +1200,8 @@ bool GCChecker::processAllocationOfResult(const CallEvent &Call,
1178
1200
Call.getOriginExpr (), C.getLocationContext (), QT, C.blockCount ());
1179
1201
State = State->BindExpr (Call.getOriginExpr (), C.getLocationContext (), S);
1180
1202
Sym = S.getAsSymbol ();
1203
+ logWithDump (" - conjureSymbolVal, S" , S);
1204
+ logWithDump (" - conjureSymbolVal, Sym" , Sym);
1181
1205
}
1182
1206
if (isGloballyRootedType (QT))
1183
1207
State = State->set <GCValueMap>(Sym, ValueState::getRooted (nullptr , ValueState::pinState (isGloballyTransitivelyPinnedType (QT)), -1 ));
@@ -1231,8 +1255,11 @@ bool GCChecker::processAllocationOfResult(const CallEvent &Call,
1231
1255
const MemRegion *Region = Test.getAsRegion ();
1232
1256
const ValueState *OldVState =
1233
1257
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
+ }
1236
1263
break ;
1237
1264
}
1238
1265
}
@@ -1360,6 +1387,7 @@ void GCChecker::checkDerivingExpr(const Expr *Result, const Expr *Parent,
1360
1387
SymbolRef OldSym = ParentVal.getAsSymbol (true );
1361
1388
const MemRegion *Region = C.getSVal (Parent).getAsRegion ();
1362
1389
const ValueState *OldValS = OldSym ? State->get <GCValueMap>(OldSym) : nullptr ;
1390
+ logWithDump (" - Region" , Region);
1363
1391
logWithDump (" - OldSym" , OldSym);
1364
1392
logWithDump (" - OldValS" , OldValS);
1365
1393
SymbolRef NewSym = getSymbolForResult (Result, OldValS, State, C);
@@ -1369,6 +1397,7 @@ void GCChecker::checkDerivingExpr(const Expr *Result, const Expr *Parent,
1369
1397
logWithDump (" - NewSym" , NewSym);
1370
1398
// NewSym might already have a better root
1371
1399
const ValueState *NewValS = State->get <GCValueMap>(NewSym);
1400
+ logWithDump (" - NewValS" , NewValS);
1372
1401
if (Region) {
1373
1402
const VarRegion *VR = Region->getAs <VarRegion>();
1374
1403
bool inheritedState = false ;
@@ -1418,8 +1447,9 @@ void GCChecker::checkDerivingExpr(const Expr *Result, const Expr *Parent,
1418
1447
validateValue (OldValS, C, OldSym, " Creating derivative of value that may have been" );
1419
1448
if (!OldValS->isPotentiallyFreed () && ResultTracked) {
1420
1449
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));
1423
1453
return ;
1424
1454
}
1425
1455
}
@@ -1739,6 +1769,13 @@ bool GCChecker::evalCall(const CallEvent &Call, CheckerContext &C) const {
1739
1769
report_error (C, " Can not understand this pin." );
1740
1770
return true ;
1741
1771
}
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
+
1742
1779
auto MRV = Arg.getAs <loc::MemRegionVal>();
1743
1780
if (!MRV) {
1744
1781
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 {
1747
1784
const MemRegion *Region = MRV->getRegion ();
1748
1785
auto State = C.getState ()->set <GCPinMap>(Region, PinState::getPin (CurrentDepth));
1749
1786
logWithDump (" - Pin region" , Region);
1750
- const ValueState *OldVS = State->get <GCValueMap>(Sym);
1751
1787
State = State->set <GCValueMap>(Sym, ValueState::getPinned (*OldVS));
1752
1788
logWithDump (" - Pin value" , Sym);
1753
1789
C.addTransition (State);
@@ -1899,8 +1935,11 @@ void GCChecker::checkBind(SVal LVal, SVal RVal, const clang::Stmt *S,
1899
1935
const ValueState *ValSP = nullptr ;
1900
1936
ValueState ValS;
1901
1937
if (rootRegionIfGlobal (R->getBaseRegion (), State, C, &ValS)) {
1938
+ logWithDump (" - rootRegionIfGlobal, base" , R->getBaseRegion ());
1902
1939
ValSP = &ValS;
1940
+ logWithDump (" - rootRegionIfGlobal ValSP" , ValSP);
1903
1941
} else {
1942
+ logWithDump (" - getValStateForRegion" , R);
1904
1943
ValSP = getValStateForRegion (C.getASTContext (), State, R);
1905
1944
}
1906
1945
if (ValSP && ValSP->isRooted ()) {
@@ -1910,8 +1949,9 @@ void GCChecker::checkBind(SVal LVal, SVal RVal, const clang::Stmt *S,
1910
1949
RValState->RootDepth < ValSP->RootDepth ) {
1911
1950
logWithDump (" - No need to set ValState, current ValState" , RValState);
1912
1951
} 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));
1915
1955
}
1916
1956
}
1917
1957
} else {
@@ -2008,42 +2048,55 @@ void GCChecker::checkLocation(SVal SLoc, bool IsLoad, const Stmt *S,
2008
2048
// Loading from a root produces a rooted symbol. TODO: Can we do something
2009
2049
// better than this.
2010
2050
if (IsLoad && (RS = State->get <GCRootMap>(SLoc.getAsRegion ()))) {
2051
+ logWithDump (" - IsLoad, RS" , RS);
2011
2052
SymbolRef LoadedSym =
2012
2053
State->getSVal (SLoc.getAs <Loc>().getValue ()).getAsSymbol ();
2013
2054
if (LoadedSym) {
2014
2055
const ValueState *ValS = State->get <GCValueMap>(LoadedSym);
2056
+ logWithDump (" - IsLoad, LoadedSym" , LoadedSym);
2057
+ logWithDump (" - IsLoad, ValS" , ValS);
2015
2058
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);
2016
2061
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);
2020
2063
}
2021
2064
}
2022
2065
}
2066
+ logWithDump (" - getAsRegion()" , SLoc.getAsRegion ());
2023
2067
// If it's just the symbol by itself, let it be. We allow dead pointer to be
2024
2068
// passed around, so long as they're not accessed. However, we do want to
2025
2069
// start tracking any globals that may have been accessed.
2026
2070
if (rootRegionIfGlobal (SLoc.getAsRegion (), State, C)) {
2027
2071
C.addTransition (State);
2072
+ log (" - rootRegionIfGlobal" );
2028
2073
return ;
2029
2074
}
2030
2075
SymbolRef SymByItself = SLoc.getAsSymbol (false );
2076
+ logWithDump (" - SymByItself" , SymByItself);
2031
2077
if (SymByItself) {
2032
2078
DidChange &&C.addTransition (State);
2033
2079
return ;
2034
2080
}
2035
2081
// This will walk backwards until it finds the base symbol
2036
2082
SymbolRef Sym = SLoc.getAsSymbol (true );
2083
+ logWithDump (" - Sym" , Sym);
2037
2084
if (!Sym) {
2038
2085
DidChange &&C.addTransition (State);
2039
2086
return ;
2040
2087
}
2041
2088
const ValueState *VState = State->get <GCValueMap>(Sym);
2089
+ logWithDump (" - VState" , VState);
2042
2090
if (!VState) {
2043
2091
DidChange &&C.addTransition (State);
2044
2092
return ;
2045
2093
}
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
+ }
2047
2100
DidChange &&C.addTransition (State);
2048
2101
}
2049
2102
0 commit comments