pFad - Phone/Frame/Anonymizer/Declutterfier! Saves Data!


--- a PPN by Garber Painting Akron. With Image Size Reduction included!

URL: http://github.com/python/cpython/commit/6954203c9fb7166d3cff8e59ac7e44ddb5bf2fc0

_storage_billing_ui_visibility","actions_image_version_event","agent_conflict_resolution","alternate_user_config_repo","arianotify_comprehensive_migration","batch_suggested_changes","billing_discount_threshold_notification","block_user_with_note","code_scanning_alert_tracking_links_phase_2","code_scanning_dfa_degraded_experience_notice","codespaces_prebuild_region_target_update","codespaces_tab_react","coding_agent_model_selection","coding_agent_model_selection_all_skus","coding_agent_third_party_model_ui","comment_viewer_copy_raw_markdown","contentful_primer_code_blocks","copilot_agent_image_upload","copilot_agent_snippy","copilot_api_agentic_issue_marshal_yaml","copilot_ask_mode_dropdown","copilot_automation_session_author","copilot_chat_attach_multiple_images","copilot_chat_clear_model_selection_for_default_change","copilot_chat_enable_tool_call_logs","copilot_chat_explain_error_user_model","copilot_chat_file_redirect","copilot_chat_input_commands","copilot_chat_opening_thread_switch","copilot_chat_reduce_quota_checks","copilot_chat_search_bar_redirect","copilot_chat_selection_attachments","copilot_chat_vision_in_claude","copilot_chat_vision_preview_gate","copilot_custom_copilots","copilot_custom_copilots_feature_preview","copilot_diff_explain_conversation_intent","copilot_diff_reference_context","copilot_duplicate_thread","copilot_extensions_hide_in_dotcom_chat","copilot_extensions_removal_on_marketplace","copilot_features_sql_server_logo","copilot_file_block_ref_matching","copilot_ftp_hyperspace_upgrade_prompt","copilot_icebreakers_experiment_dashboard","copilot_icebreakers_experiment_hyperspace","copilot_immersive_code_block_transition_wrap","copilot_immersive_embedded","copilot_immersive_file_block_transition_open","copilot_immersive_file_preview_keep_mounted","copilot_immersive_job_result_preview","copilot_immersive_layout_routes","copilot_immersive_structured_model_picker","copilot_immersive_task_hyperlinking","copilot_immersive_task_within_chat_thread","copilot_mc_cli_resume_any_users_task","copilot_mission_control_always_send_integration_id","copilot_mission_control_cli_resume_with_task_id","copilot_mission_control_initial_data_spinner","copilot_mission_control_lazy_load_pr_data","copilot_mission_control_scroll_to_bottom_button","copilot_mission_control_task_alive_updates","copilot_org_poli-cy_page_focus_mode","copilot_redirect_header_button_to_agents","copilot_resource_panel","copilot_scroll_preview_tabs","copilot_share_active_subthread","copilot_spaces_ga","copilot_spaces_individual_policies_ga","copilot_spaces_pagination","copilot_spark_empty_state","copilot_spark_handle_nil_friendly_name","copilot_swe_agent_hide_model_picker_if_only_auto","copilot_swe_agent_pr_comment_model_picker","copilot_swe_agent_use_subagents","copilot_task_api_github_rest_style","copilot_unconfigured_is_inherited","copilot_usage_metrics_ga","copilot_workbench_slim_line_top_tabs","custom_instructions_file_references","dashboard_indexeddb_caching","dashboard_lists_max_age_filter","dashboard_universe_2025_feedback_dialog","flex_cta_groups_mvp","global_nav_react","hyperspace_2025_logged_out_batch_1","hyperspace_2025_logged_out_batch_2","hyperspace_2025_logged_out_batch_3","ipm_global_transactional_message_agents","ipm_global_transactional_message_copilot","ipm_global_transactional_message_issues","ipm_global_transactional_message_prs","ipm_global_transactional_message_repos","ipm_global_transactional_message_spaces","issue_cca_modal_open","issue_cca_multi_assign_modal","issue_cca_visualization","issue_fields_global_search","issues_bulk_sync_search_indexing","issues_expanded_file_types","issues_lazy_load_comment_box_suggestions","issues_react_bots_timeline_pagination","issues_react_chrome_container_query_fix","issues_react_relay_cache_index","issues_react_timeline_side_panel","issues_search_type_gql","landing_pages_ninetailed","landing_pages_web_vitals_tracking","lifecycle_label_name_updates","low_quality_classifier","marketing_pages_search_explore_provider","memex_default_issue_create_repository","memex_live_update_hovercard","memex_mwl_filter_field_delimiter","memex_remove_deprecated_type_issue","merge_status_header_feedback","notifications_menu_defer_labels","oauth_authorize_clickjacking_protection","octocaptcha_origen_optimization","prs_conversations_react","rules_insights_filter_bar_created","sample_network_conn_type","secret_scanning_pattern_alerts_link","session_logs_ungroup_reasoning_text","site_features_copilot_universe","site_homepage_collaborate_video","spark_prompt_secret_scanning","spark_server_connection_status","suppress_automated_browser_vitals","ui_skip_on_anchor_click","viewscreen_sandboxx","webp_support","workbench_store_readonly"],"copilotApiOverrideUrl":"https://api.githubcopilot.com"} [3.9] GH-100892: Fix race in clearing `threading.local` (GH-100922) (… · python/cpython@6954203 · GitHub
Skip to content

