def do(): # see NOTE map, ptr1, obj1, ref1 = self.getVars() _, ptr2, obj2, ref2 = self.getVars() map.BridgeAssociate(ptr1, obj1) map.BridgeAssociate(ptr2, obj2) # make both ptrs 'ready to weaken' CPyMarshal.WriteIntField(ptr1, PyObject, 'ob_refcnt', 1) CPyMarshal.WriteIntField(ptr2, PyObject, 'ob_refcnt', 1) map.CheckBridgePtrs(True) del obj1 del obj2 return map, ref1, ref2
def testExtensionTypesAutoActualisable(self): discoveryModes = { "IncRef": lambda f, o: self.assertMaps(mapper, f, o, 5), "Retrieve": lambda f, o: self.assertMaps(mapper, f, o, 4), "DecRef": lambda f, o: self.assertMaps(mapper, f, o, 3), "RefCount": lambda f, o: self.assertMaps(mapper, f, o, 4), } allocator = HGlobalAllocator() mapper = PythonMapper(allocator) deallocTypes = CreateTypes(mapper) # delay deallocs to avoid types with the same addresses causing confusion userTypeDeallocs = [] try: for (mode, TestFunc) in discoveryModes.items(): typePtr, deallocType = MakeTypePtr(mapper, {"tp_name": mode + "Class"}) userTypeDeallocs.append(deallocType) objPtr = allocator.Alloc(Marshal.SizeOf(PyObject)) CPyMarshal.WriteIntField(objPtr, PyObject, "ob_refcnt", 2) CPyMarshal.WritePtrField(objPtr, PyObject, "ob_type", typePtr) discoveryFunc = getattr(mapper, mode) TestFunc(discoveryFunc, objPtr) finally: mapper.Dispose() for deallocFunc in userTypeDeallocs: deallocFunc() deallocTypes()
def testFields(self, mapper, CallLater): basePtr, deallocBase = MakeTypePtr(mapper, {}) typePtr, deallocType = MakeTypePtr(mapper, {}) CallLater(deallocBase) CallLater(deallocType) # The purpose of this rigmarole is to enable me to use SOME_VALUE # for every field, rather than creating 'proper' values for every # field -- once I've Retrieved the types, I won't actualise them # again, so I can put any old non-zero nonsense in any field to # check that it gets inherited (or not) mapper.Retrieve(basePtr) mapper.Retrieve(typePtr) CPyMarshal.WriteIntField(typePtr, PyTypeObject, "tp_flags", int(Py_TPFLAGS.HAVE_CLASS)) # end rigmarole CPyMarshal.WritePtrField(typePtr, PyTypeObject, "tp_base", basePtr) for field in INHERIT_FIELDS + DONT_INHERIT_FIELDS: CPyMarshal.WritePtrField(typePtr, PyTypeObject, field, NO_VALUE) CPyMarshal.WritePtrField(basePtr, PyTypeObject, field, SOME_VALUE) mapper.PyType_Ready(typePtr) for field in INHERIT_FIELDS: self.assertEquals(CPyMarshal.ReadPtrField(typePtr, PyTypeObject, field), SOME_VALUE) for field in DONT_INHERIT_FIELDS: self.assertEquals(CPyMarshal.ReadPtrField(typePtr, PyTypeObject, field), NO_VALUE)
def testIgnoresBridgeObjectsNotAllocatedByAllocator(self): obj = object() ptr = Marshal.AllocHGlobal(Marshal.SizeOf(PyObject)) CPyMarshal.WriteIntField(ptr, PyObject, 'ob_refcnt', 2) mapper = PythonMapper() mapper.StoreBridge(ptr, obj) mapper.Dispose()
def testActualiseFloat(self, mapper, call_later): fptr = Marshal.AllocHGlobal(Marshal.SizeOf(PyFloatObject)) call_later(lambda: Marshal.FreeHGlobal(fptr)) CPyMarshal.WritePtrField(fptr, PyFloatObject, "ob_type", mapper.PyFloat_Type) CPyMarshal.WriteIntField(fptr, PyFloatObject, "ob_refcnt", 1) CPyMarshal.WriteDoubleField(fptr, PyFloatObject, "ob_fval", 1.234) self.assertEquals(mapper.Retrieve(fptr), 1.234)
def do(): # see NOTE in interestingptrmaptest obj = object() ref = WeakReference(obj) CPyMarshal.WriteIntField(ptr, PyObject, "ob_refcnt", 1) CPyMarshal.WritePtrField(ptr, PyObject, "ob_type", mapper.PyBaseObject_Type) mapper.StoreBridge(ptr, obj) self.assertEquals(mapper.Retrieve(ptr), obj, "object not stored") self.assertEquals(mapper.Store(obj), ptr, "object not reverse-mapped") mapper.Weaken(obj) CPyMarshal.WriteIntField(ptr, PyObject, "ob_refcnt", 1) mapper.IncRef(ptr) del obj return ref
def do1(): # see NOTE in interestingptrmaptest obj = object() ref = WeakReference(obj) CPyMarshal.WriteIntField(ptr, PyObject, "ob_refcnt", 1) CPyMarshal.WritePtrField(ptr, PyObject, "ob_type", mapper.PyBaseObject_Type) mapper.StoreBridge(ptr, obj) del obj return ref
def testNotAutoActualisableTypes(self, mapper, _): safeTypes = "PyString_Type PyList_Type PyTuple_Type PyType_Type PyFile_Type PyFloat_Type".split() discoveryModes = ("IncRef", "Retrieve", "DecRef", "RefCount") for _type in filter(lambda s: s not in safeTypes, BUILTIN_TYPES): for mode in discoveryModes: objPtr = Marshal.AllocHGlobal(Marshal.SizeOf(PyObject)) CPyMarshal.WriteIntField(objPtr, PyObject, "ob_refcnt", 2) CPyMarshal.WritePtrField(objPtr, PyObject, "ob_type", getattr(mapper, _type)) self.assertRaises(CannotInterpretException, getattr(mapper, mode), objPtr) Marshal.FreeHGlobal(objPtr)
def testCanFreeWithRefCount0(self): frees = [] mapper = PythonMapper(GetAllocatingTestAllocator([], frees)) objPtr = mapper.Store(object()) CPyMarshal.WriteIntField(objPtr, PyObject, "ob_refcnt", 0) mapper.PyObject_Free(objPtr) self.assertEquals(frees, [objPtr], "didn't actually release memory") mapper.Dispose()
def testWriteIntField(self): data = Marshal.AllocHGlobal(Marshal.SizeOf(PyIntObject())) CPyMarshal.Zero(data, Marshal.SizeOf(PyIntObject())) for value in (Int32.MaxValue, Int32.MinValue): CPyMarshal.WriteIntField(data, PyIntObject, "ob_ival", value) dataStruct = PtrToStructure(data, PyIntObject) self.assertEquals(dataStruct.ob_ival, value, "failed to write") Marshal.FreeHGlobal(data)
def testReadIntField(self): data = Marshal.AllocHGlobal(Marshal.SizeOf(PyIntObject())) CPyMarshal.Zero(data, Marshal.SizeOf(PyIntObject())) for value in (Int32.MaxValue, Int32.MinValue): CPyMarshal.WriteIntField(data, PyIntObject, "ob_ival", value) self.assertEquals( CPyMarshal.ReadIntField(data, PyIntObject, "ob_ival"), value, "failed to read") Marshal.FreeHGlobal(data)
def test_PyObject_NewVar(self): allocs = [] allocator = GetAllocatingTestAllocator(allocs, []) mapper = PythonMapper(allocator) deallocTypes = CreateTypes(mapper) typeObjSize = Marshal.SizeOf(PyTypeObject()) typePtr = Marshal.AllocHGlobal(typeObjSize) CPyMarshal.Zero(typePtr, typeObjSize) CPyMarshal.WriteIntField(typePtr, PyTypeObject, "tp_basicsize", 31337) CPyMarshal.WriteIntField(typePtr, PyTypeObject, "tp_itemsize", 1337) del allocs[:] objPtr = mapper._PyObject_NewVar(typePtr, 123) self.assertEquals(allocs, [(objPtr, 31337 + (1337 * 123))]) self.assertEquals(CPyMarshal.ReadPtrField(objPtr, PyObject, 'ob_type'), typePtr) self.assertEquals(CPyMarshal.ReadIntField(objPtr, PyObject, 'ob_refcnt'), 1) self.assertEquals(mapper.HasPtr(objPtr), False) mapper.Dispose() deallocTypes()
def do1(): obj = object() ref = WeakReference(obj) # need to use same allocator as mapper, otherwise it gets upset on shutdown ptr = allocator.Alloc(Marshal.SizeOf(PyObject())) CPyMarshal.WriteIntField(ptr, PyObject, "ob_refcnt", 2) CPyMarshal.WritePtrField(ptr, PyObject, "ob_type", mapper.PyBaseObject_Type) mapper.StoreBridge(ptr, obj) # refcount > 1 means ref should have been strengthened del obj return ref, ptr
def testDecRefObjectWithZeroRefCountFails(self): allocator = HGlobalAllocator() mapper = PythonMapper(allocator) deallocTypes = CreateTypes(mapper) # need to use same allocator as mapper, otherwise it gets upset on shutdown objPtr = allocator.Alloc(Marshal.SizeOf(PyObject())) CPyMarshal.WriteIntField(objPtr, PyObject, "ob_refcnt", 0) CPyMarshal.WritePtrField(objPtr, PyObject, "ob_type", mapper.PyBaseObject_Type) mapper.StoreBridge(objPtr, object()) self.assertRaisesClr(BadRefCountException, lambda: mapper.DecRef(objPtr)) mapper.Dispose() deallocTypes()
def do(): # see NOTE map, ptr, obj, ref = self.getVars() self.keepalive = map map.BridgeAssociate(ptr, obj) map.UpdateStrength(ptr) # ref should now be weak, but obj is still referenced in this scope CPyMarshal.WriteIntField(ptr, PyObject, 'ob_refcnt', 2) map.UpdateStrength(ptr) # should now be strong; safe to del obj del obj return ref
def testReleaseGILChecksBridgePtrs(self): frees = [] allocator = GetAllocatingTestAllocator([], frees) mapper = PythonMapper(allocator) deallocTypes = CreateTypes(mapper) # force no throttling of cleanup mapper.GCThreshold = 0 def do1(): obj = object() ref = WeakReference(obj) # need to use same allocator as mapper, otherwise it gets upset on shutdown ptr = allocator.Alloc(Marshal.SizeOf(PyObject)) CPyMarshal.WriteIntField(ptr, PyObject, "ob_refcnt", 2) CPyMarshal.WritePtrField(ptr, PyObject, "ob_type", mapper.PyBaseObject_Type) mapper.StoreBridge(ptr, obj) # refcount > 1 means ref should have been strengthened del obj return ref, ptr ref, ptr = do1() gcwait() self.assertEquals(ref.IsAlive, True, "was reaped unexpectedly (refcount was 2)") CPyMarshal.WriteIntField(ptr, PyObject, "ob_refcnt", 1) mapper.EnsureGIL() mapper.ReleaseGIL() # refcount < 2 should have been weakened gcwait() self.assertRaises(NullReferenceException, mapper.Retrieve, ptr) # need to dealloc ptr ourselves, it doesn't hapen automatically # except for objects with Dispatchers mapper.IC_PyBaseObject_Dealloc(ptr) mapper.Dispose() deallocTypes()
def WriteTypeField(typePtr, name, value): if name in PTR_ARGS: CPyMarshal.WritePtrField(typePtr, PyTypeObject, name, value) return lambda: None if name in INT_ARGS: CPyMarshal.WriteIntField(typePtr, PyTypeObject, name, int(value)) return lambda: None if name in STRING_ARGS: ptr = Marshal.StringToHGlobalAnsi(value) CPyMarshal.WritePtrField(typePtr, PyTypeObject, name, ptr) return lambda: Marshal.FreeHGlobal(ptr) if name in TABLE_ARGS: ptr, dealloc = MakeItemsTablePtr(value) CPyMarshal.WritePtrField(typePtr, PyTypeObject, name, ptr) return dealloc if name in FUNC_ARGS: if value is not None: dgt = FUNC_ARGS[name](value) CPyMarshal.WriteFunctionPtrField(typePtr, PyTypeObject, name, dgt) return GC_NotYet(dgt) return lambda: None raise KeyError("WriteTypeField can't handle %s, %s" % (name, value))
def testStoreUnknownType(self, mapper, _): class C(object): __name__ = "cantankerous.cochineal" cPtr = mapper.Store(C) self.assertEquals(CPyMarshal.ReadIntField(cPtr, PyTypeObject, "ob_refcnt"), 2, "seems easiest to 'leak' types, and ensure they live forever") self.assertEquals(CPyMarshal.ReadPtrField(cPtr, PyTypeObject, "ob_type"), mapper.PyType_Type) self.assertEquals(CPyMarshal.ReadPtrField(cPtr, PyTypeObject, "tp_base"), mapper.PyBaseObject_Type) self.assertEquals(CPyMarshal.ReadPtrField(cPtr, PyTypeObject, "tp_bases"), IntPtr.Zero) self.assertEquals(CPyMarshal.ReadPtrField(cPtr, PyTypeObject, "tp_as_number"), IntPtr.Zero) namePtr = CPyMarshal.ReadPtrField(cPtr, PyTypeObject, "tp_name") self.assertEquals(mapper.Retrieve(namePtr), "cantankerous.cochineal") baseFlags = CPyMarshal.ReadIntField(cPtr, PyTypeObject, "tp_flags") self.assertEquals(baseFlags & UInt32(Py_TPFLAGS.READY), UInt32(Py_TPFLAGS.READY), "did not ready newly-stored type") instancePtr = Marshal.AllocHGlobal(Marshal.SizeOf(PyObject)) CPyMarshal.WritePtrField(instancePtr, PyObject, "ob_type", cPtr) CPyMarshal.WriteIntField(instancePtr, PyObject, "ob_refcnt", 2) instance = mapper.Retrieve(instancePtr) self.assertEquals(isinstance(instance, C), True) self.assertEquals(mapper.Store(instance), instancePtr)
def getVars(self): obj = object() ptr = Marshal.AllocHGlobal(Marshal.SizeOf(PyObject())) CPyMarshal.WriteIntField(ptr, PyObject, 'ob_refcnt', 1) self.ptrs.append(ptr) return InterestingPtrMap(), ptr, obj, WeakReference(obj)