gh-151218: Replace sys.flags in PyConfig_Set()#151402
Conversation
PyConfig_Set() and sys.set_int_max_str_digits() now replace sys.flags, instead of modifying sys.flags in-place. Modifying sys.flags in-place can lead to data races when multiple threads are reading or writing sys.flags in parallel. Use _Py_atomic functions to get and set max_str_digits members.
|
I built Python with If we agree that this change is the right approach, I will add a non-regression test. |
skirpichev
left a comment
There was a problem hiding this comment.
I think it's a correct approach.
Add test_sys to "./python -m test --tsan" tests.
|
I added a thread test to I also added some simple tests on get_int_max_str_digits() / set_int_max_str_digits() (in test_sys). |
|
Python 3.13 is not affected: I modified |
Documentation build overview
|
Update also outdated comment.
Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com>
|
@picnixz: I addressed your review. Please review the updated PR. |
picnixz
left a comment
There was a problem hiding this comment.
LGTM. Btw, I tried to delete sys.flags and it made the REPL "crash" (well just exit with an exception). I wonder whether sys.flags should be made non-deletable as well.
| sys_set_flag(flags, pos, value); | ||
| Py_DECREF(flags); | ||
| return 0; | ||
| new_flags = PyStructSequence_New(&FlagsType); |
There was a problem hiding this comment.
All this dance makes me wonder whether we need a PyStructSequence_Copy. Would be nicer to just copy the structure and alter one field.
There was a problem hiding this comment.
I searched for PyStructSequence_New() and the only other place which creates a copy of an existing structseq is structseq_replace(): structseq.__replace__() method. I'm not sure that it's worth it to write a generic PyStructSequence_Copy() function.
Example using structseq.__replace__() method:
$ python
>>> import sys, copy
>>> copy.replace(sys.flags, verbose=3)
sys.flags(..., verbose=3, ...)
In https://peps.python.org/pep-0726/ discussion, I mentioned that protecting It's not easy to modify how module attributes are set and deleted in a C extension. |
|
Thanks @vstinner for the PR 🌮🎉.. I'm working now to backport this PR to: 3.14, 3.15. |
|
Sorry, @vstinner, I could not cleanly backport this to |
|
GH-151552 is a backport of this pull request to the 3.15 branch. |
|
GH-151553 is a backport of this pull request to the 3.14 branch. |
…51552) gh-151218: Replace sys.flags in PyConfig_Set() (GH-151402) PyConfig_Set() and sys.set_int_max_str_digits() now replace sys.flags (create a new object), instead of modifying sys.flags in-place. Modifying sys.flags in-place can lead to data races when multiple threads are reading or writing sys.flags in parallel. Use _Py_atomic functions to get and set max_str_digits members. (cherry picked from commit b16d23f) Co-authored-by: Victor Stinner <vstinner@python.org> Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com>
) gh-151218: Replace sys.flags in PyConfig_Set() (#151402) PyConfig_Set() and sys.set_int_max_str_digits() now replace sys.flags (create a new object), instead of modifying sys.flags in-place. Modifying sys.flags in-place can lead to data races when multiple threads are reading or writing sys.flags in parallel. Use _Py_atomic functions to get and set max_str_digits members. (cherry picked from commit b16d23f) Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com>
PyConfig_Set() and sys.set_int_max_str_digits() now replace sys.flags, instead of modifying sys.flags in-place.
Modifying sys.flags in-place can lead to data races when multiple threads are reading or writing sys.flags in parallel.
Use _Py_atomic functions to get and set max_str_digits members.
sys_set_flagwhensys.set_int_max_str_digits()is called concurrently with free-threaded build #151218