1

I want to solve the following problem. Some C code in a shared library will call a pointer function which is a exported symbol of the shared libary

#include <stdio.h>

typedef void (*pCallBack)(const char *);

pCallBack one_pointer;

void errorPrint(const char * str)
{
   printf("my address = %p", one_pointer);
   fflush(stdout);
   (*one_pointer)(str);
}

let's compile that library as a shared library

gcc -fPIC -g -shared -o  call_back.so call_back.c

And now I want call it from Python, redefining dynamically the implementation of the pCallBack pointer

import ctypes
import sys

def myCallBack(str):
    print("inside python" % str)
    sys.stdout.flush()

libcallback = ctypes.CDLL("./call_back.so")
pointer_CallBack = ctypes.CFUNCTYPE(ctypes.c_void_p, ctypes.c_char_p)
libcallback.one_pointer = pointer_CallBack(myCallBack)
libcallback.errorPrint(b"one_string")

Unfortunately, it seems that the exported data one pointer could not be redefined. I also try in_dll function from ctypes but it does not solve the problem

When a try to run my Python script , I get the following

LD_PRELOAD="./call_back.so" python3 error.py
my address = (nil)[1]    2871869 segmentation fault (core dumped) 

Anyone knows that problem ?

aitzkora
  • 339
  • 1
  • 11

1 Answers1

1

Listing [Python.Docs]: ctypes - A foreign function library for Python.

Using ct.in_dll to modify variables inside the .dll works for simple types (int). I am not aware how to (cleanly) do that for (function) pointers. As a consequence, you need a new function that simply sets the callback.

There are also some errors:

Here's a working example.

dll00.c:

#include <stdio.h>

#if defined(_WIN32)
#  define DLL00_EXPORT_API __declspec(dllexport)
#else
#  define DLL00_EXPORT_API
#endif

typedef void (*CallbackFuncPtr)(const char*);

#if defined(__cplusplus)
extern "C" {
#endif

DLL00_EXPORT_API void setCallback(CallbackFuncPtr cb);
DLL00_EXPORT_API void errorPrint(const char *str);

#if defined(__cplusplus)
}
#endif


CallbackFuncPtr callback = NULL;


void setCallback(CallbackFuncPtr cb) {
    callback = cb;
}

void errorPrint(const char * str) {
    printf("C - Callback: %p\n", callback);
    fflush(stdout);
    if (callback) {
        (*callback)(str);
    }
    printf("C - done\n");
}

code00.py

#!/usr/bin/env python

import sys
import ctypes as ct


DLL_NAME = "./dll00.so"

CallBackType = ct.CFUNCTYPE(None, ct.c_char_p)


def callback_func(s):
    print("PY - callback arg: {:}".format(s))
    sys.stdout.flush()


def main(*argv):
    dll00 = ct.CDLL(DLL_NAME)
    setCallback = dll00.setCallback
    setCallback.argtypes = (CallBackType,)
    setCallback.restype = None
    errorPrint = dll00.errorPrint
    errorPrint.argtypes = (ct.c_char_p,)
    errorPrint.restype = None

    cb = CallBackType.in_dll(dll00, "callback")
    print("Original callback: {:}".format(cb))

    callback = CallBackType(callback_func)
    print("New callback: {:}\n".format(callback))

    errorPrint(b"Before setting callback")
    setCallback(callback)
    errorPrint(b"After setting callback")


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

Output:

[cfati@cfati-5510-0:/mnt/e/Work/Dev/StackOverflow/q067079630]> ~/sopr.sh
*** Set shorter prompt to better fit when pasted in StackOverflow (or other) pages ***

[064bit prompt]> ls
code00.py  dll00.c
[064bit prompt]> gcc -shared -fPIC -o dll00.so dll00.c
[064bit prompt]> ls
code00.py  dll00.c  dll00.so
[064bit prompt]>
[064bit prompt]> python code00.py
Python 3.8.5 (default, Jan 27 2021, 15:41:15) [GCC 9.3.0] 64bit on linux

Original callback: <CFunctionType object at 0x7f07ef740ac0>
New callback: <CFunctionType object at 0x7f07ef740e80>

C - Callback: (nil)
C - done
C - Callback: 0x7f07efffc010
PY - callback arg: b'After setting callback'
C - done

Done.
CristiFati
  • 38,250
  • 9
  • 50
  • 87
  • Thanks a lot : it solved my problem. I was not thinking it was also necessary to write a function setting explicitely the callback. Nice! – aitzkora Apr 15 '21 at 13:05