Here is a small reproducer, instructions at top of file:
// file custom.c
//
// PYVERSION=3.9 will print "my_vectorcallfunc", whereas PYVERSION=3.11 will not. This is the problem I am running into.
// To compile:
// PYVERSION=3.11; gcc -fPIC -shared -o custom.so -I /usr/include/python${PYVERSION}/ custom.c -L /usr/lib64/python${PYVERSION}/config-${PYVERSION}-x86_64-linux-gnu/ -lpython${PYVERSION}
// To run:
// LD_LIBRARY_PATH=LD_LIBRARY_PATH:/usr/lib64/python${PYVERSION}/ python${PYVERSION} -c 'import custom; import os.path; custom.custom_function(os.path.realpath); print(os.path.realpath("abc/123"))'
#include <Python.h>
#include <stdio.h>
static PyObject *(*old_vectorcall)(PyObject *callable, PyObject *const *args, size_t nargsf, PyObject *kwnames);
static PyObject *my_vectorcallfunc(PyObject *callable, PyObject *const *args, size_t nargsf, PyObject *kwnames){
printf("%s\n",__func__);
return old_vectorcall(callable, args, nargsf, kwnames);
}
static PyObject* custom_function(PyObject* self, PyObject* args) {
PyFunctionObject *args_func = (PyFunctionObject *) PyTuple_GET_ITEM(args, 0);
old_vectorcall = args_func->vectorcall;
args_func->vectorcall = (vectorcallfunc) my_vectorcallfunc;
PyObject_Print(self, stdout, Py_PRINT_RAW);
printf("\n1\n");
PyObject_Print(args, stdout, Py_PRINT_RAW);
printf("\n2\n");
return args;
}
static PyMethodDef custom_methods[] = {
{"custom_function", custom_function, METH_VARARGS, "Description of custom_function"},
{NULL, NULL, 0, NULL}
};
static struct PyModuleDef custommodule = {
PyModuleDef_HEAD_INIT,
"custom",
"Module documentation",
-1,
custom_methods
};
PyMODINIT_FUNC PyInit_custom(void) {
return PyModule_Create(&custommodule);
}
@encukou you’ve replied to my other posts. Do you have any ideas what’s going wrong, or how to work around it?
Another peculiarity is that with Python3.11, PyObject_CallObject does call my_vectorcallfunc, even though a normal call to os.path.realpath doesn’t:
// before custom_function's "return args;"
PyObject *tuple = PyTuple_Pack(1, PyUnicode_FromString("def/456"));
PyObject_CallObject((PyObject*) args_func, tuple); // prints "my_vectorcallfunc"