无法通过LD_PRELOAD拦截PyDict_New
我正在尝试使用LD_PRELOAD来拦截PyDict_New这个函数。我已经验证过,这个方法在Python解释器中使用getpid是有效的,所以我把它改成了用PyDict_New,但结果却没有达到我的预期。虽然我确实在分配字典,而且这个函数肯定会被调用,但我的重写函数并没有被触发。
我哪里出错了呢?
背景:我正在尝试调试一个非常大的系统中的问题。我发现有一个字典的引用计数不对。我知道这个字典是在哪里首次分配的,也知道问题出现的地方,但我很确定这个计数在某个中间时间出现了问题,而简单的代码追踪是没用的,因为这个字典是被gc系统缓存并重复使用的(通过PyDict_New)。
2 个回答
1
我觉得在你的情况下,直接下载适合你版本的Python源代码,然后在调试模式下构建它,再用这个版本来运行你的应用程序,会简单很多。
这种方法能让你在调试问题时更加灵活。比如,你可以在PyDict_New
这个函数里设置条件断点,或者直接用你自己的版本来替换它。
3
LD_PRELOAD 只能重载那些动态加载的函数。如果你在使用 Python 的二进制文件,PyDict_New 这个函数并不是动态加载的,所以动态加载器无法拦截到这个符号的解析。如果你自己编译一个“python”程序,并且链接 libpython.so,这样就可以实现了。下面是你需要在程序中写的内容(/tmp/foo.c):
#include "Python.h"
int
main(int argc, char **argv)
{
return Py_Main(argc, argv);
}
然后你可以用下面的命令来编译它: gcc -o foo -I/usr/include/python2.7 foo.c -lpython2.7
完成这些后,在 ./foo 上使用 LD_PRELOAD 就可以正常工作了。