GeezerVisonThe World Wide Web, restored to 800 pixels of glory. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Home|About|Gaming cabinet|Archives|How it works|Starter sites | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
GeezerVison is showing github.com — gh-112075: Fix race in constructing dict for instance by DinoV · Pull Request #118499 · python/cpython Conversation
|
| assert(dictptr != NULL); | ||
| if ((tp->tp_flags & Py_TPFLAGS_HEAPTYPE) && (cached = CACHED_KEYS(tp))) { | ||
| assert(dictptr != NULL); | ||
| dict = *dictptr; |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
We need to use atomics to load from the dictptr or there will be a data race between the read here and the write within the critical section.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
a9ad363 to
56a79e6
Compare
|
|
||
| Py_BEGIN_CRITICAL_SECTION(dict); | ||
| res = set_or_del_lock_held((PyDictObject *)dict, key, value); | ||
| Py_END_CRITICAL_SECTION(); |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
I think the ASSERT_CONSISTENT needs to be inside the critical section.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| { | ||
| PyDictKeysObject *cached; | ||
|
|
||
| PyObject *dict = FT_ATOMIC_LOAD_PTR_RELAXED(*dictptr); |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
acquire (or seq-cst)
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| else { | ||
| dict = PyDict_New(); | ||
| } | ||
| FT_ATOMIC_STORE_PTR_RELAXED(*dictptr, dict); |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
release (or seq-cst)
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| if (dict == NULL) { | ||
| dictkeys_decref(interp, cached, false); | ||
| } |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
I think new_dict_with_shared_keys already handles the dictkeys_decref in the error case.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Oh, that's super subtle, I don't think there's any reason to spread this out, I'll move the incref into new_dict_with_shared_keys
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| return -1; | ||
| } | ||
| #ifdef Py_GIL_DISABLED | ||
| Py_XDECREF(_Py_atomic_exchange_ptr(dictptr, Py_NewRef(value))); |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
I think we need to be consistent about either using atomic exchange/cas or using the object locks to protect the dictptr. I don't think we can safely mix them.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| } | ||
| #endif | ||
| PyTypeObject *tp = Py_TYPE(obj); | ||
| if ((tp->tp_flags & Py_TPFLAGS_HEAPTYPE) && (cached = CACHED_KEYS(tp))) { |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
maybe: _PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE)
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| goto done; | ||
| } | ||
| #endif | ||
| OBJECT_STAT_INC(dict_materialized_on_request); |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Are we consistent about when we increment this stat?
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
We seem to actually have an extra call in materialize_managed_dict_lock_held which is the inline values case. This one seems like maybe it shouldn't exist at all, as we no longer have a simple values array which is outside of the dict, so even though we have shared keys here we will always have a dict. I'll remove it from here.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
LGTM. Two minor comments below
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
Lock obj instead of using atomic, and fix reads/writes
There was an error while loading. Please reload this page.
Successfully merging this pull request may close these issues.
There was an error while loading. Please reload this page.