[New-bugs-announce] [issue45913] Doctest Seg Fault with Python 3.10 on CI

Dan Yeaw report at bugs.python.org
Sat Nov 27 22:53:41 EST 2021


New submission from Dan Yeaw <dan at yeaw.me>:

When running pytest --doctest-modules, I am getting seg faults on the GitHub Actions CI when running doctests covering module docstrings.

runner at fv-az177-300:~/work/gaphor/gaphor$ source .venv/bin/activate
(.venv) runner at fv-az177-300:~/work/gaphor/gaphor$ xvfb-run gdb python

(gdb) run -m pytest
Starting program: /home/runner/work/gaphor/gaphor/.venv/bin/python -m pytest
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[New Thread 0x7fffecd32700 (LWP 22846)]
[New Thread 0x7fffebd31700 (LWP 22847)]
[New Thread 0x7fffead30700 (LWP 22848)]
[New Thread 0x7fffe9d2f700 (LWP 22849)]
[New Thread 0x7fffdbfff700 (LWP 22850)]
[New Thread 0x7fffdaffe700 (LWP 22851)]
[New Thread 0x7fffd9ffd700 (LWP 22852)]
[New Thread 0x7fffcffff700 (LWP 22853)]
[Detaching after fork from child process 22854]
============================= test session starts ==============================
platform linux -- Python 3.10.0, pytest-6.2.5, py-1.11.0, pluggy-1.0.0
rootdir: /home/runner/work/gaphor/gaphor, configfile: pyproject.toml, testpaths: gaphor, tests, docs
plugins: mock-3.6.1, cov-3.0.0
collected 1135 items                                                           

