Pythonでmalloc()したメモリへのアクセスを試しました。戻り値を POINTER(c_ubyte) へキャストするとアクセスできます。
※ 例は32bit Windows限定のコードです。UNIX系ではlibcのロード方法が少し違います。
from ctypes import * malloc = cdll.msvcrt.malloc malloc.restype = POINTER(c_ubyte) free = cdll.msvcrt.free printf = cdll.msvcrt.printf p = malloc(4) p[0] = ord("a") p[1] = ord("b") p[2] = ord("c") p[3] = 0 printf(p) free(p)
スライス
POINTERはスライスできません。スライスできるようにするには、サイズを指定したARRAYをPOINTERで包みます。POINTERからARRAYを取り出すため、dereferenceで[0]とします。これらを行うラッパーを用意すれば便利です。
from ctypes import * def malloc(size): malloc = cdll.msvcrt.malloc malloc.restype = POINTER(ARRAY(c_ubyte, size)) return malloc(size)[0] free = cdll.msvcrt.free printf = cdll.msvcrt.printf p = malloc(4) p[:] = [ord("a"), ord("b"), ord("c"), 0] printf(p) free(p)
ARRAYをPOINTERで包まないと戻り値そのものが配列と見なされ、おかしなことになります。
>>> from ctypes import * >>> f = CFUNCTYPE(c_int)(lambda: 0x12345678) >>> f.restype = ARRAY(c_ubyte, 4) >>> map(lambda x: hex(x), f()) ['0x78', '0x56', '0x34', '0x12']
JIT
malloc()の代わりにVirtualAlloc()を使えば、JIT用のバッファに直接マシン語を埋め込むことができます。
def VirtualAlloc(address, size, allocationType, protect): VirtualAlloc = windll.kernel32.VirtualAlloc VirtualAlloc.restype = POINTER(ARRAY(c_ubyte, size)) VirtualAlloc.argtype = [c_void_p, c_size_t, c_int, c_int] return VirtualAlloc(address, size, allocationType, protect)[0]
ARRAYからポインタを取り出す方法は以下を参照してください。