8000 gh-106672: C API: Report indiscriminately ignored errors by serhiy-storchaka · Pull Request #106674 · python/cpython · GitHub
[go: up one dir, main page]

Skip to content

gh-106672: C API: Report indiscriminately ignored errors #106674

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

Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
e134bad
gh-106672: C API: Report indiscriminately ignored errors
serhiy-storchaka Jul 12, 2023
00ce038
Update output messsages.
serhiy-storchaka Jul 12, 2023
168f92a
Add an entry in What's New.
serhiy-storchaka Jul 12, 2023
884da66
Merge branch 'main' into capi-write-unraisable-for-ignored-errors
serhiy-storchaka Jul 12, 2023
58dbac5
Merge branch 'main' into capi-write-unraisable-for-ignored-errors
serhiy-storchaka Aug 7, 2023
07c8250
Fix smelly symbol.
serhiy-storchaka Aug 7, 2023
56e3a49
Remove PyDict_GetItem(dict, invalid_key) from test_dict_capi().
serhiy-storchaka Aug 7, 2023
4e13132
Merge branch 'main' into capi-write-unraisable-for-ignored-errors
serhiy-storchaka Aug 7, 2023
b5a661b
Fix regressions in handling NULLs.
serhiy-storchaka Aug 7, 2023
ab5eb8f
Merge branch 'main' into capi-write-unraisable-for-ignored-errors
serhiy-storchaka Aug 12, 2023
c681ce2
Merge branch 'main' into capi-write-unraisable-for-ignored-errors
serhiy-storchaka Aug 26, 2023
82efd1c
Fix merging error.
serhiy-storchaka Aug 26, 2023
c687ff8
Merge branch 'main' into capi-write-unraisable-for-ignored-errors
serhiy-storchaka Nov 5, 2023
310ae51
Add more suggestions.
serhiy-storchaka < 8000 relative-time datetime="2023-11-05T09:05:44Z" class="no-wrap">Nov 5, 2023
241576a
Improve error messages for ignoring errors set before the calls.
serhiy-storchaka Nov 5, 2023
fd50ea9
Apply suggestions from code review
serhiy-storchaka Nov 6, 2023
587b3cc
Address review comments.
serhiy-storchaka Nov 6, 2023
bfb206a
Remove non-existing cases.
serhiy-storchaka Nov 6, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Add more suggestions.
  • Loading branch information
