在C python中,访问字节码评估堆栈

2023-11-22

给定一个 C Python 帧指针,如何查看任意计算堆栈条目? (一些特定的堆栈条目可以通过locals(),我说的是其他堆栈条目。)

我不久前问了一个更广泛的问题:

获取 C python exec 参数字符串或访问计算堆栈

但在这里我想重点关注能够在运行时读取 CPython 堆栈条目。

我将采用适用于 CPython 2.7 或任何高于 Python 3.3 的 Python 的解决方案。但是,如果您有除此之外的工作,请分享,如果没有更好的解决方案,我会接受。

我不想修改 C Python 代码。在 Ruby 中,我实际上已经这样做了得到我想要的。根据我的经验,这可能不是我们想要的工作方式。但同样,如果没有更好的解决方案,我会采用它。 (我对SO点的理解是,无论哪种方式,我都会在赏金中失去它。所以我很高兴看到它落到那些表现出最好的精神和意愿的人手中,假设它有效。)

update:请参阅 user2357112 tldr 的评论;基本上这是很难做到的。 (不过,如果您认为自己有勇气尝试,请务必这样做。)

因此,让我将范围缩小到这个我认为可行的更简单的问题:

给定一个 python 堆栈框架,例如inspect.currentframe(),找到计算堆栈的开头。在该结构的 C 版本中,这是f_valuestack。然后我们需要一种 Python 方法来从那里读取 Python 值/对象。

update 2好吧,赏金的时间段已经结束,没有人(包括我自己的总结答案)提供具体的代码。我觉得这是一个好的开始,我现在比以前更了解情况了。在强制性的“描述为什么你认为应该有赏金”中,我列出了所提供的选择之一“以引起更多对这个问题的关注”,并且在这个程度上,对前世的化身有不到十几个观点这个问题,当我输入此内容时,它已被查看了不到 190 次。所以这是成功的。然而...

如果将来有人决定进一步开展这项工作,请联系我,我将设置另一笔赏金。

谢谢大家。


有时这是可能的,使用 ctypes 来直接访问 C 结构成员,但它很快就会变得混乱。

首先,无论是 C 端还是 Python 端,都没有可用的公共 API,所以这是不可能的。我们必须深入研究 C 实现的未记录的内部结构。我将重点关注 CPython 3.8 实现;其他版本中的细节应该相似,尽管可能有所不同。

PyFrameObject 结构有一个f_valuestack指向其计算堆栈底部的成员。它还有一个f_stacktop有时会指向其计算堆栈顶部的成员。在执行帧期间,Python 实际上使用stack_pointer局部变量在_PyEval_EvalFrameDefault:

stack_pointer = f->f_stacktop;
assert(stack_pointer != NULL);
f->f_stacktop = NULL;       /* remains NULL unless yield suspends frame */

有两种情况f_stacktop已恢复。一种是如果框架由一个yield (or yield from,或通过相同机制挂起协程的多个构造中的任何一个)。另一个是在调用跟踪函数之前'line' or 'opcode' 跟踪事件. f_stacktop当帧取消挂起或跟踪函数完成后再次清除。

这意味着如果

  • 您正在查看悬挂的生成器或协程框架,或者
  • 您当前正在使用跟踪函数'line' or 'opcode'帧的事件

然后您可以访问f_valuestack and f_stacktop带有 ctypes 的指针,用于查找帧计算堆栈的下限和上限并访问PyObject *存储在该范围内的指针。您甚至可以在没有 ctypes 的情况下获得堆栈内容的超集gc.get_referents(frame_object),尽管这将包含不在框架堆栈上的其他引用。

调试器使用跟踪函数,因此在大多数情况下,这可以让您在调试时获得顶部堆栈帧的堆栈条目值。它不会为您提供调用堆栈上任何其他堆栈帧的值堆栈条目,并且在跟踪调用时也不会为您提供值堆栈条目。'exception'事件或任何其他跟踪事件。


When f_stacktop为 NULL,确定帧的堆栈内容几乎是不可能的。您仍然可以看到堆栈从哪里开始f_valuestack,但你看不到它的终点。栈顶存储在C级stack_pointer局部变量确实很难访问。

  • 这是框架的代码对象的co_stacksize,它给出了堆栈大小的上限,但它没有给出实际的堆栈大小。
  • 您无法通过检查堆栈本身来判断堆栈在哪里结束,因为 Python 在弹出条目时不会清空堆栈上的指针。
  • gc.get_referents不返回值堆栈条目f_stacktop一片空白。在这种情况下它也不知道如何安全地检索堆栈条目(并且它不需要,因为如果f_stacktop为空并且堆栈条目存在,则保证帧可达)。
  • 您也许可以检查框架的f_lasti确定它所在的最后一个字节码指令并尝试找出该指令将离开堆栈的位置,但这需要对 Python 字节码和字节码评估循环有大量深入的了解,并且有时仍然不明确(因为框架可能指令进行到一半)。不过,这至少会给您当前堆栈大小的下限,让您安全地检查至少其中的一部分。
  • 框架对象具有彼此不连续的独立值堆栈,因此您无法查看一个框架堆栈的底部来查找另一个框架堆栈的顶部。 (值堆栈实际上是在帧对象本身内分配的。)
  • 你也许能够找到stack_pointer局部变量与一些 GDB 魔法或其他东西,但它会是一团糟。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在C python中,访问字节码评估堆栈 的相关文章

随机推荐

  • 音频记录:缓冲区溢出?

    我遇到缓冲区溢出RECORDING与我的应用程序 录音是在Service 我不明白为什么我会收到这条消息AudioFlinger 下面我实例化AudioRecord对象并设置它的回调 bufferSize AudioRecord getMi
  • 将json中的所有snake_case键转换为camelCase键

    在Go中 我们如何将JSON中的snake case键递归转换为camelCase键 我正在用 Go 编写一个 http api 此 api 从数据存储中获取数据 进行一些计算并以 JSON 形式返回响应 情况是 数据存储区 Elastic
  • 如何使用 PostgreSQL 中的函数插入多行

    我想使用 PostgreSQL 中的函数在表中插入多行 这是我的桌子 CREATE TABLE mahasiswa nim CHAR 10 nama VACHAR 40 CONSTRAINT pk nim PRIMARY KEY nim 这
  • 请帮助测试 Firefox jQuery ajax 出现 401 时的 CORS 问题

    这让我发疯 jQuery 1 4 2 Windows XP SP3 这是我的测试 加载火狐浏览器3 5 http plungjan name test testcors html works 将文件保存到硬盘并从那里运行 从我的办公室来看
  • 如何从 Visual Studio Code 中使用 Electron 和 Angular 调试应用程序?

    我正在尝试使用最新版本的 Angular 和 Electron 开发一个非常简单的应用程序 为此 我遵循了 Angular 和 Electron 的教程 经过大量的试验和错误 我终于可以启动我的应用程序 源代码在 GitHub 上 我使用
  • jquery 多个事件处理程序

    我已经根据我正在处理的最新项目中的类名定义了事件处理程序 对于前 所有具有类名 foo 的元素都应该以特定的方式响应更改事件 所有类名为 bar 的元素都应该以其他方式响应 现在我的一些元素属于这两个类 即 class foo bar 并且
  • 基类方法可以返回派生类的类型吗?

    根据我读过的其他帖子 这似乎不可能 但我想我会发布我正在尝试做的事情 看看是否有人知道解决方案 我正在尝试将 Clone 方法添加到从 Telerik 开放访问域模型生成的类中 没问题 我能够弄清楚如何将基类添加到生成的实体模型中 以便我可
  • 从 lapply 或带有 print 语句的函数调用时 kable 出现意外行为

    我试图理解使用 knit 包 在 Ubuntu 14 04 上的 RStudio 0 98 977 中 编织 HTML 时 kable 函数的以下两个意外行为 当从 lapply 中两次调用 kable 时 只有第一个调用会在最终的 HTM
  • TObject 包含哪些数据?

    TObject InstanceSize 返回 8 但 TObject 未声明任何数据成员 根据TObject ClassType的实现 前4个字节可以解释为指向对象的TClass元数据的指针 有人知道另外 4 个字节的开销是做什么用的吗
  • WSFederationAuthenticationModule.IsSignInResponse 中存在潜在危险的 Request.Form

    在我的 MVC3 站点中 我避免使用新的 ValidateInput 属性设置 requestValidationMode 2 0 但现在我尝试切换到 WIF 进行身份验证 当 STS 重定向回我的站点时 我收到异常 因为WSFederat
  • 如何检查函数的模板参数是否具有某种类型?

    假设我有一个具有模板类型的函数T和另外两个班级A and B template
  • 如何运行 GCC 预处理器来获取 #define 等宏扩展后的代码?

    GCC 预处理器是否可以生成 C 源代码并过滤掉不相关的源代码 例如 一个 c文件有一个 define切换以定义许多不同的平台 我只对一个平台感兴趣 并且我希望 C 预处理器过滤掉不相关的代码 Does GCC支持这个吗 是的 使用 E o
  • 从 C# 将二进制数据插入 SQL,无需存储过程

    有谁知道是否可以在不使用存储过程的情况下从 C 将二进制数据插入 SQL 字段 例如 将字节数组转换为 base64 或类似的东西 然后使用如下所示的文本命令 String Format update A set B 0 where C D
  • 在 ASP.NET 中使用依赖注入和工厂模式传递服务

    我正在使用 ASP NET Core 我知道框架已经提供了这样的日志记录机制 但用这个来说明我的问题 我正在使用工厂模式来构建 Logger 类 因为我不知道日志记录的类型 因为它存储在数据库中 ILogger 合约 Log string
  • 以编程方式将 Excel 2003 文件转换为 2007+

    我正在寻找一种方法 基本上获取 2003 年旧文件扩展名 xls 的 excel 文件文件夹 并将它们转换为 xlsm 我知道你可以自己进入Excel表并手动完成 但是有没有办法用代码来完成呢 具体使用任何类型的库 这不是我的代码 但我以前
  • SQL 按日期范围内的频率进行分组

    我需要编写一个存储过程 它接受开始日期 结束日期和频率 日 周 月 季度 年 并根据这些参数输出结果集 显然 简单的部分是按日期范围查询 但是如何按频率分组呢 因此 如果有一组像这样的原始数据 Date Count 11 15 2011 6
  • SonarQube 6.1:如何在没有仪表板的情况下查看随时间的变化?

    SonarQube 曾经有仪表板 可以非常方便地显示指标如何随时间变化 甚至还有一个名为 时间机器 的仪表板 如何在 SonarQube 6 1 中查看此类信息 我很欣赏对 泄漏期 的新关注 但这并不是我关心的全部 转到项目的 度量 空间并
  • LibUsbDotNet 调用 UsbDevice.AllDevices 时未找到设备

    我正在执行 LibUsbDotNet 的示例代码 它将返回所有连接的 USB 设备的信息 您可以在下面找到此代码 using System using LibUsbDotNet using LibUsbDotNet Info using L
  • 尝试在 Windows 上重定向 stdout 和 stderr - _fileno(stdout) 返回 -2

    这是我的第一个问题 我即将将一些运行良好的 C 代码从 UNIX 移植到 Windows 它通过管道将 stdout 和 stderr 重定向到自定义 GUI 组件 我需要它来显示来自第三方库的反馈 该第三方库仅将消息输出到 GUI 上的标
  • 在C python中,访问字节码评估堆栈

    给定一个 C Python 帧指针 如何查看任意计算堆栈条目 一些特定的堆栈条目可以通过locals 我说的是其他堆栈条目 我不久前问了一个更广泛的问题 获取 C python exec 参数字符串或访问计算堆栈 但在这里我想重点关注能够在