[Bugfix] PythonObjectCache::lookup() reads hash map without mutex #269
Labels
No labels
Alpha Release Requirement
Bugfix
Demo Target
Documentation
Major Feature
Minor Feature
priority:tier1-active
priority:tier2-foundation
priority:tier3-future
priority:tier4-deferred
Refactoring & Cleanup
system:animation
system:documentation
system:grid
system:input
system:performance
system:procgen
system:python-binding
system:rendering
system:ui-hierarchy
Tiny Feature
workflow:blocked
workflow:needs-benchmark
workflow:needs-documentation
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
john/McRogueFace#269
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
PythonObjectCache::lookup()reads thestd::unordered_map<uint64_t, PyObject*> cachewithout acquiring theserial_mutex, whileregisterObject(),remove(),cleanup(), andclear()all mutate the map under the mutex. If any of those methods run concurrently withlookup(), the hash map read can race with a write, causing undefined behavior (iterator invalidation during rehash, corrupted bucket chains, etc.).Root Cause
PythonObjectCache.cpp:37-52:The comment says "No mutex needed for read - GIL protects PyWeakref_GetRef" — but the GIL protects the PyWeakref call, not the
std::unordered_map::find(). The GIL does happen to serialize most Python-level operations, but:assignSerial()usesstd::atomicsuggesting thread-safety was intendedregisterObject()andremove()take the mutex, implying thread-safety is expectedImpact
In the current single-threaded architecture, the GIL likely prevents actual races. But:
rehashduringcache[serial] = weakrefinregisterObject()would invalidate the iterator in a concurrentlookup()Fix
Add mutex acquisition to
lookup():Or, if performance is a concern, use a
std::shared_mutexwithshared_lockfor reads.Severity
Medium — currently protected by GIL in practice, but the code contract is inconsistent and any future threading would expose a data race.