This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: PyImport_GetModuleDict: no module dictionary! when `__del__` triggers a warning
Type: crash Stage: resolved
Components: Interpreter Core Versions: Python 3.6, Python 3.4, Python 3.5, Python 2.7
process
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: Nosy List: andrei.avk, mbussonn, minrk, twouters
Priority: normal Keywords: patch

Created on 2016-01-19 12:14 by minrk, last changed 2022-04-11 14:58 by admin. This issue is now closed.

Files
File name Uploaded Description Edit
a.py minrk, 2016-01-19 12:14 a.py test module
b.py minrk, 2016-01-19 12:15 b.py test module
main.py minrk, 2016-01-19 12:15 main test script
Pull Requests
URL Status Linked Edit
PR 6518 merged twouters, 2018-04-18 14:21
PR 6520 closed twouters, 2018-04-18 16:40
PR 5337 njs, 2018-04-19 10:27
PR 6536 merged twouters, 2018-04-19 10:46
Messages (5)
msg258586 - (view) Author: Min RK (minrk) * Date: 2016-01-19 12:14
PyImport_GetModuleDict: no module dictionary! can be raised during interpreter shutdown if a `__del__` method results in a warning. This only happens on Python 3.5.

The prompting case is IPython 4.0.2 and traitlets 4.1.0. An IPython ExtensionManager calls `self.shell.on_trait_change` during its `__del__` to unregister a listener. That `on_trait_change` method is deprecated, and tries to display a DeprecationWarning. The call to `warnings.warn results in:

    Fatal Python error: PyImport_GetModuleDict: no module dictionary!

There appear to be races involved, because the crash happens with inconsistent frequency, sometimes quite rarely.

I've tried to put together a simple minimal test case, but I cannot reproduce the crash outside of IPython. I can, however, reproduce inconsistent behavior where a UserWarning displayed during `__del__` sometimes fails with

    ImportError: import of 'linecache' halted; None in sys.modules

and sometimes the exact same code succeeds, showing the error:

    ~/dev/tmp/del-warn/a.py:9: DeprecationWarning: I don't cleanup anymore
      self.b.cleanup()

and sometimes it shows the warning but not the frame

    ~/dev/tmp/del-warn/a.py:9: DeprecationWarning: I don't cleanup anymore
msg315453 - (view) Author: Thomas Wouters (twouters) * (Python committer) Date: 2018-04-18 13:59
We ran into this at work, with Python 3.6, where it involved extension types with a reference to files, with the (open) files being deallocated during interpreter exit and raising ResourceWarnings because of that. I tried to create a simple reproducer and failed, but I *did* manage to reproduce it in 2.7:

% cat warningscrash.py
import threading
import warnings

class WarnOnDel(object):
    def __del__(self):
        warnings.warn("oh no something went wrong", UserWarning)

def do_work():
    while True:
        w = WarnOnDel()

for i in range(10):
    t = threading.Thread(target=do_work)
    t.setDaemon(1)
    t.start()

% python2 warningscrash.py
warningscrash.py:7: UserWarning: oh no something went wrong
  warnings.warn("oh no something went wrong", UserWarning)
Fatal Python error: PyImport_GetModuleDict: no module dictionary!
Aborted (core dumped)

It's clearly dependent on timing, as even when starting 10 threads it doesn't always happen. Starting more threads makes it happen more often (but might cause your machine to trash a little). This doesn't reproduce it with Python 3.6, but I do believe it's possible there, too, but perhaps it requires threads that release the GIL for a longer period of time, or do deallocations with less overhead.

Python 2.7's warnings module doesn't try to do anything sensible during interpreter shutdown, as far as I can tell. Python 3.6's warnings module does, a little, but it's still possible to get this crash. The problem is that interp->modules (sys.modules) is deleted right before the _warnings module tries to access it (with PyImport_GetModuleDict in Python/_warnings.c:get_warnings_attr). I think a fix for 3.6 shouldn't be too hard, since we can check _Py_Finalizing.
msg315454 - (view) Author: Thomas Wouters (twouters) * (Python committer) Date: 2018-04-18 14:24
Looks like this was fixed in 3.7 by checking PyThreadState_GET()->interp->modules before trying to use it. That leaves the crash in 3.6 and earlier, though.
msg398207 - (view) Author: Andrei Kulakov (andrei.avk) * (Python triager) Date: 2021-07-26 03:22
3.6 no longer gets bugfixes, so I think this can be closed.
msg398222 - (view) Author: Thomas Wouters (twouters) * (Python committer) Date: 2021-07-26 11:23
This was fixed back in 2018, in fact.
History
Date User Action Args
2022-04-11 14:58:26adminsetgithub: 70341
2021-07-26 11:23:12twouterssetstatus: open -> closed
resolution: fixed
messages: + msg398222

stage: patch review -> resolved
2021-07-26 03:22:15andrei.avksetnosy: + andrei.avk
messages: + msg398207
2020-11-04 21:36:58brett.cannonsetnosy: - brett.cannon
2018-04-19 10:46:04twouterssetpull_requests: + pull_request6232
2018-04-19 10:27:47njssetpull_requests: + pull_request6230
2018-04-18 16:40:26twouterssetstage: patch review
pull_requests: + pull_request6213
2018-04-18 14:24:37twouterssetmessages: + msg315454
stage: patch review -> (no value)
2018-04-18 14:21:13twouterssetkeywords: + patch
stage: patch review
pull_requests: + pull_request6211
2018-04-18 13:59:21twouterssetnosy: + twouters

messages: + msg315453
versions: + Python 2.7, Python 3.4, Python 3.6
2016-01-19 19:32:44mbussonnsetnosy: + mbussonn
2016-01-19 13:49:12SilentGhostsetnosy: + brett.cannon
2016-01-19 12:15:21minrksetfiles: + main.py
2016-01-19 12:15:12minrksetfiles: + b.py
2016-01-19 12:14:48minrksetfiles: + a.py
2016-01-19 12:14:30minrkcreate