编辑完成:我包装了一个自定义 python dll,目的是最终删除自定义代码并使用最近的 python 而不是现在使用的旧版本。其中一个函数初始化一个 python 扩展,并调用
PyObject* _PyObject_New(PyTypeObject *type)
在我的包装器中,此调用产生的 (c) 对象正在崩溃PyErr_Print()
(是的,我也已经包装了它)。
我想尝试将 Repr 或 Str 调用替换为我选择的某些东西,看看它们是否有罪。另外,我不能使用胶囊,因为即使在 python 代码上也应该可以使用这些对象。
根据要求:真正的问题发生在两个 c 本机指针之一被调用的地方。我拿了 python 2.7.1 源代码,在 VS 2003 上打开(项目在 PC/VS7.1 上),在pythonrun.c
那里打开并在最后添加了三驾马车函数的存根:
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;
}
构建解决方案但删除了不起作用的 python 子项目(不需要它们)
将此 bash 文件放在 Game/Bin 目录(python dll 所在的位置)
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
编译并运行。游戏使用控制台打开,如果您dir(cvar)
在运行/打印代码期间创建 AST 后键入它会崩溃(抱歉,wine 不理解 VS 调试符号)。奇怪的是,另一个本机指针“dir(ccmd)”并没有崩溃,但可能有一些线索表明另一个有什么问题:
[]
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
请注意,它在之前崩溃(编辑:实际上,它以某种方式再次被调用。python C api 中的异常?需要调查。EDIT2:实际上这只发生在“dir(ccmd)”命令中,而不是“dir(cvar) ",立即崩溃)返回并且此功能是特定于控制台的。很可能还有更多我不知道的改动。
控制台上的“print ccmd”、“str(ccmd)”或“repr(ccmd)”给出:
<cvar object at 0x0245E4A8>
“print cvar”、“str(cvar)”或“repr(cvar)”给出
<cvar object at 0x0245E4A0>
另请注意,我不知道ConsoleString
函数的返回是什么,但我知道它正在测试返回程序集上的 0 (NULL) 以分支 if。
编辑:好的,通过在崩溃时将调试器应用于附加来找到崩溃点:它是 python 2.7.1 源代码上 typeobject.c 的第 3963 行,
if (base && base->tp_dict == NULL)
Base 不为空,但访问该字典会使解释器崩溃。我应该发送错误报告吗?