Repository navigation
Commit f68bd0f
committed
gh-156544: fix free-threading race in UserDict.get() and __getitem__().
When UserDict.__delitem__, pop(), __popitem__(), or clear() are called
concurrently with get() or __getitem__ a race can occur in that get() or
__getitem__ can see the item as being contained and then they use
self.data[key] to return the item. However, if the item is removed after the
containment check this subscript access will raise KeyError and get() and
__getitem__() will propogate it, resulting in get() not returning default and
__getitem() incorrectly skipping the call it should make to __missing__ (if
defined).
This fix detects this race condition by ignoring the KeyError after
containment checks to allow default to be returned or __missing__ to be
called.
It is implemented in this unusual way that preserves the containment check
rather than relying solely on KeyError in order to preserve existing semantics
and performance characteristics. Removing the call to __contains__ on
self.data would change how UserData interacts with it and could potentially
break code that relies on this call.
In addition to preserving the current semantics, get() with a sentinel is not
used to atomically detect if the item is missing. Changing 'in' and '[key]' to
a single call to get() would replace these optimized operators with a more
expensive function call. Because exceptions incur overhead only when raised,
this implementation preserves existing performance for all cases except when
the race actually occurs, but ensures correct functionality when it does. It
also preserves the interaction semantics with the wrapped dict.1 parent 9f675a6 commit f68bd0f
1 file changed
Lines changed: 8 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1187 | 1187 | | |
1188 | 1188 | | |
1189 | 1189 | | |
1190 | | - | |
| 1190 | + | |
| 1191 | + | |
| 1192 | + | |
| 1193 | + | |
1191 | 1194 | | |
1192 | 1195 | | |
1193 | 1196 | | |
| |||
1208 | 1211 | | |
1209 | 1212 | | |
1210 | 1213 | | |
1211 | | - | |
| 1214 | + | |
| 1215 | + | |
| 1216 | + | |
| 1217 | + | |
1212 | 1218 | | |
1213 | 1219 | | |
1214 | 1220 | | |
| |||
0 commit comments