gaphor/action.py 
Thread 1 "python" received signal SIGSEGV, Segmentation fault.
__GI___libc_free (mem=0x20) at malloc.c:3102
3102    malloc.c: No such file or directory.
(gdb) source python-gdb.py
(gdb) py-bt
Traceback (most recent call first):
  <built-in method create_dynamic of module object at remote 0x7ffff78ebcb0>
  File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
  File "<frozen importlib._bootstrap_external>", line 1176, in create_module
  File "<frozen importlib._bootstrap>", line 571, in module_from_spec
  File "<frozen importlib._bootstrap>", line 674, in _load_unlocked
  File "<frozen importlib._bootstrap>", line 1006, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 1027, in _find_and_load
  File "/opt/hostedtoolcache/Python/3.10.0/x64/lib/python3.10/pdb.py", line 157, in __init__
    import readline
  File "/opt/hostedtoolcache/Python/3.10.0/x64/lib/python3.10/doctest.py", line 364, in __init__
    pdb.Pdb.__init__(self, stdout=out, nosigint=True)
  File "/opt/hostedtoolcache/Python/3.10.0/x64/lib/python3.10/doctest.py", line 1481, in run
    self.debugger = _OutputRedirectingPdb(save_stdout)
  File "/opt/hostedtoolcache/Python/3.10.0/x64/lib/python3.10/doctest.py", line 1856, in run
    r = DocTestRunner.run(self, test, compileflags, out, False)
  File "/home/runner/work/gaphor/gaphor/.venv/lib/python3.10/site-packages/_pytest/doctest.py", line 287, in runtest
    self.runner.run(self.dtest, out=failures)  # type: ignore[arg-type]
  File "/home/runner/work/gaphor/gaphor/.venv/lib/python3.10/site-packages/_pytest/runner.py", line 162, in pytest_runtest_call
    item.runtest()
  File "/home/runner/work/gaphor/gaphor/.venv/lib/python3.10/site-packages/pluggy/_callers.py", line 39, in _multicall
    res = hook_impl.function(*args)
  File "/home/runner/work/gaphor/gaphor/.venv/lib/python3.10/site-packages/pluggy/_manager.py", line 80, in _hookexec
    return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
  File "/home/runner/work/gaphor/gaphor/.venv/lib/python3.10/site-packages/pluggy/_hooks.py", line 265, in __call__
    return self._hookexec(self.name, self.get_hookimpls(), kwargs, firstresult)
  File "/home/runner/work/gaphor/gaphor/.venv/lib/python3.10/site-packages/_pytest/runner.py", line 255, in <lambda>
    lambda: ihook(item=item, **kwds), when=when, reraise=reraise
  File "/home/runner/work/gaphor/gaphor/.venv/lib/python3.10/site-packages/_pytest/runner.py", line 311, in from_call
    result: Optional[TResult] = func()
  File "/home/runner/work/gaphor/gaphor/.venv/lib/python3.10/site-packages/_pytest/runner.py", line 254, in call_runtest_hook
    return CallInfo.from_call(
  File "/home/runner/work/gaphor/gaphor/.venv/lib/python3.10/site-packages/_pytest/runner.py", line 215, in call_and_report
    call = call_runtest_hook(item, when, **kwds)
  File "/home/runner/work/gaphor/gaphor/.venv/lib/python3.10/site-packages/_pytest/runner.py", line 126, in runtestprotocol
    reports.append(call_and_report(item, "call", log))
  File "/home/runner/work/gaphor/gaphor/.venv/lib/python3.10/site-packages/_pytest/runner.py", line 109, in pytest_runtest_protocol
    runtestprotocol(item, nextitem=nextitem)
  File "/home/runner/work/gaphor/gaphor/.venv/lib/python3.10/site-packages/pluggy/_callers.py", line 39, in _multicall
    res = hook_impl.function(*args)
  File "/home/runner/work/gaphor/gaphor/.venv/lib/python3.10/site-packages/pluggy/_manager.py", line 80, in _hookexec
    return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
  File "/home/runner/work/gaphor/gaphor/.venv/lib/python3.10/site-packages/pluggy/_hooks.py", line 265, in __call__
    return self._hookexec(self.name, self.get_hookimpls(), kwargs, firstresult)
  File "/home/runner/work/gaphor/gaphor/.venv/lib/python3.10/site-packages/_pytest/main.py", line 348, in pytest_runtestloop
    item.config.hook.pytest_runtest_protocol(item=item, nextitem=nextitem)
  File "/home/runner/work/gaphor/gaphor/.venv/lib/python3.10/site-packages/pluggy/_callers.py", line 39, in _multicall
    res = hook_impl.function(*args)
  File "/home/runner/work/gaphor/gaphor/.venv/lib/python3.10/site-packages/pluggy/_manager.py", line 80, in _hookexec
    return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
  File "/home/runner/work/gaphor/gaphor/.venv/lib/python3.10/site-packages/pluggy/_hooks.py", line 265, in __call__
    return self._hookexec(self.name, self.get_hookimpls(), kwargs, firstresult)
  File "/home/runner/work/gaphor/gaphor/.venv/lib/python3.10/site-packages/_pytest/main.py", line 323, in _main
    config.hook.pytest_runtestloop(session=session)
  File "/home/runner/work/gaphor/gaphor/.venv/lib/python3.10/site-packages/_pytest/main.py", line 269, in wrap_session
    session.exitstatus = doit(config, session) or 0
  File "/home/runner/work/gaphor/gaphor/.venv/lib/python3.10/site-packages/_pytest/main.py", line 316, in pytest_cmdline_main
    return wrap_session(config, _main)
  File "/home/runner/work/gaphor/gaphor/.venv/lib/python3.10/site-packages/pluggy/_callers.py", line 39, in _multicall
    res = hook_impl.function(*args)
  File "/home/runner/work/gaphor/gaphor/.venv/lib/python3.10/site-packages/pluggy/_manager.py", line 80, in _hookexec
    return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
  File "/home/runner/work/gaphor/gaphor/.venv/lib/python3.10/site-packages/pluggy/_hooks.py", line 265, in __call__
    return self._hookexec(self.name, self.get_hookimpls(), kwargs, firstresult)
  File "/home/runner/work/gaphor/gaphor/.venv/lib/python3.10/site-packages/_pytest/config/__init__.py", line 162, in main
    ret: Union[ExitCode, int] = config.hook.pytest_cmdline_main(
  File "/home/runner/work/gaphor/gaphor/.venv/lib/python3.10/site-packages/_pytest/config/__init__.py", line 185, in console_main
    code = main()
  File "/home/runner/work/gaphor/gaphor/.venv/lib/python3.10/site-packages/pytest/__main__.py", line 5, in <module>
    raise SystemExit(pytest.console_main())
  <built-in method exec of module object at remote 0x7ffff78d3d10>
  File "/opt/hostedtoolcache/Python/3.10.0/x64/lib/python3.10/runpy.py", line 86, in _run_code
    exec(code, run_globals)
  File "/opt/hostedtoolcache/Python/3.10.0/x64/lib/python3.10/runpy.py", line 196, in _run_module_as_main
    return _run_code(code, main_globals, None,

action.py is part of the Gaphor project here: https://github.com/gaphor/gaphor

The doctest that it is seg faulting on is:

    >>> class A:
    ...     @action(name="my_action", label="my action")
    ...     def myaction(self):
    ...         print("action called")
    >>> a = A()
    >>> a.myaction()
    action called
    >>> is_action(a.myaction)
    True
    >>> for method in dir(A):
    ...     if is_action(getattr(A, method, None)):
    ...         print(method)
    myaction
    >>> A.myaction.__action__.name
    'my_action'
    >>> A.myaction.__action__.label
    'my action'
    """

Running the doctests works fine manually:
dan at localhost:~/Projects/gaphor> python -m doctest -v gaphor/action.py
Trying:
    class A:
        @action(name="my_action", label="my action")
        def myaction(self):
            print("action called")
Expecting nothing
ok
Trying:
    a = A()
Expecting nothing
ok
Trying:
    a.myaction()
Expecting:
    action called
ok
Trying:
    is_action(a.myaction)
Expecting:
    True
ok
Trying:
    for method in dir(A):
        if is_action(getattr(A, method, None)):
            print(method)
Expecting:
    myaction
ok
Trying:
    A.myaction.__action__.name
Expecting:
    'my_action'
ok
Trying:
    A.myaction.__action__.label
Expecting:
    'my action'
ok
5 items had no tests:
    action
    action.action.__call__
    action.action.__init__
    action.action.detailed_name
    action.is_action
1 items passed all tests:
   7 tests in action.action
7 tests in 6 items.
7 passed and 0 failed.
Test passed.

If I disable this doctests, the other doctests will seg fault as well. Using xdoctest instead of doctest also fixes the seg fault.

I compiled Python 3.10.0 with debug enabled on the GitHub Actions runner, so I can provide the full backtrace if that is helpful.

----------
components: Library (Lib)
messages: 407184
nosy: danyeaw
priority: normal
severity: normal
status: open
title: Doctest Seg Fault with Python 3.10 on CI
type: crash
versions: Python 3.10

_______________________________________
Python tracker <report at bugs.python.org>
<https://bugs.python.org/issue45913>
_______________________________________


More information about the New-bugs-announce mailing list