Skip to content

Use-after-free while pickling dicts #92930

Closed
@sweeneyde

Description

Found here, but this crash is unrelated, so opening a new issue.

The following could be simplified, but it crashes because PyDict_Next creates borrowed references.

import pickle
from random import getrandbits

class Bad:
    def __eq__(self, other):
        if not ENABLED:
            return False
        break_things()
        return getrandbits(4) == 0
    def __hash__(self):
        return getrandbits(1)
    def __reduce__(self):
        break_things()
        return (Bad, (), ())
    def __setstate__(self, *args):
        break_things()
    def __del__(self):
        break_things()
    def __getattr__(self):
        break_things()

def break_things():
    if getrandbits(6) == 0:
        collection.clear()

TRIALS = 10_000
SIZE = 50

for i in range(TRIALS):
    try:
        ENABLED = False
        collection = {Bad():Bad() for _ in range(SIZE)}
        for bad in collection:
            bad.bad = bad
            bad.collection = collection
        ENABLED = True
        pickle.loads(pickle.dumps(collection))
    except RuntimeError as e:
        assert "changed size during iteration" in str(e)

print("ok")

Metadata

Assignees

No one assigned

    Labels

    type-crashA hard crash of the interpreter, possibly with a core dump

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions