python / python/cpython

_find_incompatible_extension_module() lacks argument validation and raises TypeError or AttributeError when module_name is not string

Open
#146,632 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

stdlib type-bug
Dominant language
Python
Stars
77.2k
Forks
35.9k
PR merge metrics
PR metrics pending

Description

Crash report

What happened?

Now the code for traceback._find_incompatible_extension_module is here:

def _find_incompatible_extension_module(module_name):
    import importlib.machinery
    import importlib.resources.readers

    if not module_name or not importlib.machinery.EXTENSION_SUFFIXES:
        return

    # We assume the last extension is untagged (eg. .so, .pyd)!
    # tests.test_traceback.MiscTest.test_find_incompatible_extension_modules
    # tests that assumption.
    untagged_suffix = importlib.machinery.EXTENSION_SUFFIXES[-1]
    # On Windows the debug tag is part of the module file stem, instead of the
    # extension (eg. foo_d.pyd), so let's remove it and just look for .pyd.
    if os.name == 'nt':
        untagged_suffix = untagged_suffix.removeprefix('_d')

    parent, _, child = module_name.rpartition('.')
    if parent:
        traversable = importlib.resources.files(parent)
    else:
        traversable = importlib.resources.readers.MultiplexedPath(
            *map(pathlib.Path, filter(os.path.isdir, sys.path))
        )

    for entry in traversable.iterdir():
        if entry.name.startswith(child + '.') and entry.name.endswith(untagged_suffix):
            return entry.name

However, it is a function for handle a raised exception ModuleNotFoundError. When it raised other exception, it will crash the whole python. For example:

>>> raise AttributeError(name=NotImplemented, obj=NotImplemented)
Traceback (most recent call last):
  File "<python-input-0>", line 1, in <module>
    raise AttributeError(name=NotImplemented, obj=NotImplemented)
AttributeError
>>> raise NameError(name=NotImplemented)
Traceback (most recent call last):
  File "<python-input-1>", line 1, in <module>
    raise NameError(name=NotImplemented)
NameError
>>> raise ImportError(name=NotImplemented, name_from=NotImplemented)
Traceback (most recent call last):
  File "<python-input-2>", line 1, in <module>
    raise ImportError(name=NotImplemented, name_from=NotImplemented)
ImportError
>>> raise ModuleNotFoundError(name=NotImplemented)
Traceback (most recent call last):
  File "<python-input-3>", line 1, in <module>
ModuleNotFoundError

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Users\hh180\my_python\traceback_suggest_improve\Lib\code.py", line 324, in push
    more = self.runsource(source, filename, symbol=_symbol)
  File "C:\Users\hh180\my_python\traceback_suggest_improve\Lib\_pyrepl\console.py", line 239, in runsource
    result = self.runcode(code)
  File "C:\Users\hh180\my_python\traceback_suggest_improve\Lib\_pyrepl\console.py", line 186, in runcode
    self.showtraceback()
  File "C:\Users\hh180\my_python\traceback_suggest_improve\Lib\code.py", line 128, in showtraceback
    self._showtraceback(typ, value, tb.tb_next, "")
  File "C:\Users\hh180\my_python\traceback_suggest_improve\Lib\code.py", line 144, in _showtraceback
    self._excepthook(typ, value, tb)
  File "C:\Users\hh180\my_python\traceback_suggest_improve\Lib\_pyrepl\console.py", line 174, in _excepthook
    lines = traceback.format_exception(
  File "C:\Users\hh180\my_python\traceback_suggest_improve\Lib\traceback.py", line 168, in format_exception
    te = TracebackException(type(value), value, tb, limit=limit, compact=True)
  File "C:\Users\hh180\my_python\traceback_suggest_improve\Lib\traceback.py", line 1136, in __init__
    elif abi_tag := _find_incompatible_extension_module(module_name):
  File "C:\Users\hh180\my_python\traceback_suggest_improve\Lib\traceback.py", line 1914, in _find_incompatible_extension_module
    if not module_name or not importlib.machinery.EXTENSION_SUFFIXES:
TypeError: NotImplemented should not be used in a boolean context

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Users\hh180\my_python\traceback_suggest_improve\Lib\_pyrepl\main.py", line 58, in interactive_console
    run_multiline_interactive_console(console)
  File "C:\Users\hh180\my_python\traceback_suggest_improve\Lib\_pyrepl\simple_interact.py", line 174, in run_multiline_interactive_console
    console.showtraceback()
  File "C:\Users\hh180\my_python\traceback_suggest_improve\Lib\code.py", line 128, in showtraceback
    self._showtraceback(typ, value, tb.tb_next, "")
  File "C:\Users\hh180\my_python\traceback_suggest_improve\Lib\code.py", line 144, in _showtraceback
    self._excepthook(typ, value, tb)
  File "C:\Users\hh180\my_python\traceback_suggest_improve\Lib\_pyrepl\console.py", line 174, in _excepthook
    lines = traceback.format_exception(
  File "C:\Users\hh180\my_python\traceback_suggest_improve\Lib\traceback.py", line 168, in format_exception
    te = TracebackException(type(value), value, tb, limit=limit, compact=True)
  File "C:\Users\hh180\my_python\traceback_suggest_improve\Lib\traceback.py", line 1208, in __init__
    context = TracebackException(
  File "C:\Users\hh180\my_python\traceback_suggest_improve\Lib\traceback.py", line 1136, in __init__
    elif abi_tag := _find_incompatible_extension_module(module_name):
  File "C:\Users\hh180\my_python\traceback_suggest_improve\Lib\traceback.py", line 1914, in _find_incompatible_extension_module
    if not module_name or not importlib.machinery.EXTENSION_SUFFIXES:
TypeError: NotImplemented should not be used in a boolean context

For traceback function, it needs to check isinstance(module_name, str) and use try...except to include it.

CPython versions tested on:

CPython main branch

Operating systems tested on:

No response

Output from running 'python -VV' on the command line:

No response

Linked PRs
  • gh-146633

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Read Lib/traceback.py at _find_incompatible_extension_module and the TracebackException path that calls it. Start with tests.test_traceback.MiscTest.test_find_incompatible_extension_modules, then add coverage for non-string module names and verify traceback formatting no longer raises a secondary exception; the linked gh-146633 PR indicates this work is already underway.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
devtools
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.