def testCreateStringWithData(self): allocs = [] mapper = PythonMapper(GetAllocatingTestAllocator(allocs, [])) deallocTypes = CreateTypes(mapper) del allocs[:] try: testString = "we also run the shovel racket" + self.getStringWithValues( 0, 256) testBytes = self.byteArrayFromString(testString) testData = self.ptrFromByteArray(testBytes) testLength = len(testString) strPtr = mapper.PyString_FromStringAndSize(testData, testLength) baseSize = Marshal.SizeOf(PyStringObject) self.assertEquals(allocs, [(strPtr, testLength + baseSize)], "allocated wrong") self.assertHasStringType(strPtr, mapper) self.assertStringObjectHasLength(strPtr, testLength) self.assertStringObjectHasDataBytes(strPtr, testBytes) self.assertEquals(mapper.Retrieve(strPtr), testString, "failed to read string data") finally: mapper.Dispose() deallocTypes()
def testPyTuple_DeallocDecRefsItemsAndCallsCorrectFreeFunction(self): frees = [] mapper = PythonMapper(GetAllocatingTestAllocator([], frees)) deallocTypes = CreateTypes(mapper) calls = [] def CustomFree(ptr): calls.append(ptr) freeDgt = dgt_void_ptr(CustomFree) CPyMarshal.WriteFunctionPtrField(mapper.PyTuple_Type, PyTypeObject, "tp_free", freeDgt) tuplePtr, itemPtrs = MakeTuple(mapper, (1, 2, 3)) mapper.IC_PyTuple_Dealloc(tuplePtr) for itemPtr in itemPtrs: self.assertEquals(itemPtr in frees, True, "did not decref item") self.assertEquals(calls, [tuplePtr], "did not call type's free function") mapper.PyObject_Free(tuplePtr) mapper.Dispose() deallocTypes()
def testZero(self): allocs = [] mapper = PythonMapper(GetAllocatingTestAllocator(allocs, [])) resultPtr = getattr(mapper, MALLOC_NAME)(0) self.assertEquals(allocs, [(resultPtr, 1)], "bad alloc") mapper.Dispose()
def assertPyTuple_New_Works(self, length): allocs = [] mapper = PythonMapper(GetAllocatingTestAllocator(allocs, [])) typeBlock = Marshal.AllocHGlobal(Marshal.SizeOf(PyTypeObject)) mapper.RegisterData("PyTuple_Type", typeBlock) tuplePtr = mapper.PyTuple_New(length) expectedSize = Marshal.SizeOf(PyTupleObject) + (CPyMarshal.PtrSize * (length - 1)) self.assertEquals(allocs, [(tuplePtr, expectedSize)], "bad alloc") tupleStruct = Marshal.PtrToStructure(tuplePtr, PyTupleObject) self.assertEquals(tupleStruct.ob_refcnt, 1, "bad refcount") self.assertEquals(tupleStruct.ob_type, mapper.PyTuple_Type, "bad type") self.assertEquals(tupleStruct.ob_size, length, "bad size") self.assertEquals(mapper.PyTuple_Size(tuplePtr), length, "should still work with uninitialised tuple imo") dataPtr = OffsetPtr(tuplePtr, Marshal.OffsetOf(PyTupleObject, "ob_item")) itemPtrs = [] for i in range(length): self.assertEquals(CPyMarshal.ReadPtr(dataPtr), IntPtr.Zero, "item memory not zeroed") itemPtr = mapper.Store(i + 100) CPyMarshal.WritePtr(dataPtr, itemPtr) itemPtrs.append(itemPtr) dataPtr = OffsetPtr(dataPtr, CPyMarshal.PtrSize) immutableTuple = mapper.Retrieve(tuplePtr) self.assertEquals(immutableTuple, tuple(i + 100 for i in range(length)), "broken") tuplePtr2 = mapper.Store(immutableTuple) self.assertEquals(tuplePtr2, tuplePtr, "didn't realise already had this object stored") self.assertEquals(mapper.RefCount(tuplePtr), 2, "didn't incref") mapper.Dispose() Marshal.FreeHGlobal(typeBlock)
def testPyList_New_NonZeroLength(self): allocs = [] mapper = PythonMapper(GetAllocatingTestAllocator(allocs, [])) deallocTypes = CreateTypes(mapper) del allocs[:] SIZE = 27 listPtr = mapper.PyList_New(SIZE) listStruct = Marshal.PtrToStructure(listPtr, PyListObject) self.assertEquals(listStruct.ob_refcnt, 1, "bad refcount") self.assertEquals(listStruct.ob_type, mapper.PyList_Type, "bad type") self.assertEquals(listStruct.ob_size, SIZE, "bad ob_size") self.assertEquals(listStruct.allocated, SIZE, "bad allocated") dataPtr = listStruct.ob_item self.assertNotEquals(dataPtr, IntPtr.Zero, "failed to allocate space for data") expectedAllocs = [(dataPtr, (SIZE * CPyMarshal.PtrSize)), (listPtr, Marshal.SizeOf(PyListObject))] self.assertEquals(set(allocs), set(expectedAllocs), "allocated wrong") for _ in range(SIZE): self.assertEquals(CPyMarshal.ReadPtr(dataPtr), IntPtr.Zero, "failed to zero memory") dataPtr = OffsetPtr(dataPtr, CPyMarshal.PtrSize) mapper.Dispose() deallocTypes()
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 testShrink(self): allocs = [] frees = [] mapper = PythonMapper(GetAllocatingTestAllocator(allocs, frees)) deallocTypes = CreateTypes(mapper) del allocs[:] oldLength = 365 newLength = 20 ptrPtr = Marshal.AllocHGlobal(Marshal.SizeOf(IntPtr)) try: strPtr = mapper.PyString_FromStringAndSize(IntPtr.Zero, oldLength) Marshal.WriteIntPtr(ptrPtr, strPtr) baseSize = Marshal.SizeOf(PyStringObject) self.assertEquals(allocs, [(strPtr, oldLength + baseSize)], "allocated wrong") self.assertEquals(mapper._PyString_Resize(ptrPtr, newLength), 0, "bad return on success") self.assertHasStringType(strPtr, mapper) self.assertStringObjectHasLength(strPtr, newLength) self.assertEquals(allocs, [(strPtr, oldLength + baseSize)], "unexpected extra alloc") self.assertEquals(frees, [], "unexpected frees") finally: mapper.Dispose() Marshal.FreeHGlobal(ptrPtr) deallocTypes()
def testPyMem_Free_Null(self): frees = [] mapper = PythonMapper(GetAllocatingTestAllocator([], frees)) mapper.PyMem_Free(IntPtr.Zero) self.assertEquals(frees, [], "freed inappropriately") mapper.Dispose()
def testSomeItems(self): allocs = [] mapper = PythonMapper(GetAllocatingTestAllocator(allocs, [])) deallocTypes = CreateTypes(mapper) typeSpec = { "tp_basicsize": 32, "tp_itemsize": 64, } typePtr, deallocType = MakeTypePtr(mapper, typeSpec) del allocs[:] result = mapper.PyType_GenericAlloc(typePtr, 3) self.assertEquals(allocs, [(result, 224)], "allocated wrong") refcount = CPyMarshal.ReadIntField(result, PyObject, "ob_refcnt") self.assertEquals(refcount, 1, "bad initialisation") instanceType = CPyMarshal.ReadPtrField(result, PyObject, "ob_type") self.assertEquals(instanceType, typePtr, "bad type ptr") size = CPyMarshal.ReadIntField(result, PyVarObject, "ob_size") self.assertEquals(size, 3, "bad ob_size") headerSize = Marshal.SizeOf(PyVarObject) zerosPtr = OffsetPtr(result, headerSize) for i in range(224 - headerSize): self.assertEquals(CPyMarshal.ReadByte(zerosPtr), 0, "not zeroed") zerosPtr = OffsetPtr(zerosPtr, 1) mapper.Dispose() deallocTypes() deallocType()
def test_Py_InitModule4_VarargsKwargsFunction(self): mapper = PythonMapper() deallocTypes = CreateTypes(mapper) args = (object(), object()) kwargs = {'a': object(), 'b': object()} result = object() resultPtr = mapper.Store(result) mapper.IncRef(resultPtr) def func(_, argsPtr, kwargsPtr): self.assertEquals(_, MODULE_PTR) self.assertEquals(mapper.Retrieve(argsPtr), args) self.assertEquals(mapper.Retrieve(kwargsPtr), kwargs) return resultPtr method, deallocMethod = MakeMethodDef("func", func, METH.VARARGS | METH.KEYWORDS) def testModule(module, mapper): self.assertEquals(module.func(*args, **kwargs), result, "not hooked up") self.assert_Py_InitModule4_withSingleMethod(mapper, method, testModule) deallocMethod() deallocTypes()
def testPyList_DeallocDecRefsItemsAndCallsCorrectFreeFunction(self): frees = [] mapper = PythonMapper(GetAllocatingTestAllocator([], frees)) deallocTypes = CreateTypes(mapper) calls = [] def CustomFree(ptr): calls.append(ptr) mapper.PyObject_Free(listPtr) self.freeDgt = dgt_void_ptr(CustomFree) CPyMarshal.WriteFunctionPtrField(mapper.PyList_Type, PyTypeObject, "tp_free", self.freeDgt) listPtr = mapper.Store([1, 2, 3]) itemPtrs = [] dataStore = CPyMarshal.ReadPtrField(listPtr, PyListObject, "ob_item") for _ in range(3): itemPtrs.append(CPyMarshal.ReadPtr(dataStore)) dataStore = OffsetPtr(dataStore, CPyMarshal.PtrSize) mapper.IC_PyList_Dealloc(listPtr) for itemPtr in itemPtrs: self.assertEquals(itemPtr in frees, True, "did not decref item") self.assertEquals(calls, [listPtr], "did not call type's free function") mapper.Dispose() deallocTypes()
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 assertRuns(self, test_code=''): mapper = PythonMapper(DLL_PATH) try: exec '\n'.join([import_code, test_code]) in globals(), locals_ finally: mapper.Dispose() if module in sys.modules: del sys.modules[module]
def testPyMem_Free_NonNull(self): frees = [] mapper = PythonMapper(GetAllocatingTestAllocator([], frees)) ptr = mapper.PyMem_Malloc(123) mapper.PyMem_Free(ptr) self.assertEquals(frees, [ptr], "did not free") mapper.Dispose()
def testIC_PyBaseObject_Init(self, mapper, _): "this function shouldn't do anything..." mapper = PythonMapper() deallocTypes = CreateTypes(mapper) self.assertEquals(mapper.IC_PyBaseObject_Init(IntPtr.Zero, IntPtr.Zero, IntPtr.Zero), 0) mapper.Dispose() deallocTypes()
def testNullPtr(self): allocs = [] frees = [] mapper = PythonMapper(GetAllocatingTestAllocator(allocs, frees)) mem = getattr(mapper, REALLOC_NAME)(IntPtr.Zero, 4) self.assertEquals(frees, []) self.assertEquals(allocs, [(mem, 4)]) mapper.Dispose()
def testRemovesMmapOnDispose(self): mapper = PythonMapper(DLL_PATH) try: sys.modules['csv'] = object() mapper.Dispose() self.assertFalse('mmap' in sys.modules) self.assertFalse('_csv' in sys.modules) self.assertFalse('csv' in sys.modules) finally: mapper.Dispose()
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 testDecRefLaterSurvivesEmptyStack(self): frees = [] mapper = PythonMapper(GetAllocatingTestAllocator([], frees)) mapper.tempObjects = Stack[List[IntPtr]]() try: mapper.DecRefLater(IntPtr.Zero) except InvalidOperationException: self.fail('DecRefLater should not throw StackEmpty if tempObjects is empty') finally: mapper.Dispose()
def assertUsual_tp_dealloc(self, typename): mapper = PythonMapper() deallocTypes = CreateTypes(mapper) tp_deallocPtr = CPyMarshal.ReadPtrField( getattr(mapper, typename), PyTypeObject, "tp_dealloc") self.assertEquals(tp_deallocPtr, mapper.GetFuncPtr("IC_PyBaseObject_Dealloc"), "wrong tp_dealloc for " + typename) mapper.Dispose() deallocTypes()
def testDecRefLaterSurvivesNoneOnStack(self): frees = [] mapper = PythonMapper(GetAllocatingTestAllocator([], frees)) mapper.tempObjects = Stack[List[IntPtr]]() mapper.tempObjects.Push(None) try: mapper.DecRefLater(IntPtr.Zero) except SystemError: self.fail('DecRefLater should not throw NullReference if tempObjects contains None') finally: mapper.Dispose()
def testRemovesMmapOnDispose(self): mapper = PythonMapper(os.path.join("build", "ironclad", "python26.dll")) try: sys.modules['csv'] = object() mapper.Dispose() self.assertFalse('mmap' in sys.modules) self.assertFalse('_csv' in sys.modules) self.assertFalse('csv' in sys.modules) finally: mapper.Dispose()
def testEasy(self): allocs = [] frees = [] mapper = PythonMapper(GetAllocatingTestAllocator(allocs, frees)) mem1 = getattr(mapper, MALLOC_NAME)(4) del allocs[:] mem2 = getattr(mapper, REALLOC_NAME)(mem1, 8) self.assertEquals(frees, [mem1]) self.assertEquals(allocs, [(mem2, 8)]) mapper.Dispose()
def testReleaseGilDoesntExplodeIfTempObjectsEmpty(self): frees = [] mapper = PythonMapper(GetAllocatingTestAllocator([], frees)) mapper.tempObjects = Stack[List[IntPtr]]() try: mapper.ReleaseGIL() except InvalidOperationException: self.fail('ReleaseGIL should not throw StackEmpty if tempObjects is empty') except Exception: pass finally: mapper.Dispose()
def testCallsAtExitFunctionsOnDispose(self): calls = [] def MangleCall(arg): return Marshal.GetFunctionPointerForDelegate( dgt_void_void(lambda: calls.append(arg))) mapper = PythonMapper() self.assertEquals(mapper.Py_AtExit(MangleCall('foo')), 0) self.assertEquals(mapper.Py_AtExit(MangleCall('bar')), 0) self.assertEquals(calls, []) mapper.Dispose() self.assertEquals(calls, ['bar', 'foo'])
def testReleaseGilDoesntExplodeIfTempObjectsContainsNull(self): frees = [] mapper = PythonMapper(GetAllocatingTestAllocator([], frees)) mapper.tempObjects = Stack[List[IntPtr]]() mapper.tempObjects.Push(None) try: mapper.ReleaseGIL() except SystemError: self.fail('ReleaseGIL should not throw NullReference if tempObjects contains None') except Exception: pass finally: mapper.Dispose()
def testStoreSameObjectIncRefsOriginal(self): frees = [] allocs = [] mapper = PythonMapper(GetAllocatingTestAllocator(allocs, frees)) deallocTypes = CreateTypes(mapper) del allocs[:] obj1 = object() result1 = mapper.Store(obj1) result2 = mapper.Store(obj1) self.assertEquals(allocs, [(result1, Marshal.SizeOf(PyObject))], "unexpected result") self.assertEquals(result1, result2, "did not return same ptr") self.assertEquals(mapper.RefCount(result1), 2, "did not incref") mapper.DecRef(result1) del frees[:] mapper.DecRef(result1) self.assertEquals(frees, [result1], "did not free memory") result3 = mapper.Store(obj1) self.assertEquals( allocs, [(result1, Marshal.SizeOf(PyObject)), (result3, Marshal.SizeOf(PyObject))], "unexpected result -- failed to clear reverse mapping?") mapper.Dispose() deallocTypes()
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 testBasicStoreRetrieveFree(self): frees = [] allocs = [] mapper = PythonMapper(GetAllocatingTestAllocator(allocs, frees)) deallocTypes = CreateTypes(mapper) del allocs[:] obj1 = object() ptr = mapper.Store(obj1) self.assertEquals(len(allocs), 1, "unexpected number of allocations") self.assertEquals(allocs[0], (ptr, Marshal.SizeOf(PyObject)), "unexpected result") self.assertNotEquals(ptr, IntPtr.Zero, "did not store reference") self.assertEquals(mapper.RefCount(ptr), 1, "unexpected refcount") self.assertEquals(CPyMarshal.ReadPtrField(ptr, PyObject, "ob_type"), mapper.PyBaseObject_Type, "nearly-opaque pointer had wrong type") obj2 = mapper.Retrieve(ptr) self.assertTrue(obj1 is obj2, "retrieved wrong object") self.assertEquals(frees, [], "unexpected deallocations") mapper.PyObject_Free(ptr) self.assertEquals(frees, [ptr], "unexpected deallocations") self.assertRaises(KeyError, lambda: mapper.PyObject_Free(ptr)) mapper.Dispose() deallocTypes()
def testDestroysObjectsOfUnmanagedTypesFirst(self): frees = [] mapper = PythonMapper(GetAllocatingTestAllocator([], frees)) deallocTypes = CreateTypes(mapper) modulePtr = MakeAndAddEmptyModule(mapper) module = mapper.Retrieve(modulePtr) calls = [] def Del(instancePtr): calls.append(("del", instancePtr)) mapper.PyObject_Free(instancePtr) typeSpec = {'tp_name': 'klass', 'tp_dealloc': Del} typePtr, deallocType = MakeTypePtr(mapper, typeSpec) mapper.PyModule_AddObject(modulePtr, 'klass', typePtr) easyptr = mapper.Store(123) instance1 = module.klass() hardptr = mapper.Store(instance1) instance2 = module.klass() brokenptr = mapper.Store(instance2) CPyMarshal.WritePtrField(brokenptr, PyObject, 'ob_type', IntPtr.Zero) mapper.Dispose() self.assertEquals( frees.index(hardptr) < frees.index(easyptr), True, "failed to dealloc in correct order") self.assertEquals(calls, [('del', hardptr)], "failed to clean up klass instance") deallocType() deallocTypes()
def testGrow(self): allocs = [] frees = [] mapper = PythonMapper(GetAllocatingTestAllocator(allocs, frees)) deallocTypes = CreateTypes(mapper) del allocs[:] oldLength = 20 testString = "slings and arrows" + self.getStringWithValues(0, 256) newLength = len(testString) oldStrPtr = mapper.PyString_FromStringAndSize(IntPtr.Zero, oldLength) ptrPtr = Marshal.AllocHGlobal(Marshal.SizeOf(IntPtr)) try: Marshal.WriteIntPtr(ptrPtr, oldStrPtr) newStrPtr = IntPtr.Zero baseSize = Marshal.SizeOf(PyStringObject) self.assertEquals(allocs, [(oldStrPtr, oldLength + baseSize)], "allocated wrong") self.assertEquals(mapper._PyString_Resize(ptrPtr, newLength), 0, "bad return on success") newStrPtr = Marshal.ReadIntPtr(ptrPtr) expectedAllocs = [(oldStrPtr, oldLength + baseSize), (newStrPtr, newLength + baseSize)] self.assertEquals(allocs, expectedAllocs, "allocated wrong") self.assertEquals(frees, [oldStrPtr], "did not free unused memory") self.assertHasStringType(newStrPtr, mapper) self.assertStringObjectHasLength(newStrPtr, newLength) testBytes = self.byteArrayFromString(testString) self.fillStringDataWithBytes(newStrPtr, testBytes) self.assertEquals(mapper.Retrieve(newStrPtr), testString, "failed to read string data") if oldStrPtr != newStrPtr: # this would otherwise fail (very, very rarely) self.assertEquals(oldStrPtr in frees, True) finally: mapper.Dispose() Marshal.FreeHGlobal(ptrPtr) deallocTypes()
def test_PyObject_New(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) del allocs[:] objPtr = mapper._PyObject_New(typePtr) self.assertEquals(allocs, [(objPtr, 31337)]) 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 testErrorHandling(self): allocs = [] frees = [] mapper = PythonMapper(GetAllocatingTestAllocator(allocs, frees)) deallocTypes = CreateTypes(mapper) del allocs[:] ptrPtr = Marshal.AllocHGlobal(Marshal.SizeOf(IntPtr)) try: data = mapper.PyString_FromStringAndSize(IntPtr.Zero, 365) Marshal.WriteIntPtr(ptrPtr, data) baseSize = Marshal.SizeOf(PyStringObject) self.assertEquals(allocs, [(data, 365 + baseSize)], "allocated wrong") self.assertEquals(mapper._PyString_Resize(ptrPtr, 2000000000), -1, "bad return on error") self.assertEquals(type(mapper.LastException), MemoryError, "wrong exception type") self.assertTrue(data in frees, "did not deallocate") finally: mapper.Dispose() Marshal.FreeHGlobal(ptrPtr) deallocTypes()
def test_PyTuple_Resize(self): allocs = [] mapper = PythonMapper(GetAllocatingTestAllocator(allocs, [])) tuplePtrPtr = Marshal.AllocHGlobal(CPyMarshal.PtrSize) oldTuplePtr = mapper.PyTuple_New(1) del allocs[:] CPyMarshal.WritePtr(tuplePtrPtr, oldTuplePtr) self.assertEquals(mapper._PyTuple_Resize(tuplePtrPtr, 100), 0) newTuplePtr = CPyMarshal.ReadPtr(tuplePtrPtr) expectedSize = Marshal.SizeOf(PyTupleObject) + (CPyMarshal.PtrSize * (99)) self.assertEquals(allocs, [(newTuplePtr, expectedSize)]) tupleStruct = Marshal.PtrToStructure(newTuplePtr, PyTupleObject) self.assertEquals(tupleStruct.ob_refcnt, 1) self.assertEquals(tupleStruct.ob_type, mapper.PyTuple_Type) self.assertEquals(tupleStruct.ob_size, 100) mapper.Dispose() Marshal.FreeHGlobal(tuplePtrPtr)
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.assertRaisesClr(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()