Any way to call c / C ++ code from python without changing c / C ++ code?

Edited: I am wrapping a custom python dll with the goal of permanently deleting custom code and using recent python instead of the old version that is currently in use. One of the functions initializes the python extension and calls

PyObject* _PyObject_New(PyTypeObject *type) 

In my shell, the object (c) created by this call breaks into PyErr_Print() (yes, I wrapped it too).

I would like to experiment with replacing the Repr or Str calls with what I chose to see if they are guilty. Also, I cannot use capsules because objects must be accessible even in python code.

On request: a real problem occurs where one of the two internal pointers is called c. I took the source python 2.7.1, opened in VS 2003 (the project is on PC / VS 7.1), opened pythonrun.c there and added the stubs of the triple functions at the end:

  static CHAR gameHome[MAX_PATH + 1] = { 0 }; __declspec (dllexport) void Py_SetGameInterface(){ //Set the path here unsigned long nChars; nChars = GetModuleFileName(NULL, gameHome, MAX_PATH); if(nChars <= 0){ printf("Failed getting the exe path\n"); return; } for( ; nChars > 0; nChars--){ //think windows accepts both if(gameHome[nChars]=='\\' || gameHome[nChars]=='/'){ break; } } if(nChars == 0){ printf("Failed getting the python path\n"); return; } strcpy(&gameHome[nChars+1],"Bin\\python\0"); Py_SetPythonHome(gameHome); } /* this was deprecated in python 2.3 but vampire needs it */ #undef _PyObject_Del __declspec (dllexport) void _PyObject_Del(PyObject *op) { PyObject_FREE(op); } //original returns the number of chars output //if you give it a char* youll receive what was written but that //looks like a accident of the stack __declspec (dllexport) int Py_FlushConsoleOutput(){ return 0; } __declspec (dllexport) int PyRun_ConsoleString(char * str, int typeOfExpression, PyObject * globals, PyObject * locals){ PyObject* ret = NULL; printf("Console String: %s, size %d\n", str, strlen(str)); if(PyErr_Occurred() != NULL){ printf("WTF ERROR\n%s", PyString_AsString(PyObject_Str(PyErr_Occurred()))); PyErr_Clear(); } //trying to run dir(cvar) crashes here ret = PyRun_String(str, typeOfExpression, globals, locals); if(ret != NULL){ Py_DECREF(ret); } //ret crashes with non null ret return 0; } #undef PyRun_String PyAPI_FUNC(PyObject *) PyRun_String(char *str, int s, PyObject *g, PyObject *l) { PyObject* r; if(PyErr_Occurred() != NULL){ printf("WTF ERROR\n%s", PyString_AsString(PyObject_Str(PyErr_Occurred()))); PyErr_Clear(); } r = PyRun_StringFlags(str, s, g, l, NULL); if(r != NULL && PyBool_Check(r)){ //newer python defined a bool value but bloodlines is //not accepting it somehow (though bool is a subclass of int) if(r == Py_True) return PyInt_FromLong(1L); else return PyInt_FromLong(0L); } return r; } 

Create a solution, but delete python subprojects that don't work (they are not needed)

put this bash file in the Game / Bin directory (where the python dll lives)

 cp -f /home/paulo/OS\ Images/shared/Python-2.7.1/PC/VS7.1/python27.dll ./vampire_python21.dll cp -f /home/paulo/OS\ Images/shared/Python-2.7.1/PC/VS7.1/unicodedata.pyd ./python/unicodedata.pyd cp -f /home/paulo/OS\ Images/shared/Python-2.7.1/PC/VS7.1/_ctypes.pyd ./python/_ctypes.pyd cp -f /home/paulo/OS\ Images/shared/Python-2.7.1/PC/VS7.1/select.pyd ./python/select.pyd cp -f /home/paulo/OS\ Images/shared/Python-2.7.1/PC/VS7.1/winsound.pyd ./python/winsound.pyd cp -f /home/paulo/OS\ Images/shared/Python-2.7.1/PC/VS7.1/python.exe ./python/python.exe cp -f /home/paulo/OS\ Images/shared/Python-2.7.1/PC/VS7.1/pythonw.exe ./python/pythonw.exe cp -f /home/paulo/OS\ Images/shared/Python-2.7.1/PC/VS7.1/w9xpopen.exe ./python/w9xpopen.exe rm -R ./python/Lib cp -R /home/paulo/OS\ Images/shared/Python-2.7.1/Lib ./python/Lib find ../ -name '*.pyc' -delete export PYTHONVERBOSE=1; wine ../vampire.exe -console 1 

compiled and launched. The game is opened using the console, and if you type dir(cvar) , it will crash after creating the AST during startup / printing of the code (sorry the wine does not understand the debug symbols of VS). Curiously, the other dir (ccmd) internal pointer does not break, but may have some clues about what is wrong with the other:

 [] Console String: __dict__, size 8 Traceback (most recent call last): File "<string>", line 1, in <module> NameError: name '__dict__' is not defined Console String: __members__, size 11 Traceback (most recent call last): File "<string>", line 1, in <module> NameError: name '__members__' is not defined Console String: __methods__, size 11 Traceback (most recent call last): File "<string>", line 1, in <module> NameError: name '__methods__' is not defined Console String: __class__, size 9 Traceback (most recent call last): File "<string>", line 1, in <module> NameError: name '__class__' is not defined 

Note that it crashes before (EDIT: in fact, it is called again. Exceptions in python C api? Need to be investigated. EDIT2: in fact, this only happens in the command "dir (ccmd)" not on "(cvar ) ", which immediately crashes) returns and that this function is console-specific. There may be many changes that I do not know about.

"print ccmd", "str (ccmd)" or "repr (ccmd)" on the console gives:

 <cvar object at 0x0245E4A8> 

and "print cvar", "str (cvar)" or "repr (cvar)" gives

 <cvar object at 0x0245E4A0> 

Also note that I do not know what the return of the ConsoleString function ConsoleString , but I know that it tests against 0 (NULL) in the return assembly for the if if branch.

EDIT: OK, found a crash point by applying a debugger to the application on crash: This is line 3963 of type object.c on source python 2.7.1,

 if (base && base->tp_dict == NULL) 

The base is not null, but access to this dictionary will cause the interpreter to crash. Should I send an error report?

+4
source share

Source: https://habr.com/ru/post/1342891/


All Articles