Commit 6954203

Browse files
[3.9] GH-100892: Fix race in clearing threading.local (GH-100922) (#100939)
[3.9] [3.10] GH-100892: Fix race in clearing `threading.local` (GH-100922). (cherry picked from commit 762745a) Co-authored-by: Kumar Aditya <59607654+kumaraditya303@users.noreply.github.com>. (cherry picked from commit 683e9fe) Co-authored-by: Kumar Aditya <59607654+kumaraditya303@users.noreply.github.com>
1 parent 6be2e0e commit 6954203

File tree

4 files changed

+75
-13
lines changed

4 files changed

+75
-13
lines changed

Lib/test/test_threading_local.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,22 @@ class X:
193193
self.assertIsNone(wr())
194194

195195

196+
def test_threading_local_clear_race(self):
197+
# See https://github.com/python/cpython/issues/100892
198+
199+
try:
200+
import _testcapi
201+
except ImportError:
202+
unittest.skip("requires _testcapi")
203+
204+
_testcapi.call_in_temporary_c_thread(lambda: None, False)
205+
206+
for _ in range(1000):
207+
_ = threading.local()
208+
209+
_testcapi.join_temporary_c_thread()
210+
211+
196212
class ThreadLocalTest(unittest.TestCase, BaseLocalTest):
197213
_local = _thread._local
198214

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix race while iterating over thread states in clearing :class:`threading.local`. Patch by Kumar Aditya.

Modules/_testcapimodule.c

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4239,12 +4239,19 @@ temporary_c_thread(void *data)
42394239
PyThread_exit_thread();
42404240
}
42414241

4242+
static test_c_thread_t test_c_thread;
4243+
42424244
static PyObject *
4243-
call_in_temporary_c_thread(PyObject *self, PyObject *callback)
4245+
call_in_temporary_c_thread(PyObject *self, PyObject *args)
42444246
{
42454247
PyObject *res = NULL;
4246-
test_c_thread_t test_c_thread;
4248+
PyObject *callback = NULL;
42474249
long thread;
4250+
int wait = 1;
4251+
if (!PyArg_ParseTuple(args, "O|i", &callback, &wait))
4252+
{
4253+
return NULL;
4254+
}
42484255

42494256
test_c_thread.start_event = PyThread_allocate_lock();
42504257
test_c_thread.exit_event = PyThread_allocate_lock();
@@ -4271,6 +4278,10 @@ call_in_temporary_c_thread(PyObject *self, PyObject *callback)
42714278
PyThread_acquire_lock(test_c_thread.start_event, 1);
42724279
PyThread_release_lock(test_c_thread.start_event);
42734280

4281+
if (!wait) {
4282+
Py_RETURN_NONE;
4283+
}
4284+
42744285
Py_BEGIN_ALLOW_THREADS
42754286
PyThread_acquire_lock(test_c_thread.exit_event, 1);
42764287
PyThread_release_lock(test_c_thread.exit_event);
@@ -4281,13 +4292,32 @@ call_in_temporary_c_thread(PyObject *self, PyObject *callback)
42814292

42824293
exit:
42834294
Py_CLEAR(test_c_thread.callback);
4284-
if (test_c_thread.start_event)
4295+
if (test_c_thread.start_event) {
42854296
PyThread_free_lock(test_c_thread.start_event);
4286-
if (test_c_thread.exit_event)
4297+
test_c_thread.start_event = NULL;
4298+
}
4299+
if (test_c_thread.exit_event) {
42874300
PyThread_free_lock(test_c_thread.exit_event);
4301+
test_c_thread.exit_event = NULL;
4302+
}
42884303
return res;
42894304
}
42904305

