Skip to content

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

Merged
ambv merged 6 commits into
python:mainfrom
iritkatriel:bpo-45083
Sep 3, 2021
Merged

bpo-45083: Include the exception class qualname when formatting an ex…#28119
ambv merged 6 commits into
python:mainfrom
iritkatriel:bpo-45083

Conversation

@iritkatriel

@iritkatriel iritkatriel commented Sep 1, 2021

Copy link
Copy Markdown
Member

@erlend-aasland erlend-aasland left a comment

Copy link
Copy Markdown
Contributor

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.

Comment thread Python/pythonrun.c Outdated
Comment thread Python/pythonrun.c Outdated
Comment thread Python/errors.c Outdated
iritkatriel and others added 3 commits September 2, 2021 10:36
Co-authored-by: Erlend Egeberg Aasland <erlend.aasland@innova.no>
Co-authored-by: Erlend Egeberg Aasland <erlend.aasland@innova.no>
Co-authored-by: Erlend Egeberg Aasland <erlend.aasland@innova.no>
@iritkatriel iritkatriel added the 🔨 test-with-buildbots Test PR w/ buildbots; report in status section label Sep 2, 2021
@bedevere-bot

Copy link
Copy Markdown

🤖 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
Comment thread Python/errors.c Outdated
Comment thread Python/pythonrun.c Outdated
Comment thread Python/pythonrun.c Outdated
Comment thread Python/pythonrun.c Outdated
Comment thread Python/pythonrun.c Outdated
Comment thread Python/errors.c Outdated
@erlend-aasland

Copy link
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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).

Comment thread Python/errors.c
if (className == NULL) {

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

Copy link
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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 commented Sep 3, 2021

Copy link
Copy Markdown
Contributor

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
Copy Markdown
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
Copy Markdown

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
Copy Markdown

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

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 <erlend.aasland@innova.no>
(cherry picked from commit b4b6342)

Co-authored-by: Irit Katriel <1055913+iritkatriel@users.noreply.github.com>
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 <erlend.aasland@innova.no>
(cherry picked from commit b4b6342)

Co-authored-by: Irit Katriel <1055913+iritkatriel@users.noreply.github.com>
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 <erlend.aasland@innova.no>
(cherry picked from commit b4b6342)

Co-authored-by: Irit Katriel <1055913+iritkatriel@users.noreply.github.com>
Co-authored-by: Łukasz Langa <lukasz@langa.pl>
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 <erlend.aasland@innova.no>
(cherry picked from commit b4b6342)

Co-authored-by: Irit Katriel <1055913+iritkatriel@users.noreply.github.com>

* Use a private version of _PyType_GetQualName

Co-authored-by: Łukasz Langa <lukasz@langa.pl>
@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