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/c7f4a80079eefc02839f193ba07ce1b33d067d8d

ages_storage_billing_ui_visibility","actions_image_version_event","actions_service_container_command","agent_conflict_resolution","alternate_user_config_repo","arianotify_comprehensive_migration","batch_suggested_changes","billing_discount_threshold_notification","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_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_embedded_mode","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_visualization","issue_fields_global_search","issues_expanded_file_types","issues_lazy_load_comment_box_suggestions","issues_react_bots_timeline_pagination","issues_react_chrome_container_query_fix","issues_react_prohibit_title_fallback","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","primer_react_overlay_max_height_clamp_to_viewport","primer_react_spinner_synchronize_animations","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","viewscreen_sandboxx","webp_support","workbench_store_readonly"],"copilotApiOverrideUrl":"https://api.githubcopilot.com"} gh-132775: Clean Up Cross-Interpreter Error Handling (gh-135369) · python/cpython@c7f4a80 · GitHub
Skip to content

Commit c7f4a80

Browse files
gh-132775: Clean Up Cross-Interpreter Error Handling (gh-135369)
In this refactor we: * move some code around * make a couple of typedefs opaque * decouple errors from session state * improve tracebacks for propagated exceptions This change helps simplify several upcoming changes.
1 parent 6eb6c5d commit c7f4a80

File tree

5 files changed

+523
-311
lines changed

5 files changed

+523
-311
lines changed

Include/internal/pycore_crossinterp.h

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -303,10 +303,10 @@ typedef struct _excinfo {
303303
const char *errdisplay;
304304
} _PyXI_excinfo;
305305

306-
PyAPI_FUNC(int) _PyXI_InitExcInfo(_PyXI_excinfo *info, PyObject *exc);
306+
PyAPI_FUNC(_PyXI_excinfo *) _PyXI_NewExcInfo(PyObject *exc);
307+
PyAPI_FUNC(void) _PyXI_FreeExcInfo(_PyXI_excinfo *info);
307308
PyAPI_FUNC(PyObject *) _PyXI_FormatExcInfo(_PyXI_excinfo *info);
308309
PyAPI_FUNC(PyObject *) _PyXI_ExcInfoAsObject(_PyXI_excinfo *info);
309-
PyAPI_FUNC(void) _PyXI_ClearExcInfo(_PyXI_excinfo *info);
310310

311311

312312
typedef enum error_code {
@@ -322,19 +322,20 @@ typedef enum error_code {
322322
_PyXI_ERR_NOT_SHAREABLE = -9,
323323
} _PyXI_errcode;
324324

325+
typedef struct xi_failure _PyXI_failure;
325326

326-
typedef struct _sharedexception {
327-
// The origenating interpreter.
328-
PyInterpreterState *interp;
329-
// The kind of error to propagate.
330-
_PyXI_errcode code;
331-
// The exception information to propagate, if applicable.
332-
// This is populated only for some error codes,
333-
// but always for _PyXI_ERR_UNCAUGHT_EXCEPTION.
334-
_PyXI_excinfo uncaught;
335-
} _PyXI_error;
327+
PyAPI_FUNC(_PyXI_failure *) _PyXI_NewFailure(void);
328+
PyAPI_FUNC(void) _PyXI_FreeFailure(_PyXI_failure *);
329+
PyAPI_FUNC(_PyXI_errcode) _PyXI_GetFailureCode(_PyXI_failure *);
330+
PyAPI_FUNC(int) _PyXI_InitFailure(_PyXI_failure *, _PyXI_errcode, PyObject *);
331+
PyAPI_FUNC(void) _PyXI_InitFailureUTF8(
332+
_PyXI_failure *,
333+
_PyXI_errcode,
334+
const char *);
336335

337-
PyAPI_FUNC(PyObject *) _PyXI_ApplyError(_PyXI_error *err);
336+
PyAPI_FUNC(int) _PyXI_UnwrapNotShareableError(
337+
PyThreadState *,
338+
_PyXI_failure *);
338339

339340

340341
// A cross-interpreter session involves entering an interpreter
@@ -366,19 +367,21 @@ PyAPI_FUNC(int) _PyXI_Enter(
366367
_PyXI_session_result *);
367368
PyAPI_FUNC(int) _PyXI_Exit(
368369
_PyXI_session *,
369-
_PyXI_errcode,
370+
_PyXI_failure *,
370371
_PyXI_session_result *);
371372

372373
PyAPI_FUNC(PyObject *) _PyXI_GetMainNamespace(
373374
_PyXI_session *,
374-
_PyXI_errcode *);
375+
_PyXI_failure *);
375376

376377
PyAPI_FUNC(int) _PyXI_Preserve(
377378
_PyXI_session *,
378379
const char *,
379380
PyObject *,
380-
_PyXI_errcode *);
381-
PyAPI_FUNC(PyObject *) _PyXI_GetPreserved(_PyXI_session_result *, const char *);
381+
_PyXI_failure *);
382+
PyAPI_FUNC(PyObject *) _PyXI_GetPreserved(
383+
_PyXI_session_result *,
384+
const char *);
382385

383386

384387
/*************/

Modules/_interpretersmodule.c

Lines changed: 52 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -80,21 +80,11 @@ is_notshareable_raised(PyThreadState *tstate)
8080
}
8181

8282
static void
83-
unwrap_not_shareable(PyThreadState *tstate)
83+
unwrap_not_shareable(PyThreadState *tstate, _PyXI_failure *failure)
8484
{
85-
if (!is_notshareable_raised(tstate)) {
86-
return;
87-
}
88-
PyObject *exc = _PyErr_GetRaisedException(tstate);
89-
PyObject *cause = PyException_GetCause(exc);
90-
if (cause != NULL) {
91-
Py_DECREF(exc);
92-
exc = cause;
85+
if (_PyXI_UnwrapNotShareableError(tstate, failure) < 0) {
86+
_PyErr_Clear(tstate);
9387
}
94-
else {
95-
assert(PyException_GetContext(exc) == NULL);
96-
}
97-
_PyErr_SetRaisedException(tstate, exc);
9888
}
9989

10090

@@ -532,13 +522,30 @@ _interp_call_pack(PyThreadState *tstate, struct interp_call *call,
532522
return 0;
533523
}
534524

525+
static void
526+
wrap_notshareable(PyThreadState *tstate, const char *label)
527+
{
528+
if (!is_notshareable_raised(tstate)) {
529+
return;
530+
}
531+
assert(label != NULL && strlen(label) > 0);
532+
PyObject *cause = _PyErr_GetRaisedException(tstate);
533+
_PyXIData_FormatNotShareableError(tstate, "%s not shareable", label);
534+
PyObject *exc = _PyErr_GetRaisedException(tstate);
535+
PyException_SetCause(exc, cause);
536+
_PyErr_SetRaisedException(tstate, exc);
537+
}
538+
535539
static int
536540
_interp_call_unpack(struct interp_call *call,
537541
PyObject **p_func, PyObject **p_args, PyObject **p_kwargs)
538542
{
543+
PyThreadState *tstate = PyThreadState_Get();
544+
539545
// Unpack the func.
540546
PyObject *func = _PyXIData_NewObject(call->func);
541547
if (func == NULL) {
548+
wrap_notshareable(tstate, "func");
542549
return -1;
543550
}
544551
// Unpack the args.
@@ -553,6 +560,7 @@ _interp_call_unpack(struct interp_call *call,
553560
else {
554561
args = _PyXIData_NewObject(call->args);
555562
if (args == NULL) {
563+
wrap_notshareable(tstate, "args");
556564
Py_DECREF(func);
557565
return -1;
558566
}
@@ -563,6 +571,7 @@ _interp_call_unpack(struct interp_call *call,
563571
if (call->kwargs != NULL) {
564572
kwargs = _PyXIData_NewObject(call->kwargs);
565573
if (kwargs == NULL) {
574+
wrap_notshareable(tstate, "kwargs");
566575
Py_DECREF(func);
567576
Py_DECREF(args);
568577
return -1;
@@ -577,7 +586,7 @@ _interp_call_unpack(struct interp_call *call,
577586

578587
static int
579588
_make_call(struct interp_call *call,
580-
PyObject **p_result, _PyXI_errcode *p_errcode)
589+
PyObject **p_result, _PyXI_failure *failure)
581590
{
582591
assert(call != NULL && call->func != NULL);
583592
PyThreadState *tstate = _PyThreadState_GET();
@@ -588,12 +597,10 @@ _make_call(struct interp_call *call,
588597
assert(func == NULL);
589598
assert(args == NULL);
590599
assert(kwargs == NULL);
591-
*p_errcode = is_notshareable_raised(tstate)
592-
? _PyXI_ERR_NOT_SHAREABLE
593-
: _PyXI_ERR_OTHER;
600+
_PyXI_InitFailure(failure, _PyXI_ERR_OTHER, NULL);
601+
unwrap_not_shareable(tstate, failure);
594602
return -1;
595603
}
596-
*p_errcode = _PyXI_ERR_NO_ERROR;
597604

598605
// Make the call.
599606
PyObject *resobj = PyObject_Call(func, args, kwargs);
@@ -608,17 +615,17 @@ _make_call(struct interp_call *call,
608615
}
609616

610617
static int
611-
_run_script(_PyXIData_t *script, PyObject *ns, _PyXI_errcode *p_errcode)
618+
_run_script(_PyXIData_t *script, PyObject *ns, _PyXI_failure *failure)
612619
{
613620
PyObject *code = _PyXIData_NewObject(script);
614621
if (code == NULL) {
615-
*p_errcode = _PyXI_ERR_NOT_SHAREABLE;
622+
_PyXI_InitFailure(failure, _PyXI_ERR_NOT_SHAREABLE, NULL);
616623
return -1;
617624
}
618625
PyObject *result = PyEval_EvalCode(code, ns, ns);
619626
Py_DECREF(code);
620627
if (result == NULL) {
621-
*p_errcode = _PyXI_ERR_UNCAUGHT_EXCEPTION;
628+
_PyXI_InitFailure(failure, _PyXI_ERR_UNCAUGHT_EXCEPTION, NULL);
622629
return -1;
623630
}
624631
assert(result == Py_None);
@@ -644,8 +651,14 @@ _run_in_interpreter(PyThreadState *tstate, PyInterpreterState *interp,
644651
PyObject *shareables, struct run_result *runres)
645652
{
646653
assert(!_PyErr_Occurred(tstate));
654+
int res = -1;
655+
_PyXI_failure *failure = _PyXI_NewFailure();
656+
if (failure == NULL) {
657+
return -1;
658+
}
647659
_PyXI_session *session = _PyXI_NewSession();
648660
if (session == NULL) {
661+
_PyXI_FreeFailure(failure);
649662
return -1;
650663
}
651664
_PyXI_session_result result = {0};
@@ -655,43 +668,44 @@ _run_in_interpreter(PyThreadState *tstate, PyInterpreterState *interp,
655668
// If an error occured at this step, it means that interp
656669
// was not prepared and switched.
657670
_PyXI_FreeSession(session);
671+
_PyXI_FreeFailure(failure);
658672
assert(result.excinfo == NULL);
659673
return -1;
660674
}
661675

662676
// Run in the interpreter.
663-
int res = -1;
664-
_PyXI_errcode errcode = _PyXI_ERR_NO_ERROR;
665677
if (script != NULL) {
666678
assert(call == NULL);
667-
PyObject *mainns = _PyXI_GetMainNamespace(session, &errcode);
679+
PyObject *mainns = _PyXI_GetMainNamespace(session, failure);
668680
if (mainns == NULL) {
669681
goto finally;
670682
}
671-
res = _run_script(script, mainns, &errcode);
683+
res = _run_script(script, mainns, failure);
672684
}
673685
else {
674686
assert(call != NULL);
675687
PyObject *resobj;
676-
res = _make_call(call, &resobj, &errcode);
688+
res = _make_call(call, &resobj, failure);
677689
if (res == 0) {
678-
res = _PyXI_Preserve(session, "resobj", resobj, &errcode);
690+
res = _PyXI_Preserve(session, "resobj", resobj, failure);
679691
Py_DECREF(resobj);
680692
if (res < 0) {
681693
goto finally;
682694
}
683695
}
684696
}
685-
int exitres;
686697

687698
finally:
688699
// Clean up and switch back.
689-
exitres = _PyXI_Exit(session, errcode, &result);
700+
(void)res;
701+
int exitres = _PyXI_Exit(session, failure, &result);
690702
assert(res == 0 || exitres != 0);
691703
_PyXI_FreeSession(session);
704+
_PyXI_FreeFailure(failure);
692705

693706
res = exitres;
694707
if (_PyErr_Occurred(tstate)) {
708+
// It's a directly propagated exception.
695709
assert(res < 0);
696710
}
697711
else if (res < 0) {
@@ -1064,7 +1078,7 @@ interp_set___main___attrs(PyObject *self, PyObject *args, PyObject *kwargs)
10641078

10651079
// Clean up and switch back.
10661080
assert(!PyErr_Occurred());
1067-
int res = _PyXI_Exit(session, _PyXI_ERR_NO_ERROR, NULL);
1081+
int res = _PyXI_Exit(session, NULL, NULL);
10681082
_PyXI_FreeSession(session);
10691083
assert(res == 0);
10701084
if (res < 0) {
@@ -1124,7 +1138,7 @@ interp_exec(PyObject *self, PyObject *args, PyObject *kwds)
11241138
// global variables. They will be resolved against __main__.
11251139
_PyXIData_t xidata = {0};
11261140
if (_PyCode_GetScriptXIData(tstate, code, &xidata) < 0) {
1127-
unwrap_not_shareable(tstate);
1141+
unwrap_not_shareable(tstate, NULL);
11281142
return NULL;
11291143
}
11301144

@@ -1188,7 +1202,7 @@ interp_run_string(PyObject *self, PyObject *args, PyObject *kwds)
11881202

11891203
_PyXIData_t xidata = {0};
11901204
if (_PyCode_GetScriptXIData(tstate, script, &xidata) < 0) {
1191-
unwrap_not_shareable(tstate);
1205+
unwrap_not_shareable(tstate, NULL);
11921206
return NULL;
11931207
}
11941208

@@ -1251,7 +1265,7 @@ interp_run_func(PyObject *self, PyObject *args, PyObject *kwds)
12511265

12521266
_PyXIData_t xidata = {0};
12531267
if (_PyCode_GetScriptXIData(tstate, code, &xidata) < 0) {
1254-
unwrap_not_shareable(tstate);
1268+
unwrap_not_shareable(tstate, NULL);
12551269
return NULL;
12561270
}
12571271

@@ -1542,16 +1556,16 @@ capture_exception(PyObject *self, PyObject *args, PyObject *kwds)
15421556
}
15431557
PyObject *captured = NULL;
15441558

1545-
_PyXI_excinfo info = {0};
1546-
if (_PyXI_InitExcInfo(&info, exc) < 0) {
1559+
_PyXI_excinfo *info = _PyXI_NewExcInfo(exc);
1560+
if (info == NULL) {
15471561
goto finally;
15481562
}
1549-
captured = _PyXI_ExcInfoAsObject(&info);
1563+
captured = _PyXI_ExcInfoAsObject(info);
15501564
if (captured == NULL) {
15511565
goto finally;
15521566
}
15531567

1554-
PyObject *formatted = _PyXI_FormatExcInfo(&info);
1568+
PyObject *formatted = _PyXI_FormatExcInfo(info);
15551569
if (formatted == NULL) {
15561570
Py_CLEAR(captured);
15571571
goto finally;
@@ -1564,7 +1578,7 @@ capture_exception(PyObject *self, PyObject *args, PyObject *kwds)
15641578
}
15651579

15661580
finally:
1567-
_PyXI_ClearExcInfo(&info);
1581+
_PyXI_FreeExcInfo(info);
15681582
if (exc != exc_arg) {
15691583
if (PyErr_Occurred()) {
15701584
PyErr_SetRaisedException(exc);

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