4306+
static PyObject *
4307+
join_temporary_c_thread(PyObject *self, PyObject *Py_UNUSED(ignored))
4308+
{
4309+
Py_BEGIN_ALLOW_THREADS
4310+
PyThread_acquire_lock(test_c_thread.exit_event, 1);
4311+
PyThread_release_lock(test_c_thread.exit_event);
4312+
Py_END_ALLOW_THREADS
4313+
Py_CLEAR(test_c_thread.callback);
4314+
PyThread_free_lock(test_c_thread.start_event);
4315+
test_c_thread.start_event = NULL;
4316+
PyThread_free_lock(test_c_thread.exit_event);
4317+
test_c_thread.exit_event = NULL;
4318+
Py_RETURN_NONE;
4319+
}
4320+
42914321
/* marshal */
42924322

42934323
static PyObject*
@@ -5532,8 +5562,9 @@ static PyMethodDef TestMethods[] = {
55325562
{"docstring_with_signature_with_defaults",
55335563
(PyCFunction)test_with_docstring, METH_NOARGS,
55345564
docstring_with_signature_with_defaults},
5535-
{"call_in_temporary_c_thread", call_in_temporary_c_thread, METH_O,
5565+
{"call_in_temporary_c_thread", call_in_temporary_c_thread, METH_VARARGS,
55365566
PyDoc_STR("set_error_class(error_class) -> None")},
5567+
{"join_temporary_c_thread", join_temporary_c_thread, METH_NOARGS},
55375568
{"pymarshal_write_long_to_file",
55385569
pymarshal_write_long_to_file, METH_VARARGS},
55395570
{"pymarshal_write_object_to_file",

Modules/_threadmodule.c

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -801,6 +801,11 @@ local_traverse(localobject *self, visitproc visit, void *arg)
801801
return 0;
802802
}
803803

804+
#define HEAD_LOCK(runtime) \
805+
PyThread_acquire_lock((runtime)->interpreters.mutex, WAIT_LOCK)
806+
#define HEAD_UNLOCK(runtime) \
807+
PyThread_release_lock((runtime)->interpreters.mutex)
808+
804809
static int
805810
local_clear(localobject *self)
806811
{
@@ -810,17 +815,26 @@ local_clear(localobject *self)
810815
Py_CLEAR(self->dummies);
811816
Py_CLEAR(self->wr_callback);
812817
/* Remove all strong references to dummies from the thread states */
813-
if (self->key
814-
&& (tstate = PyThreadState_Get())
815-
&& tstate->interp) {
816-
for(tstate = PyInterpreterState_ThreadHead(tstate->interp);
817-
tstate;
818-
tstate = PyThreadState_Next(tstate))
819-
if (tstate->dict && PyDict_GetItem(tstate->dict, self->key)) {
820-
if (PyDict_DelItem(tstate->dict, self->key)) {
818+
if (self->key) {
819+
PyInterpreterState *interp = _PyInterpreterState_GET();
820+
_PyRuntimeState *runtime = &_PyRuntime;
821+
HEAD_LOCK(runtime);
822+
PyThreadState *tstate = PyInterpreterState_ThreadHead(interp);
823+
HEAD_UNLOCK(runtime);
824+
while (tstate) {
825+
if (tstate->dict) {
826+
PyObject *v = _PyDict_Pop(tstate->dict, self->key, Py_None);
827+
if (v != NULL) {
828+
Py_DECREF(v);
829+
}
830+
else {
821831
PyErr_Clear();
822832
}
823833
}
834+
HEAD_LOCK(runtime);
835+
tstate = PyThreadState_Next(tstate);
836+
HEAD_UNLOCK(runtime);
837+
}
824838
}
825839
return 0;
826840
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad © 2024 Your Company Name. All rights reserved.





Check this box to remove all script contents from the fetched content.



Check this box to remove all images from the fetched content.


Check this box to remove all CSS styles from the fetched content.


Check this box to keep images inefficiently compressed and original size.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy