The Wayback Machine - https://web.archive.org/web/20250620193532/https://github.com/python/cpython/pull/28119
Skip to content

bpo-45083: Include the exception class qualname when formatting an ex… #28119

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
merged 6 commits into from
Sep 3, 2021

Conversation

iritkatriel
Copy link
Member

@iritkatriel iritkatriel commented Sep 1, 2021

Copy link
Contributor

@erlend-aasland erlend-aasland left a comment

Choose a reason for hiding this comment

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

I left some nitpicky code style remarks.

iritkatriel and others added 3 commits September 2, 2021 10:36
Co-authored-by: Erlend Egeberg Aasland <[email protected]>
Co-authored-by: Erlend Egeberg Aasland <[email protected]>
Co-authored-by: Erlend Egeberg Aasland <[email protected]>
@iritkatriel iritkatriel added the 🔨 test-with-buildbots Test PR w/ buildbots; report in status section label Sep 2, 2021
@bedevere-bot
Copy link

🤖 New build scheduled with the buildbot fleet by @iritkatriel for commit 9781ce5 🤖

If you want to schedule another build, you need to add the ":hammer: test-with-buildbots" label again.

@bedevere-bot bedevere-bot removed the 🔨 test-with-buildbots Test PR w/ buildbots; report in status section label Sep 2, 2021
@erlend-aasland
Copy link
Contributor

In order to free qual name easily in Python/errors.c, I moved PyType_GetQualName and PyUnicode_AsUTF8 down to where class name is actually used. Ditto for Python/pythonrun.c.

patch
diff --git a/Python/errors.c b/Python/errors.c
index e390187215..cfa4275722 100644
--- a/Python/errors.c
+++ b/Python/errors.c
@@ -1287,14 +1287,6 @@ write_unraisable_exc_file(PyThreadState *tstate, PyObject *exc_type,
     }
 
     assert(PyExceptionClass_Check(exc_type));
-    PyObject *qualName = PyType_GetQualName((PyTypeObject *)exc_type);
-    if (qualName == NULL) {
-        return -1;
-    }
-    const char *className = PyUnicode_AsUTF8(qualName);
-    if (!className) {
-        return -1;
-    }
 
     PyObject *moduleName = _PyObject_GetAttrId(exc_type, &PyId___module__);
     if (moduleName == NULL || !PyUnicode_Check(moduleName)) {
@@ -1319,13 +1311,22 @@ write_unraisable_exc_file(PyThreadState *tstate, PyObject *exc_type,
             Py_DECREF(moduleName);
         }
     }
