PYTHON - Ctypes : OSError: exception: access violation writing 0xFFFFFFFFFA1C001B

Before anything, here's (almost) everything that you need: [Python 3]: ctypes - A foreign function library for Python. ctypes.wintypes is not explained, but you can see its exports by running dir(ctypes.wintypes) in the Python console. Note that all these types are simple ctypes types, I use them just for convention / consistency / readability's sake.

Your updated code (code.py):

#!/usr/bin/env python3

import sys
from ctypes import windll, cdll,\
    c_wchar, c_size_t, c_ulonglong, c_wchar_p, c_void_p,\
    sizeof,\
    WinError
from ctypes.wintypes import BOOL, DWORD, HANDLE, LPCWSTR, LPCVOID, LPVOID
import mmap


if __name__ == "__main__":
    print("Python {:s} on {:s}".format(sys.version, sys.platform))
    FILE_MAP_ALL_ACCESS = 0x000F001F
    INVALID_HANDLE_VALUE = -1
    SHMEMSIZE = 0x100
    PAGE_READWRITE = 0x04


    kernel32_dll = windll.kernel32
    msvcrt_dll = cdll.msvcrt


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

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

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

    rtl_copy_memory_func = kernel32_dll.RtlCopyMemory
    rtl_copy_memory_func.argtypes = (LPVOID, LPCVOID, c_ulonglong)

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

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

    get_last_error_func = kernel32_dll.GetLastError
    getch_func = msvcrt_dll._getch


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

    mapping_handle = create_file_mapping_func(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(get_last_error_func()))
        raise WinError()

    mapped_view_ptr = map_view_of_file_func(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(get_last_error_func()))
        close_handle_func(mapping_handle)
        raise WinError()

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

    memcpy_func(mapped_view_ptr, msg_ptr, byte_len)
    rtl_copy_memory_func(mapped_view_ptr, msg_ptr, byte_len)

    unmap_view_of_file_func(mapped_view_ptr)
    close_handle_func(mapping_handle)


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


    print("Hit a key to exit...")
    getch_func()

Notes:

  • Added the argtypes and restype for the functions. Details can be seen in the "Specifying the required argument types (function prototypes)" and "Return types" sections, and of course MSDN for function declarations
  • memcpy's 2nd argument is a Python string, which is not the same its char * address (not to mention that in Python 3, strings are wchar_t based) that memcpy expects, this will probably yield Undefined Behavior
  • FILE_MAP_ALL_ACCESS's value is 0x000F001F (printed out the value from VStudio 2015), 0x04 corresponds to FILE_MAP_READ
  • Error converting INVALID_HANDLE_VALUE's old value to HANDLE, changed it to -1 (as in handleapi.h)
  • You're calling CreateFileMappingA with a c_wchar_p. That will set a name consisting of only the 1st character from the supplied string for the mapping object because each wcha_t consists of 2 bytes: 0x00 plus the corresponding char value - 'A' will be represented as 0x00 0x41 (generally this is not true - especially the 0x00 part, but in our case, it is) - so the 2nd char in the lpName argument (due to little-endianness) will be 0x00 (NULL)
  • No need to import msvcrt module, just for _getch which is also exposed by vcruntime140.dll (ucrtbase.dll)
  • According to the page above:

    Accessing the standard C library through cdll.msvcrt will use an outdated version of the library that may be incompatible with the one being used by Python.

    So, I also added [Docs.MS]: RtlCopyMemory function to replace memcpy (you can comment out its line, I left it there just to show that it works), as in the example ([MS.Docs]: Creating Named Shared Memory) that you took the code from, and tried to convert it ([minwinbase.h: 36]: #define CopyMemory RtlCopyMemory)

  • Changed naming convention to be Python compliant ([Python]: PEP 8 -- Style Guide for Python Code)
  • Other (non critical) changes (output formatting, moving lines of code around for a better structure, and so on ...)

Output:

(py35x64_test) E:\Work\Dev\StackOverflow\q048788549>"e:\Work\Dev\VEnvs\py35x64_test\Scripts\python.exe" code.py
Python 3.5.4 (v3.5.4:3f56838, Aug  8 2017, 02:17:05) [MSC v.1900 64 bit (AMD64)] on win32
Mapping object handle: 0x000000000000012C
Mapped view addr: 0x00000206E3BD0000
Message length: 35 chars (70 bytes)
Hit a key to exit...