Skip to content

exporter: scrape dicts via items(), not keys() + __getitem__ (KeyError on mutated keys) - #9

Merged
mahmoud merged 1 commit into
kurtbrose:masterfrom
mahmoud:fix-mutated-dict-key-dump
Aug 9, 2026
Merged

exporter: scrape dicts via items(), not keys() + __getitem__ (KeyError on mutated keys)#9
mahmoud merged 1 commit into
kurtbrose:masterfrom
mahmoud:fix-mutated-dict-key-dump

Conversation

@mahmoud

@mahmoud mahmoud commented Aug 9, 2026

Copy link
Copy Markdown
Collaborator

Problem

dump_graph dies with KeyError(<key>) on any heap containing a dict whose key was mutated after insertion (hash no longer matches its bucket). Iteration over such a dict works fine, but lookup by the key raises, and the exporter scraped dicts via keys() + dict.__getitem__(obj, key).

Seen in the wild via openpyxl: StyleArray is an array subclass with a content-based hash that openpyxl mutates in place after using it as a dict key. Any worker heap containing a loaded-and-modified workbook made the dump fail:

KeyError(StyleArray('i', [0, 0, 0, 0, 0, 1, 0, 0, 0]))

Minimal repro against master:

from openpyxl.styles.cell_style import StyleArray
k = StyleArray()
d = {k: 1}
k[5] = 1  # in-place mutation changes hash
from objex import dump_graph
dump_graph('/tmp/dump.db')  # KeyError(StyleArray(...))

Fix

Scrape dicts with dict.items(obj): reads key and value straight off the bucket, no re-lookup; also one C call instead of one per key.

Test

Added MutableHashKey (a pure-Python stand-in for StyleArray) to the shared fixture heap with a post-insert mutation, plus test_dump_graph_survives_mutated_dict_keys following the existing survives_* pattern. Pre-fix, the fixture dump subprocess crashes (22 errors); post-fix, the full suite passes (30 passed).

A dict key mutated after insertion (hash no longer matches its bucket)
iterates fine but raises KeyError on lookup by key, killing the whole
dump. Seen in the wild with openpyxl's StyleArray (an array subclass
with a content-based hash that openpyxl mutates in place after using
it as a dict key): dump_graph on any heap containing a loaded-and-
modified workbook died with KeyError(StyleArray(...)).

dict.items() reads key and value straight off the bucket, so no
re-lookup happens; it's also one C call instead of one per key.
@mahmoud
mahmoud merged commit 2ca773f into kurtbrose:master Aug 9, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant