python / python/cpython

profiling.sampling incorrectly handles base_frame and native frame as the first frame

未关闭
#157,605 6 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

还没有人认领这个 Issue。

extension-modules topic-profiling type-bug
主要语言
Python
星标
77.2k
派生
35.9k
PR 合并指标
PR 指标待抓取

描述

Bug description

profiling.sampling does not correctly handle some frame chains whose first frame is not a Python frame.

There are two cases:

  1. The first frame is base_frame

    A native thread can retain a Python thread state while waiting in C code, with no Python functions executing. Its frame chain contains only the base_frame sentinel.

    The sampler skips this sentinel and then raises:

    RuntimeError: Failed to parse initial frame in chain

  2. The first frame is a native frame

    When the first frame in the chain is a native frame, the sampler does not correctly handle it as the initial frame and may report the frame chain as invalid instead of adding a <native> frame.

In both cases, the failure can cause the entire sampling call to fail, so valid Python stacks from other threads are also lost.

Reproduction

Case 1: base_frame as the first frame

Create a pthread that registers and detaches a Python thread state:

PyGILState_STATE state = PyGILState_Ensure();
PyThreadState *saved = PyEval_SaveThread();

/* Wait on a pthread condition variable while the parent samples. */

/* Cleanup after sampling. */
PyEval_RestoreThread(saved);
PyGILState_Release(state);

Keep the main thread inside a Python function and sample the child process from its parent:

unwinder = _remote_debugging.RemoteUnwinder(
    pid, all_threads=True, cache_frames=False,
)
unwinder.get_stack_trace()

tachyon-empty-native-repro.zip

  • Reproduces with frame caching both enabled and disabled.
Case 2: Native frame as the first frame

Construct a frame chain whose current frame is a native frame and whose previous frame leads to base_frame.

When native-frame collection is enabled, sampling this thread currently fails to correctly handle the native frame as the first frame.

Expected behavior

The sampler should correctly handle both cases:

  1. If the first frame is base_frame, treat it as a valid empty Python stack.
  2. If the first frame is a native frame, add a <native> frame to the returned stack and continue walking the frame chain.

A special frame state in one thread should not cause the entire sampling operation to fail or prevent valid stacks from other threads from being returned.

Suspected cause

process_frame_chain() does not correctly handle cases where the first frame does not contain a parseable Python frame, including base_frame and native frames.

These cases can be incorrectly treated as a broken initial frame chain.

Environment

Linux, CPython 3.15.0rc2+dev free-threaded build and current main.

Linked PRs
  • gh-157817

贡献指南

打开贡献指南

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

调研方向

首先跟踪 process_frame_chain(),重点关注它如何处理 base_frame 以及作为第一个 frame 的 native frame。使用提供的 pthread 复现和 native-frame 场景来检验这两条路径。完成的标准是:base_frame 生成有效的空 Python stack,native frame 添加一个 frame,并且一个特殊线程不会丢弃其他线程的有效 stack。

由索引模型根据 Issue 内容生成。

评估

技术栈
c, python
领域
performance
Issue 类型
缺陷
难度
4/5
预计耗时
3-5 天
活跃度
活跃
描述清晰度
基本清楚
新手友好度
55/100

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。