@@ -2152,30 +2152,48 @@ static Object doIt(Object object) {
21522152 public abstract static class UpdateStrongRefNode extends Node {
21532153
21542154 public final void execute (Node inliningTarget , PythonAbstractObjectNativeWrapper wrapper , long refCount ) {
2155- execute (inliningTarget , wrapper , refCount > MANAGED_REFCNT );
2155+ execute (inliningTarget , wrapper , refCount > MANAGED_REFCNT , false );
21562156 }
21572157
2158- public final void clearStrongRef (Node inliningTarget , PythonAbstractObjectNativeWrapper wrapper ) {
2159- execute (inliningTarget , wrapper , false );
2158+ /**
2159+ * Makes the handle table reference of the given wrapper weak but keeps the native object
2160+ * stub in the GC list (if currently contained in any). The only valid use case for this
2161+ * method is when iterating over all objects of a GC list, calling this method on each
2162+ * object and in the end, dropping the whole GC list.
2163+ */
2164+ public final void clearStrongRefButKeepInGCList (Node inliningTarget , PythonAbstractObjectNativeWrapper wrapper ) {
2165+ execute (inliningTarget , wrapper , false , true );
21602166 }
21612167
2162- public abstract void execute (Node inliningTarget , PythonAbstractObjectNativeWrapper wrapper , boolean setStrong );
2168+ public abstract void execute (Node inliningTarget , PythonAbstractObjectNativeWrapper wrapper , boolean setStrong , boolean keepInGcList );
21632169
21642170 @ Specialization
2165- static void doGeneric (Node inliningTarget , PythonAbstractObjectNativeWrapper wrapper , boolean setStrong ,
2171+ static void doGeneric (Node inliningTarget , PythonAbstractObjectNativeWrapper wrapper , boolean setStrong , boolean keepInGcList ,
21662172 @ Cached InlinedConditionProfile hasRefProfile ,
2167- @ Cached PyObjectGCTrackNode gcTrackNode ) {
2173+ @ Cached PyObjectGCTrackNode gcTrackNode ,
2174+ @ Cached GCListRemoveNode gcListRemoveNode ) {
2175+ assert CompilerDirectives .isPartialEvaluationConstant (keepInGcList );
2176+
21682177 PythonObjectReference ref ;
21692178 if (hasRefProfile .profile (inliningTarget , (ref = wrapper .ref ) != null )) {
21702179 assert ref .pointer == wrapper .getNativePointer ();
21712180 if (setStrong && !ref .isStrongReference ()) {
21722181 ref .setStrongReference (wrapper );
21732182 if (ref .gc && PythonLanguage .get (inliningTarget ).getEngineOption (PythonOptions .PythonGC )) {
21742183 // gc = AS_GC(op)
2175- long gc = wrapper . getNativePointer () - CStructs .PyGC_Head .size ();
2184+ long gc = ref . pointer - CStructs .PyGC_Head .size ();
21762185 gcTrackNode .execute (inliningTarget , gc );
21772186 }
21782187 } else if (!setStrong && ref .isStrongReference ()) {
2188+ /*
2189+ * As soon as the reference is made weak, we remove it from the GC list because
2190+ * there are ways to iterate a GC list (e.g. 'PyUnstable_GC_VisitObjects') and
2191+ * while doing so, the objects may be accessed. Since weakly referenced objects
2192+ * may die any time, this could lead to dangling pointers being used.
2193+ */
2194+ if (!keepInGcList && ref .gc ) {
2195+ gcListRemoveNode .executeOp (inliningTarget , ref .pointer );
2196+ }
21792197 ref .setStrongReference (null );
21802198 }
21812199 }
0 commit comments