7

I want to read in a Python script a number of bytes starting from a specific address. E.g., I want to read 40000 bytes starting from 0x561124456.

The pointer is given from a C# app. I want to use this method to pass data between the app and script. I've used a TCP socket via localhost, but I want to try this method also.

How can I do this?

Cristian M
  • 715
  • 2
  • 12
  • 32
  • 1
    Why do you want to do this? Python does not have pointers. What is responsible for putting those bytes at that address in the first place? – Daniel Roseman Feb 15 '18 at 13:57
  • @DanielRoseman I've updated the question. – Cristian M Feb 15 '18 at 14:02
  • I wonder if [`ctypes..from_address`](https://docs.python.org/3/library/ctypes.html#ctypes._CData.from_address) would be useful here? Having just tried it twice, I got `OverflowError` and a hard crash with no exception, but maybe there's some way to avoid those. – Kevin Feb 15 '18 at 14:03
  • Yeah, putting data into a memory location isn't a good way of passing between applications. That is what sockets are for. – Daniel Roseman Feb 15 '18 at 14:55
  • @DanielRoseman Why isn't it a good way? I can make the the buffer fixed, so it isn't deallocated and I pass the pointer to the script. I think this method is faster than using a socket through localhost whose performance is limited by the CPU and TCP/IP stack performance. – Cristian M Feb 16 '18 at 06:13

3 Answers3

10

If you really want to, enjoy:

import ctypes
g = (ctypes.c_char*40000).from_address(0x561124456)

Looks like segfault fun. There are good socket-connection libraries on both languages (sockets, RPC etc...), so I would think about this again if this is for some large project.

kabanus
  • 24,623
  • 6
  • 41
  • 74
4

Once I got a pointer of memory location from C, I found "list(listSize * listDataType).from_address(memoryPointer)" created a internal copy of C memeory. If the data in memory is huge, Python takes a long time to create a list object by using internal copy. To avoid internal copy, I used the ctypelib.as_array in python:

import ctypes
import binascii
import numpy as np

myCfunslib.getData.restype = ctypes.c_void_p
#myCfunslib.getData.restype=ctypes.POINTER(ctypes.c_ubyte)#no need to cast
dataSize = 1092 * 1208
#call the c function to get the data memory pointer
cMemoryPointer = myCfunslib.getData();
newpnt = ctypes.cast(cMemoryPointer, ctypes.POINTER(ctypes.c_ubyte))
# and construct an array using this data
DataBytes = np.ctypeslib.as_array(newpnt, (dataSize,)) #no internal copy
print "the mid byte of the data in python side is ", DataBytes[dataSize/2]
Hannah Zhang
  • 489
  • 5
  • 5
  • works great. would love to find a way w/o bringing in all of numpy. i tried to peek at how it was done inside numpy and bit over my head. – lazieburd Feb 03 '23 at 13:32
1

I happened to work on the similar issue. My python script load .so library to get an image buffer address from c++ .so. After I got the buffer address, I need to be able to read each byte in the buffer. I used "from_address" to create a list object:

imageBytes = list(c_ubyte * dataSize).from_address(pointer)

The following shows the details how to get memory address passed from c++ to pyth and how to access the memory data on python side too. In c++ code frameprovider.cpp:

dataPackPtr = new DataPack(); 

DataPack * getFrame(){
    uint32_t width = 1920;
    uint32_t height = 1208;
    const size_t buffersize = width * height * 4;//rgba, each color is one byte
    unsigned char* rgbaImage = (unsigned char * )malloc(buffersize);
    memset(rgbaImage, 0, buffersize); // set all the buffer data to 0.
    dataPackPtr->width = width;
    dataPackPtr->height = height;
    dataPackPtr->buffersize = buffersize;
    dataPackPtr->bufferPtr = rgbaImage;
    return dataPackPtr;
}

extern "C" {
    DataPack* getFrame_wrapper(){
        return getFrame();
    }
}

My python:

import ctypes
import binascii
lib = ctypes.cdll.LoadLibrary('/libpath/frameprovider.so')
print vars(lib)

class dataPack(ctypes.Structure):
    _fields_ = [("width",ctypes.c_int),
                ("height",ctypes.c_int),
                ("buffersize",ctypes.c_int),
                ("bufferAddress", ctypes.c_void_p)]

lib.getFrame_wrapper.restype = ctypes.POINTER(dataPack)
data = lib.getFrame_wrapper()
print "in python the w= ", data.contents.width, "h=",data.contents.height
print "the buffersize=",data.contents.height
imageBytes = list(
(data.contents.buffersize * ctypes.c_ubyte).
 from_address(data.contents.bufferAddress))        

print "the len of imageBytes are ", len(imageBytes)
print imageBytes[data.contents.buffersize -1] #print the last byte in the buffer
print "in python, the hex value of element 12 is ", hex(imageBytes[12])
Hannah Zhang
  • 489
  • 5
  • 5