Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Segfault in ~ThreadStateCreator on shutdown on Python 3.11 #411

Closed
samschlegel opened this issue Jun 24, 2024 · 1 comment · Fixed by #414
Closed

Segfault in ~ThreadStateCreator on shutdown on Python 3.11 #411

samschlegel opened this issue Jun 24, 2024 · 1 comment · Fixed by #414

Comments

@samschlegel
Copy link
Contributor

samschlegel commented Jun 24, 2024

We recently upgraded a service from Python 3.8 to 3.11, and from greenlet 1.1.3.post0 to 3.3.0 and have been seeing a decent amount of segfaults during shutdown in the ThreadStateCreator destructor. It seems that this ends up getting called after the interpreter has already shut down which leads to a null pointer in PyEval_AddPendingCall.

I'm working on trying to get a minimal repro and reading through the changes that might have made this happen, but wanted to flag here in case anyone had some ideas on what changes might be leading to this.

As far as fixing it goes, I'm pretty sure it would be safe to check if the interpreter still exists before this call is made, and if so just exit, since presumably there wouldn't be much to cleanup anyways if the interpreter is gone. Without knowing the ultimate cause though, it feels if this is due to some race condition then doing a pre-check would likely just reduce but not eliminate the issue

#0  __pthread_kill_implementation (no_tid=0, signo=11, threadid=138025401046592) at ./nptl/pthread_kill.c:44
#1  __pthread_kill_internal (signo=11, threadid=138025401046592) at ./nptl/pthread_kill.c:78
#2  __GI___pthread_kill (threadid=138025401046592, signo=signo@entry=11) at ./nptl/pthread_kill.c:89
#3  0x00007d8a0591a476 in __GI_raise (sig=11) at ../sysdeps/posix/raise.c:26
#4  <signal handler called>
#5  0x00000000004e8bc8 in _PyEval_AddPendingCall (interp=0x0, func=0x7d8a046f7540 <greenlet::ThreadState_DestroyNoGIL::DestroyQueueWithGIL(void*)>, arg=0x0) at ../Python/ceval.c:617
#6  0x00007d8a046f80ae in greenlet::ThreadState_DestroyNoGIL::AddPendingCall (arg=0x0, func=0x7d8a046f7540 <greenlet::ThreadState_DestroyNoGIL::DestroyQueueWithGIL(void*)>) at src/greenlet/TThreadStateDestroy.cpp:99
#7  greenlet::ThreadState_DestroyNoGIL::ThreadState_DestroyNoGIL (state=0x7d88d5c3a160, this=<synthetic pointer>) at src/greenlet/TThreadStateDestroy.cpp:147
#8  greenlet::ThreadStateCreator<greenlet::ThreadState_DestroyNoGIL>::~ThreadStateCreator (this=<optimized out>, __in_chrg=<optimized out>) at src/greenlet/greenlet_thread_state.hpp:488
#9  0x00007d8a0591dd9f in __GI___call_tls_dtors () at ./stdlib/cxa_thread_atexit_impl.c:159
#10 0x00007d8a0596c945 in start_thread (arg=<optimized out>) at ./nptl/pthread_create.c:450
#11 0x00007d8a059fe850 in clone3 () at ../sysdeps/unix/sysv/linux/x86_64/clone3.S:81
@samschlegel
Copy link
Contributor Author

For additional context, here is is the stack trace for the main thread from the same coredump