serhiy-storchaka committed Nov 5, 2023
commit 310ae5108eefa699498d60c2f35750881c403676
4 changes: 4 additions & 0 deletions Objects/abstract.c
Original file line number Diff line number Diff line change
Expand Up @@ -2484,6 +2484,7 @@ PyMapping_HasKeyString(PyObject *obj, const char *key)
if (rc < 0) {
PyErr_FormatUnraisable(
"Exception ignored in PyMapping_HasKeyString(); consider using "
"PyMapping_HasKeyStringWithError(), "
"PyMapping_GetOptionalItemString() or PyMapping_GetItemString()");
return 0;
}
Expand All @@ -2492,6 +2493,7 @@ PyMapping_HasKeyString(PyObject *obj, const char *key)
if (rc == 0 && PyErr_Occurred()) {
PyErr_FormatUnraisable(
"Exception ignored in PyMapping_HasKeyString(); consider using "
"PyMapping_HasKeyStringWithError(), "
"PyMapping_GetOptionalItemString() or PyMapping_GetItemString()");
Copy link
Member
@vstinner vstinner Nov 6, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can these 3 functions be called with an exception set? They don't override the exception? That sounds surprising. I would prefer suggesting to not call the function with an exception set. What do you think?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got catch. Indeed, PyMapping_GetOptionalItemString() can only return 0 if no exception is set, so this condition is always false. Also, the alternative functions also can clear exceptions.

I think that we should classify the C API by classes:

  1. Function that can be called when an exception is set, and they do not change it.
  2. Function that can be called when an exception is set, and they do not change it unless they fail.
  3. Function that can be called when an exception is set, but they can change it even at success.
  4. Function that can be called when an exception is set, but the result is ambiguous in some cases (you cannot distinguish some successful results from failure).
  5. Function that should never be called when an exception is set.

There may be more classes.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the general case, to write safe code handling a raised exception, I think the safest option is to keep the exception aside using PyErr_GetRaisedException(). Maybe today some functions are perfectly fine and never override the currently raised exception. But what if tomorrow their implementation changes, and they may start to clear the currently raised exception?

In Python, in an except: block, there is no "currently raised exception" in the C level, even if sys.exc_info() returns the exception. The difference between PyThreadState.exc_info and PyThreadState.current_exception is subtle.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is why it should be clearly documented.

Obviously you can call PyErr_Occurred(), PyErr_GetRaisedException() or PyErr_WriteUnraisable() when an exception is set.

return 0;
}
Expand All @@ -2516,6 +2518,7 @@ PyMapping_HasKey(PyObject *obj, PyObject *key)
if (rc < 0) {
PyErr_FormatUnraisable(
"Exception ignored in PyMapping_HasKey(); consider using "
"PyMapping_HasKeyWithError(), "
"PyMapping_GetOptionalItem() or PyObject_GetItem()");
return 0;
}
Expand All @@ -2524,6 +2527,7 @@ PyMapping_HasKey(PyObject *obj, PyObject *key)
if (rc == 0 && PyErr_Occurred()) {
PyErr_FormatUnraisable(
"Exception ignored in PyMapping_HasKey(); consider using "
"PyMapping_HasKeyWithError(), "
"PyMapping_GetOptionalItem() or PyObject_GetItem()");
return 0;
}
Expand Down
15 changes: 9 additions & 6 deletions Objects/dictobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -1675,7 +1675,7 @@ dict_getitem(PyObject *op, PyObject *key, const char *warnmsg)
if (!PyUnicode_CheckExact(key) || (hash = unicode_get_hash(key)) == -1) {
hash = PyObject_Hash(key);
if (hash == -1) {
PyErr_FormatUnraisable("Exception ignored %s", warnmsg);
PyErr_FormatUnraisable(warnmsg);
return NULL;
}
}
Expand All @@ -1698,7 +1698,7 @@ dict_getitem(PyObject *op, PyObject *key, const char *warnmsg)
/* Ignore any exception raised by the lookup */
PyObject *exc2 = _PyErr_Occurred(tstate);
if (exc2 && !PyErr_GivenExceptionMatches(exc2, PyExc_KeyError)) {
PyErr_FormatUnraisable("Exception ignored %s", warnmsg);
PyErr_FormatUnraisable(warnmsg);
}
_PyErr_SetRaisedException(tstate, exc);

Expand All @@ -1710,8 +1710,8 @@ PyObject *
PyDict_GetItem(PyObject *op, PyObject *key)
{
return dict_getitem(op, key,
"in PyDict_GetItem(); consider using "
"PyDict_GetItemWithError()");
"Exception ignored in PyDict_GetItem(); consider using "
"PyDict_GetItemRef() or PyDict_GetItemWithError()");
}

Py_ssize_t
Expand Down Expand Up @@ -3938,11 +3938,14 @@ PyDict_GetItemString(PyObject *v, const char *key)
kv = PyUnicode_FromString(key);
if (kv == NULL) {
PyErr_FormatUnraisable(
"Exception ignored in PyDict_GetItemString()");
"Exception ignored in PyDict_GetItemString(); consider using "
"PyDict_GetItemRefString()");
return NULL;
}
rv = PyDict_GetItem(v, kv);
rv = dict_getitem(v, kv, "in PyDict_GetItemString()");
rv = dict_getitem(v, kv,
"Exception ignored in PyDict_GetItemString(); consider using "
"PyDict_GetItemRefString()");
Py_DECREF(kv);
return rv; // borrowed reference
}
Expand Down
2 changes: 2 additions & 0 deletions Objects/object.c
Original file line number Diff line number Diff line change
Expand Up @@ -1042,6 +1042,7 @@ PyObject_HasAttrString(PyObject *obj, const char *name)
if (rc < 0) {
PyErr_FormatUnraisable(
"Exception ignored in PyObject_HasAttrString(); consider using "
"PyObject_HasAttrStringWithError(), "
"PyObject_GetOptionalAttrString() or PyObject_GetAttrString()");
return 0;
}
Expand Down Expand Up @@ -1279,6 +1280,7 @@ PyObject_HasAttr(PyObject *obj, PyObject *name)
if (rc < 0) {
PyErr_FormatUnraisable(
"Exception ignored in PyObject_HasAttr(); consider using "
"PyObject_HasAttrWithError(), "
"PyObject_GetOptionalAttr() or PyObject_GetAttr()");
return 0;
}
Expand Down
0