11// This file is a part of Julia. License is MIT: https://julialang.org/license
22
33// Assumptions for pinning:
4- // * args need to be pinned
5- // * JL_ROOTING_ARGUMENT and JL_ROOTED_ARGUMENT will propagate pinning state as well.
64// * The checker may not consider alias for derived pointers in some cases.
75// * 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.
86// * a = x->y; b = x->y; PTR_PIN(a); The checker will find b as pinned.
@@ -49,7 +47,7 @@ static const Stmt *getStmtForDiagnostics(const ExplodedNode *N)
4947}
5048
5149// Turn on/off the log here
52- #define DEBUG_LOG 1
50+ #define DEBUG_LOG 0
5351
5452class GCChecker
5553 : public Checker<
@@ -175,6 +173,9 @@ class GCChecker
175173 } else if (parent.isPinned ()) {
176174 // If parent is pinned, the child is not pinned.
177175 return getNotPinned (parent);
176+ } else if (parent.isMoved ()) {
177+ // If parent is moved, the child is not pinned.
178+ return getNotPinned (parent);
178179 } else {
179180 // For other cases, the children have the same state as the parent.
180181 return parent;
@@ -200,19 +201,20 @@ class GCChecker
200201 const ParmVarDecl *PVD) {
201202 bool isFunctionSafepoint = !isFDAnnotatedNotSafepoint (FD);
202203 bool maybeUnrooted = declHasAnnotation (PVD, " julia_maybe_unrooted" );
203- bool maybeUnpinned = declHasAnnotation (PVD, " julia_maybe_unpinned" );
204- if (!isFunctionSafepoint || maybeUnrooted || maybeUnpinned) {
204+ if (!isFunctionSafepoint || maybeUnrooted) {
205205 ValueState VS = getAllocated ();
206206 VS.PVD = PVD;
207207 VS.FD = FD;
208208 return VS;
209209 }
210210 bool require_tpin = declHasAnnotation (PVD, " julia_require_tpin" );
211+ bool require_pin = declHasAnnotation (PVD, " julia_require_pin" );
211212 if (require_tpin) {
212213 return getRooted (nullptr , ValueState::TransitivelyPinned, -1 );
213- } else {
214- // Assume arguments are pinned
214+ } else if (require_pin) {
215215 return getRooted (nullptr , ValueState::Pinned, -1 );
216+ } else {
217+ return getRooted (nullptr , ValueState::NotPinned, -1 );
216218 }
217219 }
218220 };
@@ -345,6 +347,7 @@ class GCChecker
345347 void validateValue (const GCChecker::ValueState* VS, CheckerContext &C, SymbolRef Sym, const char *message) const ;
346348 void validateValueRootnessOnly (const GCChecker::ValueState* VS, CheckerContext &C, SymbolRef Sym, const char *message) const ;
347349 void validateValue (const GCChecker::ValueState* VS, CheckerContext &C, SymbolRef Sym, const char *message, SourceRange range) const ;
350+ void validateValueRootnessOnly (const GCChecker::ValueState* VS, CheckerContext &C, SymbolRef Sym, const char *message, SourceRange range) const ;
348351 int validateValueInner (const GCChecker::ValueState* VS) const ;
349352 GCChecker::ValueState getRootedFromRegion (const MemRegion *Region, const PinState *PS, int Depth) const ;
350353 template <typename T>
@@ -481,6 +484,15 @@ static const VarRegion *walk_back_to_global_VR(const MemRegion *Region) {
481484#define FREED 1
482485#define MOVED 2
483486
487+ void GCChecker::validateValueRootnessOnly (const ValueState* VS, CheckerContext &C, SymbolRef Sym, const char *message, SourceRange range) const {
488+ int v = validateValueInner (VS);
489+ if (v == FREED) {
490+ GCChecker::report_value_error (C, Sym, (std::string (message) + " GCed" ).c_str (), range);
491+ } else if (v == MOVED) {
492+ // We don't care if it is moved
493+ }
494+ }
495+
484496void GCChecker::validateValue (const ValueState* VS, CheckerContext &C, SymbolRef Sym, const char *message, SourceRange range) const {
485497 int v = validateValueInner (VS);
486498 if (v == FREED) {
@@ -1139,10 +1151,10 @@ bool GCChecker::processPotentialSafepoint(const CallEvent &Call,
11391151 // Symbolically move all unpinned values.
11401152 GCValueMapTy AMap2 = State->get <GCValueMap>();
11411153 for (auto I = AMap2.begin (), E = AMap2.end (); I != E; ++I) {
1154+ logWithDump (" - check Sym" , I.getKey ());
11421155 if (RetSym == I.getKey ())
11431156 continue ;
11441157 if (I.getData ().isNotPinned ()) {
1145- logWithDump (" - move unpinned values, Sym" , I.getKey ());
11461158 logWithDump (" - move unpinned values, VS" , I.getData ());
11471159 auto NewVS = ValueState::getMoved (I.getData ());
11481160 State = State->set <GCValueMap>(I.getKey (), NewVS);
@@ -1195,9 +1207,9 @@ bool GCChecker::processArgumentRooting(const CallEvent &Call, CheckerContext &C,
11951207 const ValueState *CurrentVState = State->get <GCValueMap>(RootedSymbol);
11961208 ValueState NewVState = *OldVState;
11971209 // If the old state is pinned, the new state is not pinned.
1198- if (OldVState->isPinned () && ((CurrentVState && !CurrentVState->isPinnedByAnyway ()) || !CurrentVState)) {
1199- NewVState = ValueState::getNotPinned (*OldVState);
1200- }
1210+ // if (OldVState->isPinned() && ((CurrentVState && !CurrentVState->isPinnedByAnyway()) || !CurrentVState)) {
1211+ // NewVState = ValueState::getNotPinned(*OldVState);
1212+ // }
12011213 logWithDump (" - Rooted set to" , NewVState);
12021214 State = State->set <GCValueMap>(RootedSymbol, NewVState);
12031215 return true ;
@@ -1633,23 +1645,16 @@ void GCChecker::checkPreCall(const CallEvent &Call, CheckerContext &C) const {
16331645 range);
16341646 }
16351647 }
1636- if (ValState->isNotPinned ()) {
1637- bool MaybeUnpinned = false ;
1638- if (FD) {
1639- if (idx < FD->getNumParams ()) {
1640- MaybeUnpinned =
1641- declHasAnnotation (FD->getParamDecl (idx), " julia_maybe_unpinned" );
1642- }
1643- }
1644- if (!MaybeUnpinned && isCalleeSafepoint) {
1645- report_value_error (C, Sym, " Passing non-pinned value as argument to function that may GC" , range);
1646- }
1647- }
16481648 if (FD && idx < FD->getNumParams () && declHasAnnotation (FD->getParamDecl (idx), " julia_require_tpin" )) {
16491649 if (!ValState->isTransitivelyPinned ()) {
16501650 report_value_error (C, Sym, " Passing non-tpinned argument to function that requires a tpin argument." );
16511651 }
16521652 }
1653+ if (FD && idx < FD->getNumParams () && declHasAnnotation (FD->getParamDecl (idx), " julia_require_pin" )) {
1654+ if (!ValState->isPinnedByAnyway ()) {
1655+ report_value_error (C, Sym, " Passing non-pinned argument to function that requires a pin argument." );
1656+ }
1657+ }
16531658 }
16541659}
16551660
@@ -1810,6 +1815,7 @@ bool GCChecker::evalCall(const CallEvent &Call, CheckerContext &C) const {
18101815 }
18111816
18121817 const ValueState *OldVS = C.getState ()->get <GCValueMap>(Sym);
1818+ logWithDump (" - PTR_PIN OldVS" , OldVS);
18131819 if (OldVS && OldVS->isMoved ()) {
18141820 report_error (C, " Attempt to PIN a value that is already moved." );
18151821 return true ;
0 commit comments