Skip to content

Commit 909ef27

Browse files
committed
Fix UnicodeError.__str__ when attributes have a custom __str__.
1 parent ae7f621 commit 909ef27

File tree

1 file changed

+44
-15
lines changed

1 file changed

+44
-15
lines changed

Objects/exceptions.c

Lines changed: 44 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2673,6 +2673,8 @@ SyntaxError_str(PySyntaxErrorObject *self)
26732673
if (!filename && !have_lineno)
26742674
return PyObject_Str(self->msg ? self->msg : Py_None);
26752675

2676+
// Even if 'filename' can be an instance of a subclass of 'str',
2677+
// we only render its "true" content and do not use str(filename).
26762678
if (filename && have_lineno)
26772679
result = PyUnicode_FromFormat("%S (%U, line %ld)",
26782680
self->msg ? self->msg : Py_None,
@@ -2790,29 +2792,47 @@ SimpleExtendsException(PyExc_ValueError, UnicodeError,
27902792

27912793
/*
27922794
* Check the validity of 'attr' as a unicode or bytes object depending
2793-
* on 'as_bytes' and return a new reference on it if it is the case.
2795+
* on 'as_bytes'.
27942796
*
27952797
* The 'name' is the attribute name and is only used for error reporting.
27962798
*
2797-
* On success, this returns a strong reference on 'attr'.
2798-
* On failure, this sets a TypeError and returns NULL.
2799+
* On success, this returns 0.
2800+
* On failure, this sets a TypeError and returns -1.
27992801
*/
2800-
static PyObject *
2801-
as_unicode_error_attribute(PyObject *attr, const char *name, int as_bytes)
2802+
static int
2803+
check_unicode_error_attribute(PyObject *attr, const char *name, int as_bytes)
28022804
{
28032805
assert(as_bytes == 0 || as_bytes == 1);
28042806
if (attr == NULL) {
2805-
PyErr_Format(PyExc_TypeError, "%s attribute not set", name);
2806-
return NULL;
2807+
PyErr_Format(PyExc_TypeError,
2808+
"UnicodeError '%s' attribute is not set",
2809+
name);
2810+
return -1;
28072811
}
28082812
if (!(as_bytes ? PyBytes_Check(attr) : PyUnicode_Check(attr))) {
28092813
PyErr_Format(PyExc_TypeError,
2810-
"%s attribute must be %s",
2811-
name,
2812-
as_bytes ? "bytes" : "unicode");
2813-
return NULL;
2814+
"UnicodeError '%s' attribute must be a %s",
2815+
name, as_bytes ? "bytes" : "string");
2816+
return -1;
28142817
}
2815-
return Py_NewRef(attr);
2818+
return 0;
2819+
}
2820+
2821+
2822+
/*
2823+
* Check the validity of 'attr' as a unicode or bytes object depending
2824+
* on 'as_bytes' and return a new reference on it if it is the case.
2825+
*
2826+
* The 'name' is the attribute name and is only used for error reporting.
2827+
*
2828+
* On success, this returns a strong reference on 'attr'.
2829+
* On failure, this sets a TypeError and returns NULL.
2830+
*/
2831+
static PyObject *
2832+
as_unicode_error_attribute(PyObject *attr, const char *name, int as_bytes)
2833+
{
2834+
int rc = check_unicode_error_attribute(attr, name, as_bytes);
2835+
return rc < 0 ? NULL : Py_NewRef(attr);
28162836
}
28172837

28182838

@@ -3379,7 +3399,10 @@ UnicodeEncodeError_str(PyObject *self)
33793399
if (encoding_str == NULL) {
33803400
goto done;
33813401
}
3382-
3402+
// calls to PyObject_Str(...) above might mutate 'exc->object'
3403+
if (check_unicode_error_attribute(exc->object, "object", false) < 0) {
3404+
goto done;
3405+
}
33833406
Py_ssize_t len = PyUnicode_GET_LENGTH(exc->object);
33843407
Py_ssize_t start = exc->start, end = exc->end;
33853408

@@ -3499,7 +3522,10 @@ UnicodeDecodeError_str(PyObject *self)
34993522
if (encoding_str == NULL) {
35003523
goto done;
35013524
}
3502-
3525+
// calls to PyObject_Str(...) above might mutate 'exc->object'
3526+
if (check_unicode_error_attribute(exc->object, "object", true) < 0) {
3527+
goto done;
3528+
}
35033529
Py_ssize_t len = PyBytes_GET_SIZE(exc->object);
35043530
Py_ssize_t start = exc->start, end = exc->end;
35053531

@@ -3595,7 +3621,10 @@ UnicodeTranslateError_str(PyObject *self)
35953621
if (reason_str == NULL) {
35963622
goto done;
35973623
}
3598-
3624+
// call to PyObject_Str(...) above might mutate 'exc->object'
3625+
if (check_unicode_error_attribute(exc->object, "object", false) < 0) {
3626+
goto done;
3627+
}
35993628
Py_ssize_t len = PyUnicode_GET_LENGTH(exc->object);
36003629
Py_ssize_t start = exc->start, end = exc->end;
36013630

0 commit comments

Comments
 (0)