def testReadCStringFieldEmpty(self): data = Marshal.AllocHGlobal(Marshal.SizeOf(PyTypeObject())) CPyMarshal.Zero(data, Marshal.SizeOf(PyTypeObject())) CPyMarshal.WritePtrField(data, PyTypeObject, "tp_doc", IntPtr.Zero) self.assertEquals( CPyMarshal.ReadCStringField(data, PyTypeObject, "tp_doc"), "", "failed to read correctly") Marshal.FreeHGlobal(data)
def testReadPtrField(self): data = Marshal.AllocHGlobal(Marshal.SizeOf(PyTypeObject())) CPyMarshal.Zero(data, Marshal.SizeOf(PyTypeObject())) CPyMarshal.WritePtrField(data, PyTypeObject, "tp_doc", IntPtr(12345)) self.assertEquals( CPyMarshal.ReadPtrField(data, PyTypeObject, "tp_doc"), IntPtr(12345), "failed to read") Marshal.FreeHGlobal(data)
def testReadUIntField(self): data = Marshal.AllocHGlobal(Marshal.SizeOf(PyTypeObject())) CPyMarshal.Zero(data, Marshal.SizeOf(PyTypeObject())) for value in (UInt32.MaxValue, UInt32.MinValue): CPyMarshal.WriteUIntField(data, PyTypeObject, "tp_version_tag", value) self.assertEquals( CPyMarshal.ReadUIntField(data, PyTypeObject, "tp_version_tag"), value, "failed to read") Marshal.FreeHGlobal(data)
def testWriteCStringField(self): data = Marshal.AllocHGlobal(Marshal.SizeOf(PyTypeObject())) CPyMarshal.Zero(data, Marshal.SizeOf(PyTypeObject())) string = "Hey, I am a string. I have tricksy \\escapes\\." CPyMarshal.WriteCStringField(data, PyTypeObject, "tp_doc", string) self.assertEquals( CPyMarshal.ReadCStringField(data, PyTypeObject, "tp_doc"), string, "failed to read correctly") Marshal.FreeHGlobal( CPyMarshal.ReadPtrField(data, PyTypeObject, "tp_doc")) Marshal.FreeHGlobal(data)
def testWriteUIntField(self): data = Marshal.AllocHGlobal(Marshal.SizeOf(PyTypeObject())) CPyMarshal.Zero(data, Marshal.SizeOf(PyTypeObject())) for value in (UInt32.MaxValue, UInt32.MinValue): CPyMarshal.WriteUIntField(data, PyTypeObject, "tp_version_tag", value) dataStruct = PtrToStructure(data, PyTypeObject) self.assertEquals(dataStruct.tp_version_tag, value, "failed to write") Marshal.FreeHGlobal(data)
def CreateTypes(mapper, readyTypes=True): blocks = [] def create(name, size): block = Marshal.AllocHGlobal(size) if name == 'PyFile_Type': CPyMarshal.Zero(block, size) CPyMarshal.WritePtrField(block, PyTypeObject, 'tp_dealloc', mapper.GetFuncPtr('IC_file_dealloc')) mapper.RegisterData(name, block) blocks.append(block) for _type in _types: create(_type, Marshal.SizeOf(PyTypeObject())) for (_other, size) in _others.items(): create(_other, size) if readyTypes: mapper.ReadyBuiltinTypes() def DestroyTypes(): for block in blocks: Marshal.FreeHGlobal(block) return DestroyTypes
def testStoreTypeDictCreatesDictTypeWhichWorks(self, mapper, addToCleanUp): typeBlock = Marshal.AllocHGlobal(Marshal.SizeOf(PyTypeObject())) addToCleanUp(lambda: Marshal.FreeHGlobal(typeBlock)) mapper.RegisterData("PyDict_Type", typeBlock) class klass(object): pass dictPtr = mapper.Store(klass.__dict__) self.assertEquals( CPyMarshal.ReadPtrField(dictPtr, PyObject, "ob_type"), typeBlock, "wrong type") self.assertEquals( mapper.PyDict_SetItemString(dictPtr, 'foo', mapper.Store('bar')), 0) self.assertEquals( mapper.PyDict_SetItem(dictPtr, mapper.Store('baz'), mapper.Store('qux')), 0) self.assertEquals( mapper.Retrieve(mapper.PyDict_GetItemString(dictPtr, 'foo')), 'bar') self.assertEquals( mapper.Retrieve(mapper.PyDict_GetItem(dictPtr, mapper.Store('baz'))), 'qux') self.assertEquals(klass.foo, 'bar') self.assertEquals(klass.baz, 'qux') self.assertEquals(mapper.PyDict_Size(dictPtr), len(klass.__dict__))
def testStoreTupleCreatesTupleType(self): allocs = [] mapper = PythonMapper(GetAllocatingTestAllocator(allocs, [])) typeBlock = Marshal.AllocHGlobal(Marshal.SizeOf(PyTypeObject())) mapper.RegisterData("PyTuple_Type", typeBlock) theTuple = (0, 1, 2) tuplePtr = mapper.Store(theTuple) self.assertEquals( CPyMarshal.ReadPtrField(tuplePtr, PyTupleObject, "ob_type"), typeBlock, "wrong type") dataPtr = OffsetPtr(tuplePtr, Marshal.OffsetOf(PyTupleObject, "ob_item")) for i in range(3): item = mapper.Retrieve(CPyMarshal.ReadPtr(dataPtr)) self.assertEquals(item, i, "did not store data") dataPtr = OffsetPtr(dataPtr, CPyMarshal.PtrSize) tuplePtr2 = mapper.Store(theTuple) self.assertEquals(tuplePtr2, tuplePtr, "didn't realise already had this tuple") self.assertEquals(mapper.RefCount(tuplePtr), 2, "didn't incref") mapper.Dispose() Marshal.FreeHGlobal(typeBlock)
def testPyFile_Type(self, mapper, addToCleanUp): typeBlock = Marshal.AllocHGlobal(Marshal.SizeOf(PyTypeObject())) addToCleanUp(lambda: Marshal.FreeHGlobal(typeBlock)) mapper.RegisterData("PyFile_Type", typeBlock) self.assertEquals(mapper.PyFile_Type, typeBlock, "type address not stored") self.assertEquals(mapper.Retrieve(typeBlock), file, "type not mapped")
def assertFindsType(self, name): class MyPM(PythonApi): def fillmethod(self, address): WritePyTypeObject(address) setattr(MyPM, "Register_" + name, getattr(MyPM, "fillmethod")) self.assertDataSetterSetsAndRemembers(MyPM, name, Marshal.SizeOf(PyTypeObject()), TestWrotePyTypeObject)
def testStoreDictCreatesDictType(self, mapper, addToCleanUp): typeBlock = Marshal.AllocHGlobal(Marshal.SizeOf(PyTypeObject())) addToCleanUp(lambda: Marshal.FreeHGlobal(typeBlock)) mapper.RegisterData("PyDict_Type", typeBlock) dictPtr = mapper.Store({0: 1, 2: 3}) self.assertEquals( CPyMarshal.ReadPtrField(dictPtr, PyObject, "ob_type"), typeBlock, "wrong type")
def testReadFunctionPtrField(self): data = Marshal.AllocHGlobal(Marshal.SizeOf(PyTypeObject())) CPyMarshal.Zero(data, Marshal.SizeOf(PyTypeObject())) calls = [] def TestFunc(selfPtr, argsPtr, kwargsPtr): calls.append((selfPtr, argsPtr, kwargsPtr)) return 123 self.testDgt = dgt_int_ptrptrptr(TestFunc) CPyMarshal.WriteFunctionPtrField(data, PyTypeObject, "tp_init", self.testDgt) readDgt = CPyMarshal.ReadFunctionPtrField(data, PyTypeObject, "tp_init", dgt_int_ptrptrptr) args = (IntPtr(111), IntPtr(222), IntPtr(333)) self.assertEquals(readDgt(*args), 123, "not hooked up") self.assertEquals(calls, [args], "not hooked up")
def testCreateEllipsis(self, mapper, addToCleanUp): ellipsisTypePtr = Marshal.AllocHGlobal(Marshal.SizeOf(PyTypeObject())) addToCleanUp(lambda: Marshal.FreeHGlobal(ellipsisTypePtr)) ellipsisPtr = Marshal.AllocHGlobal(Marshal.SizeOf(PyObject())) addToCleanUp(lambda: Marshal.FreeHGlobal(ellipsisPtr)) mapper.RegisterData("PyEllipsis_Type", ellipsisTypePtr) mapper.RegisterData("_Py_EllipsisObject", ellipsisPtr) self.assertEquals( CPyMarshal.ReadPtrField(ellipsisPtr, PyObject, "ob_type"), mapper.PyEllipsis_Type) self.assertEquals( CPyMarshal.ReadIntField(ellipsisPtr, PyObject, "ob_refcnt"), 1) self.assertEquals(mapper.Store(Ellipsis), ellipsisPtr) self.assertEquals(mapper.RefCount(ellipsisPtr), 2)
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")
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 testFinalDecRefComplainsAboutMissing_tp_dealloc(self): frees = [] mapper = PythonMapper(GetAllocatingTestAllocator([], frees)) deallocTypes = CreateTypes(mapper) typePtr = Marshal.AllocHGlobal(Marshal.SizeOf(PyTypeObject())) CPyMarshal.WritePtrField(typePtr, PyTypeObject, "tp_dealloc", IntPtr.Zero) obj = object() objPtr = mapper.Store(obj) CPyMarshal.WritePtrField(objPtr, PyObject, "ob_type", typePtr) mapper.IncRef(objPtr) del frees [:] mapper.DecRef(objPtr) self.assertEquals(frees, [], "freed prematurely") self.assertRaisesClr(CannotInterpretException, mapper.DecRef, objPtr) mapper.Dispose() deallocTypes()
def testPyListTypeField_tp_dealloc(self): calls = [] class MyPM(PythonMapper): def IC_PyList_Dealloc(self, listPtr): calls.append(listPtr) mapper = MyPM() typeBlock = Marshal.AllocHGlobal(Marshal.SizeOf(PyTypeObject())) mapper.RegisterData("PyList_Type", typeBlock) gcwait( ) # this will make the function pointers invalid if we forgot to store references to the delegates deallocDgt = CPyMarshal.ReadFunctionPtrField(typeBlock, PyTypeObject, "tp_dealloc", dgt_void_ptr) deallocDgt(IntPtr(12345)) self.assertEquals(calls, [IntPtr(12345)], "wrong calls") mapper.Dispose() Marshal.FreeHGlobal(typeBlock)
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 = 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 MakeTypePtr(mapper, params, allocator=None): fields = dict(MAKETYPEPTR_DEFAULTS) fields.update(GetMapperTypePtrDefaults(mapper)) fields.update(params) deallocs = [] typeSize = Marshal.SizeOf(PyTypeObject()) if allocator: # pretend this was constructed by a C extension, using the mapper's allocator # hence mapper should do the deallocation itself typePtr = allocator.Alloc(typeSize) else: typePtr = Marshal.AllocHGlobal(typeSize) deallocs.append(lambda: Marshal.FreeHGlobal(typePtr)) CPyMarshal.Zero(typePtr, typeSize) for field, value in fields.items(): deallocs.append(WriteTypeField(typePtr, field, value)) def dealloc(): for f in deallocs: f() return typePtr, dealloc
return TestWroteBytes def GetWriteBytes(bytes): intCount = bytes / CPyMarshal.IntSize def WriteBytes(address): for a in range(intCount): ptr = OffsetPtr(address, a * CPyMarshal.IntSize) Marshal.WriteInt32(ptr, TEST_NUMBER) return WriteBytes WritePyTypeObject = GetWriteBytes(Marshal.SizeOf(PyTypeObject())) TestWrotePyTypeObject = GetTestWroteBytes(Marshal.SizeOf(PyTypeObject())) WritePyObject = GetWriteBytes(Marshal.SizeOf(PyObject())) TestWrotePyObject = GetTestWroteBytes(Marshal.SizeOf(PyObject())) WritePtr = GetWriteBytes(Marshal.SizeOf(IntPtr())) TestWrotePtr = GetTestWroteBytes(Marshal.SizeOf(IntPtr())) TYPES = ( "PyBool_Type", "PyClass_Type", "PyInstance_Type", "PyMethod_Type", "PyComplex_Type", "PyWrapperDescr_Type",