Search code examples
luaffiluajitlua-lanes

How to convert a luajit pointer to a string and back?


I need some help converting a luajit pointer to a string and back.

First I define the ctype:

ffi.cdef[[
    typedef struct {
        unsigned char Bytes[16];
    } EncryptionKeys[100000000];

void* malloc(size_t);                   
void free(void*);
]]

Then use malloc to allocate some memory and then create the 'EncryptionKeys' variable.

local EncryptionKeyMemoryAddress = ffi.C.malloc(ffi.sizeof("EncryptionKeys"))

local EncryptionKeys = ffi.cast("EncryptionKeys(&)", EncryptionKeyMemoryAddress)

I first convert the variable into a lua string using:

ffi.string(EncryptionKeyMemoryAddress)

But I can't figure out how to convert it back! Can someone please help me?

FYI: I am passing the 'EncryptionKeyMemoryAddress' variable to one of the function parameters for a lua lane (https://lualanes.github.io/lanes/).

Edit: Here is the section of code that I am working on: This is for the client managers module of my server that manages a list of lua states that all have access to any clients connected to the server. They all use a shared section of memory that I want them to have access to using a pointer.



local ClientFFIString = [[
    
    typedef struct {
        unsigned char Bytes[16];
    } EncryptionKeys[100000000];

    void* malloc(size_t);                   
    void free(void*);
]]

ffi.cdef(Matchpools.FFIString)

local EncryptionKeyMemoryAddress = ffi.C.malloc(ffi.sizeof("EncryptionKeys"))

--------------------------------------------
function ClientManagers.CreateNewClientManager()

    local EncryptionKeys = ffi.cast("EncryptionKeys(&)", EncryptionKeyMemoryAddress)

    EncryptionKeys[0].Bytes[0] = 24

    print("___a", EncryptionKeys[0].Bytes[0])


    local NewIndex = #ClientManagers.List+1
    ClientManagers.List[NewIndex] = ClientManagerFunc(
        ClientFFIString, 
        ffi.string(EncryptionKeysMemoryAddress)
    )

end


--------------------------------------------
local ClientManagerFunc = Lanes.gen("*", function(ClientFFIString, EncryptionKeysMemoryAddress)

    ffi = require("ffi")

    ffi.cdef(ClientFFIString)


    local EncryptionKeys = ffi.cast("EncryptionKeys(&)", EncryptionKeyMemoryAddress)
    
    print("___a", EncryptionKeys[0].Bytes[0]) 
    -- I want this to be 24 just like it is in the function that created this lua state


    local ClientManagerRunning = true
    while ClientManagerRunning do

        --local dt = GetDt()

        --UpdateClientData(dt)

        --UpdateMatchmaking(dt)

    end

end)

Solution

  • You can convert Lua string to your structure pointer (and later use it as an array):

    ffi.cdef"typedef struct {unsigned char Bytes[16];} Key;"
    ptr=ffi.cast("Key *", your_string)
    print("First Byte of the First Key in your Array:", ptr[0].Bytes[0])
    

    UPDATE:
    Let's test how it works for an array containing three keys:

    local ffi = require'ffi'
    ffi.cdef"typedef struct {unsigned char Bytes[16];} Key;"
    local your_string = string.char(11):rep(16)..string.char(22):rep(16)..string.char(33):rep(16)
    local ptr=ffi.cast("Key *", your_string)
    print("First Byte of the First Key in your Array:", ptr[0].Bytes[0])
    print("First Byte of the Second Key in your Array:", ptr[1].Bytes[0])
    print("First Byte of the Third Key in your Array:", ptr[2].Bytes[0])
    

    It prints 11, 22, 33


    UPDATE 2:
    Pass the address of buffer instead of the content of buffer

    In the main thread

    -- allocate the buffer
    local Keys = ffi.cast("EncryptionKeys&", ffi.C.malloc(ffi.sizeof("EncryptionKeys")))
    -- write to the buffer
    Keys[2].Bytes[5] = 42
    -- create string containing 64-bit address
    local string_to_send = tostring(ffi.cast("uint64_t", Keys))
    -- Send string_to_send to a lane
    

    Inside the lane

    -- receive the string
    local received_string = .....
    -- restore the buffer pointer
    local Keys = ffi.cast("EncryptionKeys&", loadstring("return "..received_string)())
    -- read the data from the buffer
    print(Keys[2].Bytes[5])