-    if (className == NULL) {
+
+    PyObject *qualname = PyType_GetQualName((PyTypeObject *)exc_type);
+    if (qualname == NULL) {
+        return -1;
+    }
+    const char *classname = PyUnicode_AsUTF8(qualname);
+    if (classname == NULL) {
+        Py_DECREF(qualname);
         if (PyFile_WriteString("<unknown>", file) < 0) {
             return -1;
         }
     }
     else {
-        if (PyFile_WriteString(className, file) < 0) {
+        int rc = PyFile_WriteString(classname, file);
+        Py_DECREF(qualname);
+        if (rc < 0) {
             return -1;
         }
     }
diff --git a/Python/pythonrun.c b/Python/pythonrun.c
index b4e34fb504..b5a3b6979b 100644
--- a/Python/pythonrun.c
+++ b/Python/pythonrun.c
@@ -962,23 +962,10 @@ print_exception(PyObject *f, PyObject *value)
     }
     else {
         PyObject* moduleName;
-        PyObject* qualName;
-        const char *className = NULL;
 
         _Py_IDENTIFIER(__module__);
         assert(PyExceptionClass_Check(type));
 
-        qualName = PyType_GetQualName((PyTypeObject *)type);
-        if (!qualName) {
-            PyErr_Clear();
-        }
-        else {
-            className = PyUnicode_AsUTF8(qualName);
-            if (!className) {
-                PyErr_Clear();
-            }
-        }
-
         moduleName = _PyObject_GetAttrId(type, &PyId___module__);
         if (moduleName == NULL || !PyUnicode_Check(moduleName))
         {
@@ -994,10 +981,20 @@ print_exception(PyObject *f, PyObject *value)
             Py_DECREF(moduleName);
         }
         if (err == 0) {
-            if (className == NULL)
+            PyObject *qualname = PyType_GetQualName((PyTypeObject *)type);
+            if (qualname == NULL) {
+                err = PyFile_WriteString("<unknown>", f);
+            }
+            else {
+                const char *classname = PyUnicode_AsUTF8(qualname);
+                if (classname == NULL) {
                       err = PyFile_WriteString("<unknown>", f);
-            else
-                      err = PyFile_WriteString(className, f);
+                }
+                else {
+                      err = PyFile_WriteString(classname, f);
+                }
+                Py_DECREF(qualname);
+            }
         }
     }
     if (err == 0 && (value != Py_None)) {

@iritkatriel
Copy link
Member Author

Do we not need to clear the error in this case?

-        else {
-            className = PyUnicode_AsUTF8(qualName);
-            if (!className) {
-                PyErr_Clear();
-            }
-        }

@erlend-aasland
Copy link
Contributor

Do we not need to clear the error in this case?

I'm not sure; you probably know that better than me :) IIRC, the old code did not clear the error (on mobile right now, so I can't verify).

if (className == NULL) {

PyObject *qualname = PyType_GetQualName((PyTypeObject *)exc_type);
if (qualname == NULL || !PyUnicode_Check(qualname)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Sorry, one last nitpick :) Unless I've missed something in typeobject.c, qualname is always a unicode object. I suggest using an assert for the unicode check. Ditto for the check in pythonrun.c.

Copy link
Member Author

Choose a reason for hiding this comment

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

I think that's correct, but I wasn't sure we want to assume it here (since this is error handling code, it needs to be very safe while it's not performance sensitive).

There is the same check above for modulename, I think there it is actually necessary.

I'm on the fence, wonder what others think.

Copy link
Contributor

Choose a reason for hiding this comment

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

[...] since this is error handling code, it needs to be very safe while it's not performance sensitive

Good points!

Copy link
Contributor

Choose a reason for hiding this comment

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

Well, you can't make __qualname__ anything else than a string from Python code:

>>> class C: ...
...
>>> C.__name__ = 1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can only assign string to C.__name__, not 'int'
>>> C.__qualname__ = 1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can only assign string to C.__qualname__, not 'int'
>>> C.__module__ = 1
>>>

I don't mind keeping the check though as it's less dramatic than an assert failure. You're right that error handling isn't performance-sensitive.

Copy link
Contributor

Choose a reason for hiding this comment

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

Additionally, this isn't even bona fide "error handling", it's literally about printing the exception out so totally no issue with keeping the additional check.

@ambv ambv added needs backport to 3.9 only security fixes needs backport to 3.10 only security fixes labels Sep 3, 2021
@ambv
Copy link
Contributor

ambv commented Sep 3, 2021

Confirmed no refleaks in test_exceptions and test_concurrent_futures.

@ambv ambv merged commit b4b6342 into python:main Sep 3, 2021
@miss-islington
Copy link
Contributor

Thanks @iritkatriel for the PR, and @ambv for merging it 🌮🎉.. I'm working now to backport this PR to: 3.9, 3.10.
🐍🍒⛏🤖

@bedevere-bot
Copy link

GH-28134 is a backport of this pull request to the 3.10 branch.

@bedevere-bot bedevere-bot removed the needs backport to 3.10 only security fixes label Sep 3, 2021
@bedevere-bot
Copy link

GH-28135 is a backport of this pull request to the 3.9 branch.

@bedevere-bot bedevere-bot removed the needs backport to 3.9 only security fixes label Sep 3, 2021
miss-islington pushed a commit to miss-islington/cpython that referenced this pull request Sep 3, 2021
…ception (pythonGH-28119)

Co-authored-by: Erlend Egeberg Aasland <[email protected]>
(cherry picked from commit b4b6342)

Co-authored-by: Irit Katriel <[email protected]>
miss-islington pushed a commit to miss-islington/cpython that referenced this pull request Sep 3, 2021
…ception (pythonGH-28119)

Co-authored-by: Erlend Egeberg Aasland <[email protected]>
(cherry picked from commit b4b6342)

Co-authored-by: Irit Katriel <[email protected]>
ambv added a commit that referenced this pull request Sep 3, 2021
… an exception (GH-28119) (GH-28135)

* bpo-45083: Include the exception class qualname when formatting an exception (GH-28119)

Co-authored-by: Erlend Egeberg Aasland <[email protected]>
(cherry picked from commit b4b6342)

Co-authored-by: Irit Katriel <[email protected]>
Co-authored-by: Łukasz Langa <[email protected]>
ambv added a commit that referenced this pull request Sep 8, 2021
…g an exception (GH-28119) (GH-28134)

Co-authored-by: Erlend Egeberg Aasland <[email protected]>
(cherry picked from commit b4b6342)

Co-authored-by: Irit Katriel <[email protected]>

* Use a private version of _PyType_GetQualName

Co-authored-by: Łukasz Langa <[email protected]>
@iritkatriel iritkatriel deleted the bpo-45083 branch November 5, 2021 09:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants