python / python/cpython

posix_spawn crashes when python is run with gprofng

未關閉
#149,509 1 則留言 0 個 reaction 已指派 0 人 在 GitHub 檢視

還沒有人認領這個 Issue。

extension-modules type-bug
主要語言
Python
星號
77.2k
分支
36k
PR 合併指標
PR 指標待擷取

描述

Bug report

Bug description:

I've been observing crashes when python code calls posix_spawn when being
run under gprofng.

As an example, I tested on a Fedora 42 x86_64 system with python3-3.13.13-1.fc42.x86_64
[Python 3.13.13 (main, Apr 8 2026, 00:00:00) [GCC 15.2.1 20260123 (Red Hat 15.2.1-7)] on linux]
and binutils-2.44-12.fc42.x86_64
[GNU gprofng binutils version 2.44]

Consider this script:

import os
os.posix_spawn("/usr/bin/echo", ["/usr/bin/echo", "world"], None)
print ("hello")

If I run this on its own, it works as expected:

$ python spawn.py
hello
world

But if I run it with gprofng, it crashes:

$ gprofng collect app python spawn.py
Creating experiment directory test.1.er (Process ID: 591620) ...
free(): invalid pointer
Aborted (core dumped)
$ world

The problem goes away if I change the third argument of the posix_spawn
command from None to os.environ. I also reproduce the crash with
cpython git main as of May 6 (65ed109b5de7bab28f1051336f0ae312205c4233).

The issue is that py_posix_spawn assumes that environ does not change
over the call to posix_spawn. However, when gprofng is used, it
interposes code wrapping the posix_spawn call that can modify the
environment (apparently to sanitize the environment from things like
LD_PRELOAD entries used by gprofng) and thus change environ.

In more detail, in py_posix_spawn, we have this before the spawn call:

    EXECV_CHAR **envlist = NULL;
    ...
    Py_ssize_t argc, envc;
    ...
    if (env == Py_None) {
#ifdef USE_DARWIN_NS_GET_ENVIRON
        environ = *_NSGetEnviron();
#endif
        envlist = environ;
    } else {
        envlist = parse_envlist(env, &envc);
        if (envlist == NULL) {
            goto exit;
        }
    }

and after the call:

    if (envlist && envlist != environ) {
        free_string_array(envlist, envc);
    }

So if the env argument is null and environ is changed by the call,
then we end up trying to free environ,
using a length taken from an uninitialized variable.

Here's one possible fix:

diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c
index 5bd53c2146a..4fef8a60647 100644
--- a/Modules/posixmodule.c
+++ b/Modules/posixmodule.c
@@ -7961,6 +7961,7 @@ py_posix_spawn(int use_posix_spawnp, PyObject *module, path_t *path, PyObject *a
         environ = *_NSGetEnviron();
 #endif
         envlist = environ;
+        envc = (Py_ssize_t)-1;
     } else {
         envlist = parse_envlist(env, &envc);
         if (envlist == NULL) {
@@ -8028,7 +8029,10 @@ py_posix_spawn(int use_posix_spawnp, PyObject *module, path_t *path, PyObject *a
     if (attrp) {
         (void)posix_spawnattr_destroy(attrp);
     }
-    if (envlist && envlist != environ) {
+    /* Can't just test for envlist != environ because some tools, such as
+       gprofng, interpose code around the posix_spawn call that can change
+       environ. */
+    if (envlist && envc != (Py_ssize_t)-1) {
         free_string_array(envlist, envc);
     }
     if (argvlist) {
CPython versions tested on:

3.13, CPython main branch

Operating systems tested on:

Linux

Linked PRs
  • gh-149724

貢獻指南

開啟貢獻指南

從這裡開始

  1. 先讀完整個 Issue,再讀專案的貢獻指南。
  2. 在 Issue 下留言說明你要接手 —— 這能避免兩個人做同樣的事。
  3. Fork 儲存庫,在一個分支上完成修改。
  4. 送出 Pull Request,並在描述裡引用這個 Issue 編號。

研究方向

從 Modules/posixmodule.c 中的 py_posix_spawn 開始,使用提供的 gprofng 下的重現程式比較 posix_spawn 呼叫前後對 environ 的處理。當環境在呼叫期間發生變更時重現程式不再當機,同時 posix_spawn 的一般行為維持不變,即可視為完成。

由索引模型根據 Issue 內容生成。

評估

技術堆疊
c, python
領域
operating-systems
Issue 類型
缺陷
難度
3/5
預估耗時
1-2 天
活躍度
停滯
描述清晰度
描述清楚
新手友好度
35/100

把新 issue 寄到你的電子郵件信箱

精選適合新手參與的 GitHub issue 摘要。