#0  0x00007d8a059f6a7b in munmap () at ../sysdeps/unix/syscall-template.S:117
#1  0x00007d8a0347676b in mmap_object_dealloc (m_obj=0x7d89c1d79de0) at ./Modules/mmapmodule.c:166
#2  0x000000000058c5d8 in _Py_Dealloc (op=<optimized out>) at ../Objects/object.c:2390
#3  Py_DECREF (op=<optimized out>) at ../Include/object.h:538
#4  Py_XDECREF (op=<optimized out>) at ../Include/object.h:602
#5  _PyObject_FreeInstanceAttributes (self=<Decoder at remote 0x7d89c1dae190>) at ../Objects/dictobject.c:5583
#6  subtype_dealloc (self=<Decoder at remote 0x7d89c1dae190>) at ../Objects/typeobject.c:1433
#7  0x000000000058c1f5 in _Py_Dealloc (op=<optimized out>) at ../Objects/object.c:2390
#8  Py_DECREF (op=<optimized out>) at ../Include/object.h:538
#9  Py_XDECREF (op=<optimized out>) at ../Include/object.h:602
#10 _PyObject_FreeInstanceAttributes (self=<Reader at remote 0x7d89c1d9bcd0>) at ../Objects/dictobject.c:5583
#11 subtype_dealloc (self=<Reader at remote 0x7d89c1d9bcd0>) at ../Objects/typeobject.c:1433
#12 0x000000000052071b in _Py_Dealloc (op=<optimized out>) at ../Objects/object.c:2390
#13 Py_DECREF (op=<optimized out>) at ../Include/object.h:538
#14 Py_XDECREF (op=<optimized out>) at ../Include/object.h:602
#15 insertdict (mp=<optimized out>, key='client', hash=<optimized out>, value=<optimized out>) at ../Objects/dictobject.c:1304
#16 0x00000000005b7e6c in _PyDict_SetItem_Take2 (value=<optimized out>, key=<optimized out>, mp=<optimized out>) at ../Objects/dictobject.c:1886
#17 PyDict_SetItem (value=<optimized out>, key=<optimized out>, op={...(truncated)}) at ../Objects/dictobject.c:1906
#18 _PyModule_ClearDict (d={...(truncated)}) at ../Objects/moduleobject.c:634
#19 0x00000000006442f5 in finalize_modules_clear_weaklist (verbose=0, weaklist=[...(truncated)], interp=0xa4ee58 <_PyRuntime+58936>) at ../Python/pylifecycle.c:1499
#20 finalize_modules (tstate=0xa691d8 <_PyRuntime+166328>) at ../Python/pylifecycle.c:1581
#21 0x0000000000632fbb in Py_FinalizeEx () at ../Python/pylifecycle.c:1833
#22 0x000000000065464c in Py_Exit (sts=0) at ../Python/pylifecycle.c:2940
#23 0x000000000064496f in handle_system_exit () at ../Python/pythonrun.c:771
#24 0x0000000000644756 in _PyErr_PrintEx (set_sys_last_vars=1, tstate=0xa691d8 <_PyRuntime+166328>) at ../Python/pythonrun.c:781
#25 PyErr_PrintEx (set_sys_last_vars=1) at ../Python/pythonrun.c:876
#26 0x000000000046b455 in PyErr_Print () at ../Python/pythonrun.c:882
#27 _PyRun_SimpleFileObject (fp=<optimized out>, filename=<optimized out>, closeit=<optimized out>, flags=0x7fff6a21c938) at ../Python/pythonrun.c:446
#28 0x0000000000643b37 in _PyRun_AnyFileObject (fp=0x217dd20, filename='/usr/local/bin/gunicorn', closeit=1, flags=0x7fff6a21c938) at ../Python/pythonrun.c:79
#29 0x000000000063e679 in pymain_run_file_obj (skip_source_first_line=0, filename='/usr/local/bin/gunicorn', program_name='/usr/bin/python3.11') at ../Modules/main.c:360
#30 pymain_run_file (config=0xa4f220 <_PyRuntime+59904>) at ../Modules/main.c:379
#31 pymain_run_python (exitcode=0x7fff6a21c934) at ../Modules/main.c:601
#32 Py_RunMain () at ../Modules/main.c:680
#33 0x00000000006042bd in Py_BytesMain (argc=<optimized out>, argv=<optimized out>) at ../Modules/main.c:734
#34 0x00007d8a05901d90 in __libc_start_call_main (main=main@entry=0x604210 <main>, argc=argc@entry=29, argv=argv@entry=0x7fff6a21cb68) at ../sysdeps/nptl/libc_start_call_main.h:58
#35 0x00007d8a05901e40 in __libc_start_main_impl (main=0x604210 <main>, argc=29, argv=0x7fff6a21cb68, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fff6a21cb58) at ../csu/libc-start.c:392
#36 0x0000000000604145 in _start ()

