def assertTypeDeallocWorks(self, typename, CreateMapper, CreateInstance, TestConsequences): mapper = CreateMapper() deallocTypes = CreateTypes(mapper) calls = [] def tp_free(ptr): calls.append(("tp_free", ptr)) self.tp_freeDgt = dgt_void_ptr(tp_free) CPyMarshal.WriteFunctionPtrField(getattr(mapper, typename), PyTypeObject, "tp_free", self.tp_freeDgt) objPtr = CreateInstance(mapper, calls) deallocDgt = CPyMarshal.ReadFunctionPtrField(getattr(mapper, typename), PyTypeObject, "tp_dealloc", dgt_void_ptr) deallocDgt(objPtr) TestConsequences(mapper, objPtr, calls) mapper.Dispose() deallocTypes()
def testPySlice_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.PySlice_Type, PyTypeObject, "tp_free", freeDgt) slicePtr = mapper.Store(slice(1, 2, 3)) del frees[:] mapper.IC_PySlice_Dealloc(slicePtr) self.assertEquals(len(frees), 3, "did not dealloc each item") self.assertEquals(calls, [slicePtr], "did not call type's free function") mapper.PyObject_Free(slicePtr) mapper.Dispose() 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 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 testIC_PyFile_AsFile_Write(self, mapper, addToCleanUp, _): testDir = tempfile.mkdtemp() addToCleanUp(lambda: shutil.rmtree(testDir)) path = os.path.join(testDir, "test") testStr = "meh, string data" testLength = len(testStr) testStrPtr = mapper.Store(testStr) testDataPtr = OffsetPtr(testStrPtr, Marshal.OffsetOf(PyStringObject, "ob_sval")) filePtr = mapper.Store(open(path, 'w')) f = mapper.IC_PyFile_AsFile(filePtr) self.assertEquals(Unmanaged.fwrite(testDataPtr, 1, testLength, f), testLength, "didn't work") # nasty test: patch out PyObject_Free # the memory will not be deallocated, but the FILE handle should be calls = [] def Free(ptr): calls.append(ptr) freeDgt = dgt_void_ptr(Free) CPyMarshal.WriteFunctionPtrField(mapper.PyFile_Type, PyTypeObject, 'tp_free', freeDgt) mapper.DecRef(filePtr) self.assertEquals(calls, [filePtr], 'failed to call tp_free function') mgdF = open(path) result = mgdF.read() self.assertEquals(result, testStr, "failed to write (got >>%s<<) -- deallocing filePtr did not close FILE" % result) mgdF.close()
def testPyBaseObject_TypeDeallocCallsObjTypesFreeFunction(self, mapper, addToCleanUp): calls = [] def Some_FreeFunc(objPtr): calls.append(objPtr) self.freeDgt = dgt_void_ptr(Some_FreeFunc) baseObjTypeBlock = mapper.PyBaseObject_Type objTypeBlock = mapper.PyDict_Type # type not actually important objPtr = Marshal.AllocHGlobal(Marshal.SizeOf(PyObject())) addToCleanUp(lambda: Marshal.FreeHGlobal(objPtr)) CPyMarshal.WriteFunctionPtrField(objTypeBlock, PyTypeObject, "tp_free", self.freeDgt) CPyMarshal.WritePtrField(objPtr, PyObject, "ob_type", objTypeBlock) gcwait() # this should make the function pointers invalid if we forgot to store references to the delegates mapper.IC_PyBaseObject_Dealloc(objPtr) self.assertEquals(calls, [objPtr], "wrong calls")
def testFinalDecRefOfObjectWithTypeCalls_tp_dealloc(self, mapper, _): calls = [] def TypeDealloc(ptr): calls.append(ptr) deallocDgt = dgt_void_ptr(TypeDealloc) deallocFP = Marshal.GetFunctionPointerForDelegate(deallocDgt) typePtr = Marshal.AllocHGlobal(Marshal.SizeOf(PyTypeObject())) deallocPtr = CPyMarshal.Offset(typePtr, Marshal.OffsetOf(PyTypeObject, "tp_dealloc")) CPyMarshal.WritePtr(deallocPtr, deallocFP) obj = object() objPtr = mapper.Store(obj) CPyMarshal.WritePtrField(objPtr, PyObject, "ob_type", typePtr) mapper.IncRef(objPtr) mapper.DecRef(objPtr) self.assertEquals(calls, [], "called prematurely") mapper.DecRef(objPtr) self.assertEquals(calls, [objPtr], "not called when refcount hit 0")