posix_spawn crashes when python is run with gprofng
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 77.2k
- Forks
- 35.9k
- PR merge metrics
- PR metrics pending
Description
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
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in Modules/posixmodule.c at py_posix_spawn and compare the environ handling before and after the posix_spawn call with the provided reproducer under gprofng. Done means the reproducer no longer crashes when the environment changes during the call, while ordinary posix_spawn behavior remains intact.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- c, python
- Domain
- operating-systems
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Stale
- Clarity
- Clearly specified
- Newbie friendliness
- 35/100