-
-
Notifications
You must be signed in to change notification settings - Fork 34.7k
gh-151218: Replace sys.flags in PyConfig_Set() #151402
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
425b022
19e863c
a66a331
4ca409d
f114294
e5280f1
770d385
df57cf2
44bc1b2
1843290
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| import sys | ||
| import unittest | ||
| from test.support import threading_helper | ||
|
|
||
|
|
||
| class SysModuleTest(unittest.TestCase): | ||
| def test_int_max_str_digits_thread(self): | ||
| # gh-151218: Check that it's safe to call get_int_max_str_digits() and | ||
| # set_int_max_str_digits() in parallel. Previously, this test triggered | ||
| # warnings in TSan on a free threaded build. | ||
|
|
||
| old_limit = sys.get_int_max_str_digits() | ||
| self.addCleanup(sys.set_int_max_str_digits, old_limit) | ||
|
|
||
| def worker(worker_id): | ||
| if not worker_id: | ||
| for i in range (20_000): | ||
| sys.get_int_max_str_digits() | ||
| else: | ||
| for i in range (20_000): | ||
| sys.set_int_max_str_digits(4300 + (i & 7)) | ||
|
|
||
| workers = [lambda: worker(i) for i in range(5)] | ||
| threading_helper.run_concurrently(workers) | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| unittest.main() |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| :c:func:`PyConfig_Set` and :func:`sys.set_int_max_str_digits` now replace | ||
| :data:`sys.flags` (create a new object), instead of modifying :data:`sys.flags` | ||
| in-place. Patch by Victor Stinner. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1874,7 +1874,8 @@ sys_get_int_max_str_digits_impl(PyObject *module) | |
| /*[clinic end generated code: output=0042f5e8ae0e8631 input=77fb74e987ba7ecb]*/ | ||
| { | ||
| PyInterpreterState *interp = _PyInterpreterState_GET(); | ||
| return PyLong_FromLong(interp->long_state.max_str_digits); | ||
| int maxdigits = _Py_atomic_load_int(&interp->long_state.max_str_digits); | ||
| return PyLong_FromLong(maxdigits); | ||
| } | ||
|
|
||
|
|
||
|
|
@@ -3490,14 +3491,39 @@ sys_set_flag(PyObject *flags, Py_ssize_t pos, PyObject *value) | |
| int | ||
| _PySys_SetFlagObj(Py_ssize_t pos, PyObject *value) | ||
| { | ||
| PyObject *flags = PySys_GetAttrString("flags"); | ||
| if (flags == NULL) { | ||
| return -1; | ||
| PyObject *new_flags = NULL; | ||
| PyObject *flags_str = &_Py_ID(flags); // immortal ref | ||
|
|
||
| PyObject *old_flags = PySys_GetAttr(flags_str); | ||
| if (old_flags == NULL) { | ||
| goto error; | ||
| } | ||
|
|
||
| sys_set_flag(flags, pos, value); | ||
| Py_DECREF(flags); | ||
| return 0; | ||
| new_flags = PyStructSequence_New(&FlagsType); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. All this dance makes me wonder whether we need a
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I searched for Example using |
||
| if (new_flags == NULL) { | ||
| goto error; | ||
| } | ||
|
|
||
| for (Py_ssize_t i = 0; i < (Py_ssize_t)(Py_ARRAY_LENGTH(flags_fields) - 1); i++) { | ||
| if (i != pos) { | ||
| PyObject *old_value; | ||
| old_value = PyStructSequence_GET_ITEM(old_flags, i); // borrowed ref | ||
| sys_set_flag(new_flags, i, old_value); | ||
| } | ||
| else { | ||
| sys_set_flag(new_flags, pos, value); | ||
| } | ||
| } | ||
|
|
||
| int res = _PySys_SetAttr(flags_str, new_flags); | ||
| Py_DECREF(old_flags); | ||
| Py_DECREF(new_flags); | ||
| return res; | ||
|
|
||
| error: | ||
| Py_XDECREF(old_flags); | ||
| Py_XDECREF(new_flags); | ||
| return -1; | ||
| } | ||
|
|
||
|
|
||
|
|
@@ -3521,8 +3547,6 @@ set_flags_from_config(PyInterpreterState *interp, PyObject *flags) | |
| const PyPreConfig *preconfig = &interp->runtime->preconfig; | ||
| const PyConfig *config = _PyInterpreterState_GetConfig(interp); | ||
|
|
||
| // _PySys_UpdateConfig() modifies sys.flags in-place: | ||
| // Py_XDECREF() is needed in this case. | ||
| Py_ssize_t pos = 0; | ||
| #define SetFlagObj(expr) \ | ||
| do { \ | ||
|
|
@@ -4033,7 +4057,7 @@ _PySys_InitCore(PyThreadState *tstate, PyObject *sysdict) | |
| /* implementation */ | ||
| SET_SYS("implementation", make_impl_info(version_info)); | ||
|
|
||
| // sys.flags: updated in-place later by _PySys_UpdateConfig() | ||
| // sys.flags: updated later by _PySys_UpdateConfig() | ||
| ENSURE_INFO_TYPE(FlagsType, flags_desc); | ||
| SET_SYS("flags", make_flags(tstate->interp)); | ||
|
|
||
|
|
@@ -4153,16 +4177,21 @@ _PySys_UpdateConfig(PyThreadState *tstate) | |
| #undef COPY_LIST | ||
| #undef COPY_WSTR | ||
|
|
||
| // sys.flags | ||
| PyObject *flags = PySys_GetAttrString("flags"); | ||
| if (flags == NULL) { | ||
| // replace sys.flags | ||
| PyObject *new_flags = PyStructSequence_New(&FlagsType); | ||
| if (new_flags == NULL) { | ||
| return -1; | ||
| } | ||
| if (set_flags_from_config(interp, flags) < 0) { | ||
| Py_DECREF(flags); | ||
| if (set_flags_from_config(interp, new_flags) < 0) { | ||
| Py_DECREF(new_flags); | ||
| return -1; | ||
| } | ||
|
|
||
| res = _PySys_SetAttr(&_Py_ID(flags), new_flags); | ||
| Py_DECREF(new_flags); | ||
| if (res < 0) { | ||
| return -1; | ||
| } | ||
| Py_DECREF(flags); | ||
|
|
||
| SET_SYS("dont_write_bytecode", PyBool_FromLong(!config->write_bytecode)); | ||
|
|
||
|
|
@@ -4675,7 +4704,7 @@ _PySys_SetIntMaxStrDigits(int maxdigits) | |
| // Set PyInterpreterState.long_state.max_str_digits | ||
| // and PyInterpreterState.config.int_max_str_digits. | ||
| PyInterpreterState *interp = _PyInterpreterState_GET(); | ||
| interp->long_state.max_str_digits = maxdigits; | ||
| interp->config.int_max_str_digits = maxdigits; | ||
| _Py_atomic_store_int(&interp->long_state.max_str_digits, maxdigits); | ||
| _Py_atomic_store_int(&interp->config.int_max_str_digits, maxdigits); | ||
|
picnixz marked this conversation as resolved.
|
||
| return 0; | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.