【问题标题】:can't intercept PyDict_New with LD_PRELOAD无法使用 LD_PRELOAD 拦截 PyDict_New
【发布时间】:2011-12-18 03:45:56
【问题描述】:

我正在尝试使用 LD_PRELOAD 来拦截 PyDict_New 函数。我已经验证 this recipe 在 python 解释器中与 getpid 一起工作,而我已经 adapted it to use PyDict_New 代替,但它根本不像我预期的那样工作。虽然我清楚地分配了字典,并且必须使用这个函数,但我的覆盖没有被调用。

我做错了什么?


背景:我正在尝试在一个非常大的系统中调试问题。我发现有一个引用计数错误的字典。我知道字典第一次分配的位置,以及问题出现的位置,但我很确定计数在某个中间时间变坏了,并且简单的代码跟踪不会做,因为字典被缓存和重用(通过 PyDict_New)由 gc 系统。

【问题讨论】:

    标签: python c dlsym ld-preload


    【解决方案1】:

    LD_PRELOAD 只能重载本身动态加载的函数。如果您使用的是 python 二进制文件,则 PyDict_New 不会动态加载,因此动态加载器无法拦截该符号的解析。如果您通过编译自己的二进制文件并与 libpython.so 链接来创建自己的“python”,它应该可以工作。以下是您需要放入程序 (/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 应该可以工作。

    【讨论】:

    • “自己动态加载”是什么意思。 LD_PRELOAD 不能用于覆盖未使用 -Bsymbolic 编译的共享库中的全局函数吗?
    • 我指的是可执行文件中的符号不​​是由 ld.so 动态加载的事实。由于它们不是由 ld.so 加载的,因此根本不使用 LD_PRELOAD。在这种情况下,OP 想要覆盖的函数被编译到 python 可执行文件中,而不是由 ld.so 从任何共享库加载。在提供的解决方案中,所有 python 都是从 libpython2.7.so 动态加载的,因此 LD_PRELOAD 将起作用。至于 -Bsymbolic,我的理解是,唯一的效果是让库首先更喜欢它自己的符号,而不是首先查看可执行文件的符号。
    【解决方案2】:

    我认为在您的情况下,只需下载 Python 的源代码分发版(适用于与您相关的版本),在调试模式下构建它并使用它运行您的应用程序会容易得多。

    此方法将在调试问题时为您提供更大的灵活性。例如,您可以在PyDict_New 中设置条件断点,或者将其替换为您自己的版本。

    【讨论】:

    • 虽然这不能解决问题,但我会投赞成票。我没有想到这一点。我想我只是不习惯在这么低的水平上工作。
    • @bukzor:您的问题确实没有提供足够的细节来直接解决(显示您的代码、您的编译/链接/执行路径、您期望的输出、您看到的输出等。否则它目前太抽象了)。尽管如此,我建议的方法应该让你更快地调试你的问题,恕我直言
    • 如果您单击我帖子中的链接,您会找到所有这些信息。也许我应该让它们更加突出/明确。明天就可以了。
    猜你喜欢
    • 2013-03-14
    • 2015-10-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-26
    相关资源
    最近更新 更多