Skip to content

iter __reduce__ can segfault if accessing __builtins__.__dict__['iter'] mutates the iter object #101765

@ionite34

Description

@ionite34
Contributor

Crash report

Example from @chilaxan

corrupt = iter(lambda:0, 0)

class Cstr:
    def __hash__(self):
        return hash('iter')
    def __eq__(self, other):
        [*corrupt]
        return other == 'iter'

builtins = __builtins__.__dict__ if hasattr(__builtins__, '__dict__') else __builtins__
oiter = builtins['iter']
del builtins['iter']
builtins[Cstr()] = oiter

print(corrupt.__reduce__())

Expected result

This should return a valid __reduce__ tuple of the exhausted iterator. Instead behavior is inconsistent between segmentation faults, SystemErrors, and sometimes returning the iterator without being exhausted.

Error messages

  • 3.11, windows, PYTHONMALLOC=debug
  • 3.12.0a4, windows, PYTHONMALLOC=debug
Windows fatal exception: access violation
> exit code -1073741819 (0xC0000005)
  • 3.12.04a4, windows, compiled with debug mode
    print(corrupt.__reduce__())
          ^^^^^^^^^^^^^^^^^^^^
SystemError: NULL object passed to Py_BuildValue
  • 3.11, ubuntu
(<built-in function iter>, (<function  at 0x7fb772c3c4a0>, 0))
> terminated by signal SIGSEGV (Address boundary error)
  • 3.12.0a4, ubuntu
(<built-in function iter>, (<function  at 0x7f3480d71f80>, 0))
  • 3.12.0a4, ubuntu, PYTHONMALLOC=debug
Fatal Python error: Segmentation fault

Linked PRs

Activity

added
type-crashA hard crash of the interpreter, possibly with a core dump
on Feb 9, 2023
godlygeek

godlygeek commented on Feb 9, 2023

@godlygeek
Contributor

This (horrific) reproducer provokes undefined defined behavior from this statement:

return Py_BuildValue("N(OO)", _PyEval_GetBuiltin(&_Py_ID(iter)),
it->it_callable, it->it_sentinel);

The call to _PyEval_GetBuiltin to find the iter builtin is calling Cstr.__eq__, which exhausts the iterator, causing the Py_CLEAR in calliter_iternext to be executed, setting it->it_callable and it->it_sentinel to NULL. But the order of evaluation of arguments in a function call isn't specified, and modifying an argument by evaluating another argument is a bug.

On some platforms, it->it_callable and it->it_sentinel are being evaluated before _PyEval_GetBuiltin, and so Py_BuildValue is being passed pointers to objects that got freed inside the _PyEval_GetBuiltin call.

changed the title [-]`iter.__reduce__` can segfault if accessing `__builtins__.__dict__['iter']` exhausts the iter object[/-] [+]iter `__reduce__` can segfault if accessing `__builtins__.__dict__['iter']` mutates the iter object[/+] on Feb 10, 2023
added a commit that references this issue on Feb 10, 2023
added a commit that references this issue on Feb 24, 2023
54dfa14
added 2 commits that reference this issue on Feb 25, 2023
a9cd908
297d01e
added a commit that references this issue on Feb 25, 2023
031382c
added 2 commits that reference this issue on Feb 25, 2023
5d46122
9f472f8

5 remaining items

added 4 commits that reference this issue on Feb 26, 2023
added a commit that references this issue on Feb 26, 2023
8d0f09b
added a commit that references this issue on Feb 26, 2023
added 3 commits that reference this issue on Feb 26, 2023
added a commit that references this issue on Feb 28, 2023
added a commit that references this issue on Sep 10, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    interpreter-core(Objects, Python, Grammar, and Parser dirs)type-crashA hard crash of the interpreter, possibly with a core dump

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @godlygeek@arhadthedev@ionite34

        Issue actions

          iter `__reduce__` can segfault if accessing `__builtins__.__dict__['iter']` mutates the iter object · Issue #101765 · python/cpython