tamnd / tamnd/firepanda

The extension segfaults on import into a free threaded interpreter

Open
#400 0 comments 0 reactions 0 assignees View on GitHub
area/python bug ci toolchain
Dominant language
Mojo
Stars
1
Forks
0
PR merge metrics
PR metrics pending

Description

`uv run` picks the newest interpreter it can find, and as of today that is a free threaded build of 3.14. Importing the extension into it segfaults inside `PyInit__firepanda`, before a single test runs, on every platform at once. That is what took CI down on Linux x86, Linux arm and macOS simultaneously on pull requests that touched no Python at all.

The reproduction is one line, with the extension built:

```
uv run --no-project --with pytest python -m pytest python/tests -q
```

```
Fatal Python error: Segmentation fault

Current thread 0x00007ba1bdad9740 [python] (most recent call first):
File "", line 1053 in create_module
File "/tmp/pytest-of-gopher/pytest-1/staged0/firepanda/__init__.py", line 37 in
```

```
Binary file ".../firepanda/_firepanda.so", at PyInit__firepanda+0x91
```

The interpreter is `3.14.7 free-threading build`. The same tests on 3.13 pass.

## Why this is a defect and not a feature we have not asked for

An extension module that says nothing about whether it is safe without the GIL is supposed to be handled, not crashed on. CPython reads `Py_mod_gil` from the module definition, and a module that does not set `Py_MOD_GIL_NOT_USED` makes the interpreter re enable the GIL, print a warning and continue. Segfaulting in the init function is not that. So either the module definition the Mojo toolchain emits is missing the slot in a way that leaves the interpreter reading uninitialized memory, or something in the init path is doing work that a free threaded build has moved.

That distinction matters because it decides who fixes it. If the module definition is incomplete then this is upstream in the toolchain. If it is our init path then it is ours.

## What has been done

CI pins the extension tests to 3.13, in the step comment that points here. That is a stopgap and it narrows what we test on rather than fixing anything.

## What is left

- Find out whether the crash is in the module definition the toolchain emits or in our init path, by getting a symbolized backtrace from a debug build rather than the address soup above
- If it is ours, fix it and unpin
- If it is upstream, report it there with this reproduction, and unpin when it lands
- Decide separately whether we want to actually support the free threaded build rather than merely survive it, which is a different and larger question and probably wants its own issue
- The wheels workflow imports the extension too, and is skipped on pull requests, so it is worth checking whether it has the same problem before a release

Contributor guide

Open the contributing guide

Research direction

Start with the one-line pytest reproduction and a debug build to obtain a symbolized backtrace from PyInit__firepanda. Inspect whether the crash is in the emitted module definition or the extension init path, then check the wheels workflow for the same import failure. Done means fixing the issue and unpinning 3.13, or reporting it upstream with the reproduction if the toolchain is responsible.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
build-system, testing
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.