shaldengeki referenced this issue in shaldengeki/monorepo Sep 24, 2024
Bumps [greenlet](https://github.com/python-greenlet/greenlet) from 3.0.3
to 3.1.1.
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/python-greenlet/greenlet/blob/master/CHANGES.rst">greenlet's
changelog</a>.</em></p>
<blockquote>
<h1>3.1.1 (2024-09-20)</h1>
<ul>
<li>Fix crashes on 32-bit PPC Linux. Note that there is no CI for this,
and support is best effort; there may be other issues lurking.
See <code>issue 422
&lt;https://github.com/python-greenlet/greenlet/issues/422&gt;</code>_.</li>
<li>Remove unnecessary logging sometimes during interpreter shutdown.
See <code>issue 426
&lt;https://github.com/python-greenlet/greenlet/issues/426&gt;</code>_.</li>
<li>Fix some crashes on 32-bit PPC MacOS. This is a very old platform,
and is only known to be tested on beta versions of an operating
system that was never released, using the GCC 14 only provided by
MacPorts; it may or may not work on the final MacOS X release that
supported 32-bit PowerPC. It has the known issue of leaking memory
when greenlets are used in multiple threads. Help debugging this
would be appreciated. See <code>PR 419
&lt;https://github.com/python-greenlet/greenlet/pull/419&gt;</code>_.</li>
</ul>
<h1>3.1.0 (2024-09-10)</h1>
<p>.. note::</p>
<pre><code>This will be the last release to support Python 3.7 and 3.8.
</code></pre>
<ul>
<li>Adds support for Python 3.13.</li>
</ul>
<p>.. note::</p>
<p>greenlet will not work in no-gil (free threaded) builds of CPython.
Internally, greenlet heavily depends on the GIL.</p>
<ul>
<li>Greatly reduce the chances for crashes during interpreter shutdown.
See <code>issue 411
&lt;https://github.com/python-greenlet/greenlet/issues/411&gt;</code>_.</li>
</ul>
<h2>Platform Support</h2>
<p>Support for the following platforms was contributed by the community.
Note that they are untested by this project's continuous integration
services.</p>
<ul>
<li>Hitachi's <code>SuperH CPU
&lt;https://github.com/python-greenlet/greenlet/issues/166&gt;</code>_.</li>
<li><code>NetBSD on PowerPC.
&lt;https://github.com/python-greenlet/greenlet/pull/402&gt;</code>_</li>
<li>RiscV 64 with <code>-fno-omit-frame-pointer
&lt;https://github.com/python-greenlet/greenlet/pull/404&gt;</code><em>.
Note that
there are <code>known test failures
&lt;https://github.com/python-greenlet/greenlet/issues/403&gt;</code></em>,
so this</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/python-greenlet/greenlet/commit/dd0a948da112a574864b518e5739bd90d068a1b0"><code>dd0a948</code></a>
Preparing release 3.1.1</li>
<li><a
href="https://github.com/python-greenlet/greenlet/commit/ab8d3bc1245f0e454cd3865009f6332a8c0090a0"><code>ab8d3bc</code></a>
Disable thread-local cleanup on 32-bit MacOS PPC with GCC. This will
result i...</li>
<li><a
href="https://github.com/python-greenlet/greenlet/commit/e9db22a94101e10909829c198b6d693ccf11f48f"><code>e9db22a</code></a>
Merge pull request <a
href="https://redirect.github.com/python-greenlet/greenlet/issues/429">#429</a>
from python-greenlet/issue419redux</li>
<li><a
href="https://github.com/python-greenlet/greenlet/commit/6081a16bb1c560262b34cf112896a6982756d02c"><code>6081a16</code></a>
Merge pull request <a
href="https://redirect.github.com/python-greenlet/greenlet/issues/419">#419</a>
from barracuda156/powerpc</li>
<li><a
href="https://github.com/python-greenlet/greenlet/commit/dbf311a021d80aecb38033a9f44fcf13be9e7a6f"><code>dbf311a</code></a>
Greater safety and fewer assumptions doing cross-thread cleanup.</li>
<li><a
href="https://github.com/python-greenlet/greenlet/commit/9e8a90b1a47e1254df65057af444671e22ca61e0"><code>9e8a90b</code></a>
Set back greenlet_thread_state.hpp file</li>
<li><a
href="https://github.com/python-greenlet/greenlet/commit/1bf374f4d8aaa8039012f70f93249726d23bdf59"><code>1bf374f</code></a>
Duplicate greenlet_thread_state.hpp history.</li>
<li><a
href="https://github.com/python-greenlet/greenlet/commit/64e0b4f6ceaa5cc2debafe551caea1276aa84aa9"><code>64e0b4f</code></a>
Copy greenlet_thread_state.hpp into TThreadStateCreator.hpp</li>
<li><a
href="https://github.com/python-greenlet/greenlet/commit/358a2e8f20816a68e65703b5488dd0337722a9a9"><code>358a2e8</code></a>
Keep greenlet_thread_state.hpp</li>
<li><a
href="https://github.com/python-greenlet/greenlet/commit/5144f7070cd7882f643f6b16a3dbc9138dbbf483"><code>5144f70</code></a>
Sigh. Pip hides compiler output which is, you know, important, and the
only w...</li>
<li>Additional commits viewable in <a
href="https://github.com/python-greenlet/greenlet/compare/3.0.3...3.1.1">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=greenlet&package-manager=pip&previous-version=3.0.3&new-version=3.1.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant