当前位置: 首页 > 面试题库 >

PYTHON-Ctypes:OSError:异常:访问冲突写入0xFFFFFFFFFA1C001B

靳茂
2023-03-14
问题内容

这是使用内存映射将值写入内存的代码。当我尝试运行代码时, 在memcpy(pBuf,szMsg,len(szMsg))OSError中
出现错误 “文件“ MMF.py”,第26行,OSError:异常:访问冲突写入0xFFFFFFFFFA1C001B”

import msvcrt, mmap
import ctypes
from ctypes import *

FILE_MAP_ALL_ACCESS = 0x04
INVALID_HANDLE_VALUE = 0xFFFFFFFF
SHMEMSIZE = 256
PAGE_READWRITE = 0x04
szName = ctypes.c_wchar_p("MyFileMappingObject")
szMsg = "Message from Python(ctypes) process"

hMapObject = windll.kernel32.CreateFileMappingA(INVALID_HANDLE_VALUE,None, PAGE_READWRITE, 0, SHMEMSIZE, szName)
print("Handle:",hMapObject)
if (hMapObject == 0):
    print("Could not open file mapping object")
    raise WinError()

pBuf = windll.kernel32.MapViewOfFile(hMapObject, FILE_MAP_ALL_ACCESS,0, 0, SHMEMSIZE)
print("Buffer Starting Addr:",pBuf)
if (pBuf == 0):
    print("Could not map view of file")
    raise WinError()
else:
    print(len(szMsg))
    memcpy = cdll.msvcrt.memcpy
    memcpy(pBuf, szMsg, len(szMsg))

shmem = mmap.mmap(0, 256, "MyFileMappingObject_ctypes", mmap.ACCESS_WRITE)
shmem.write("Message Python process")

msvcrt.getch()

windll.kernel32.UnmapViewOfFile(pBuf)
windll.kernel32.CloseHandle(hMapObject)
shmem.close()

问题答案:

在此之前,这里(几乎)是您需要的一切:[Python 3.Docs]:ctypes-
Python的外部函数库
。没有解释 ctypes.wintypes ,但是您可以通过dir(ctypes.wintypes)Python
控制台中运行来查看其导出。请注意,所有这些类型都是简单的 CTypes 类型,仅出于约定/一致性/可读性的目的而使用它们。

您更新的代码( code00.py ):

import sys
import ctypes as ct
import ctypes.wintypes as wt
import mmap
import msvcrt


def main(*argv):
    FILE_MAP_ALL_ACCESS = 0x000F001F
    INVALID_HANDLE_VALUE = -1
    SHMEMSIZE = 0x100
    PAGE_READWRITE = 0x04

    kernel32_dll = ct.windll.kernel32
    msvcrt_dll = ct.cdll.msvcrt  # To be avoided

    CreateFileMapping = kernel32_dll.CreateFileMappingW
    CreateFileMapping.argtypes = (wt.HANDLE, wt.LPVOID, wt.DWORD, wt.DWORD, wt.DWORD, wt.LPCWSTR)
    CreateFileMapping.restype = wt.HANDLE

    MapViewOfFile = kernel32_dll.MapViewOfFile
    MapViewOfFile.argtypes = (wt.HANDLE, wt.DWORD, wt.DWORD, wt.DWORD, ct.c_ulonglong)
    MapViewOfFile.restype = wt.LPVOID

    memcpy = msvcrt_dll.memcpy
    memcpy.argtypes = (ct.c_void_p, ct.c_void_p, ct.c_size_t)
    memcpy.restype = wt.LPVOID

    RtlCopyMemory = kernel32_dll.RtlCopyMemory
    RtlCopyMemory.argtypes = (wt.LPVOID, wt.LPCVOID, ct.c_ulonglong)

    UnmapViewOfFile = kernel32_dll.UnmapViewOfFile
    UnmapViewOfFile.argtypes = (wt.LPCVOID,)
    UnmapViewOfFile.restype = wt.BOOL

    CloseHandle = kernel32_dll.CloseHandle
    CloseHandle.argtypes = (wt.HANDLE,)
    CloseHandle.restype = wt.BOOL

    GetLastError = kernel32_dll.GetLastError

    file_mapping_name_ptr = ct.c_wchar_p("MyFileMappingObject")
    msg = "Message from Python(ctypes) process"
    msg_ptr = ct.c_wchar_p(msg)

    mapping_handle = CreateFileMapping(INVALID_HANDLE_VALUE, 0, PAGE_READWRITE, 0, SHMEMSIZE, file_mapping_name_ptr)

    print("Mapping object handle: 0x{:016X}".format(mapping_handle))
    if not mapping_handle:
        print("Could not open file mapping object: {:d}".format(GetLastError()))
        raise ct.WinError()

    mapped_view_ptr = MapViewOfFile(mapping_handle, FILE_MAP_ALL_ACCESS, 0, 0, SHMEMSIZE)

    print("Mapped view addr: 0x{:016X}".format(mapped_view_ptr))
    if not mapped_view_ptr:
        print("Could not map view of file: {:d}".format(GetLastError()))
        CloseHandle(mapping_handle)
        raise ct.WinError()

    byte_len = len(msg) * ct.sizeof(ct.c_wchar)
    print("Message length: {:d} chars ({:d} bytes)".format(len(msg), byte_len))

    memcpy(mapped_view_ptr, msg_ptr, byte_len)  # Comment this line
    RtlCopyMemory(mapped_view_ptr, msg_ptr, byte_len)

    # Python vriant
    shmem = mmap.mmap(0, 256, "MyFileMappingObject_ctypes", mmap.ACCESS_WRITE)
    shmem.write(b"Message Python process")

    print("Hit a key to clean all memory maps and exit...")
    msvcrt.getch()

    UnmapViewOfFile(mapped_view_ptr)
    CloseHandle(mapping_handle)

    shmem.close()


if __name__ == "__main__":
    print("Python {0:s} {1:d}bit on {2:s}\n".format(" ".join(item.strip() for item in sys.version.split("\n")), 64 if sys.maxsize > 0x100000000 else 32, sys.platform))
    main(*sys.argv[1:])
    print("\nDone.")

注意事项

  • 为函数添加了 argtypesrestype 。详细信息可以在“ 指定所需的参数类型(函数原型) ”和“ 返回类型 ”部分中找到,当然也可以在函数声明的MS.Docs中看到。这是 未定义行为UB ),尤其是在 64位上 :[SO]:通过ctypes从Python调用的C函数返回错误值(@CristiFati的回答)

  • 的memcpy 的2次参数是一个 Python的 字符串,它是 相同的 字符* 地址(更不用说在 Python 3中 ,字符串 为wchar_t 基于),其 的memcpy 预计,这将可能也产生 UB

  • 常数:

    • FILE_MAP_ALL_ACCESS 的值为 0x000F001F (从 VStudio 2015 打印出该值), 0x04 对应于 FILE_MAP_READ

    • INVALID_HANDLE_VALUE 的旧值转换为 HANDLE时 出错,将其更改为-1(如 handleapi.h所示

  • 您正在使用 c_wchar_p 调用 CreateFileMappingA 。,将设置仅由1个的名ST从该映射对象提供的字符串的字符,因为每个 wchar_t的 由2个字节: 0×00 加上相应的 字符 值- “ 甲* ”将被表示为 0×00 0×41 (通常这是 正确-尤其是 0x00 部分,但在我们的例子中是)-因此 lpName 参数中的第二个 字符 (由于 little-endianness )将为 0x00NUL __ *** ______

  • 根据上面的页面:

通过访问标准C库cdll.msvcrt将使用该库的过时版本,该版本可能与Python所使用的版本不兼容。

因此,我还添加了[MS.Docs]:RtlCopyMemory函数来替换 memcpy
(您可以注释掉其行,我在此处保留它只是为了表明它可以工作),如示例中所示([MS.Docs]:创建命名共享内存),你采取了从代码,并试图将其转换([
minwinbase.h#36 ] #define CopyMemory RtlCopyMemory

  • 将命名约定更改为与 Python 兼容([Python]:PEP 8-Python代码样式指南)

  • 其他(非关键)更改(输出格式,为了更好的结构而移动代码行等等)

输出

[cfati@CFATI-5510-0:e:\Work\Dev\StackOverflow\q048788549]>

“e:\Work\Dev\VEnvs\py_pc064_03.07.06_test0\Scripts\python.exe” code00.py
Python 3.7.6 (tags/v3.7.6:43364a7ae0, Dec 19 2019, 00:42:30) [MSC v.1916
64 bit (AMD64)] 64bit on win32

Mapping object handle: 0x000000000000022C
Mapped view addr: 0x00000192912B0000
Message length: 35 chars (70 bytes)
Hit a key to clean all memory maps and exit...

Done.


 类似资料:
  • 当调用glDraweElements()时,我得到了一个错误,我不知道为什么:/I是使用OpenGL的新手,我正在尝试了解它的工作原理。 注意:我正在使用此库将OBJ文件转换为OpenGL应该能够使用的数组:https://github.com/korre/java-obj-to-opengl/blob/master/MeshObjectLoader.java

  • http://www.youtube.com/watch?v=bWl98dhvf8Q我参考了这个网站,并添加了MP4视频到javafx程序,我得到了一个致命的错误,有人请帮我清除这个运行时错误!谢谢你... Java运行时环境检测到一个致命错误:pc=0x6b9589ec,pid=1812,tid=5132 JRE版本:7.0_10-b17 Java VM:Java HotSpot(TM)客户端V

  • 我试图在OSGi(Felix)中使用新的Leap运动传感器,但我最终遇到了一个异常访问冲突。 在我的清单中,我声明捆绑NativeCode如 当然: 在OSGi之外使用相同库的简单程序运行良好 这两个库在“x86”文件夹中的我的包中 “osname=win32;processor=x86”适合我(已经用其他bunble进行了测试) 在反编译Leap Motion jar后,我看到LeapJava.

  • 我试图在C语言中实现一个四叉树,但是我有一个读访问冲突,我花了几个小时试图弄清楚。请注意,我已将所有成员变量公开,仅用于调试工作。 每当我试图细分一个象限,即根象限,我得到 抛出异常:读取访问冲突。标准::_Vector_alloc 四叉树由一个指向连续象限数组的指针和点组成。这些指针被传递到每一个象限,所以它们能够写入而不需要复制。 我做错了什么?你能提出改进的建议吗? 这是我的四叉树类: 四叉

  • 作为一个新的反应者,我被一些看似简单的事情所困扰。不知道我做错了什么。 我有一个组件BasicReactComponent。我喜欢这样: 我试图在我的主文件中调用它,如下所示: 我一直得到下面的错误

  • 尝试使用AWS C++SDK创建SQS队列。 运行在Windows上,64位,VC++。 更改调用以使用AWS::SQS::SQSClient*,将所有NuGet包更新到latets版本(以X.60结束)。这是堆栈跟踪: Testdb.exe!AmazonSQSqueue::AmazonSQSqueue(std::Basic_String,std::Allocator>queueIdentifie