Patch #50002: Display line information for bad \x escapes:
- recognize "SyntaxError"s by the print_file_and_line attribute.
- add the syntaxerror attributes to all exceptions in compile.c.
Fixes #221791
diff --git a/Misc/NEWS b/Misc/NEWS
index 15644b8..58d5a66 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -6,6 +6,9 @@
Core and builtins
+- PyErr_Display will provide file and line information for all exceptions
+ that have an attribute print_file_and_line, not just SyntaxErrors.
+
- The UTF-8 codec will now encode and decode Unicode surrogates
correctly and without raising exceptions for unpaired ones.
diff --git a/Python/compile.c b/Python/compile.c
index dbae00d..de0a8e2 100644
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -465,14 +465,21 @@
Py_INCREF(Py_None);
line = Py_None;
}
- t = Py_BuildValue("(ziOO)", c->c_filename, c->c_lineno,
- Py_None, line);
- if (t == NULL)
- goto exit;
- w = Py_BuildValue("(OO)", v, t);
- if (w == NULL)
- goto exit;
- PyErr_SetObject(exc, w);
+ if (exc == PyExc_SyntaxError) {
+ t = Py_BuildValue("(ziOO)", c->c_filename, c->c_lineno,
+ Py_None, line);
+ if (t == NULL)
+ goto exit;
+ w = Py_BuildValue("(OO)", v, t);
+ if (w == NULL)
+ goto exit;
+ PyErr_SetObject(exc, w);
+ } else {
+ /* Make sure additional exceptions are printed with
+ file and line, also. */
+ PyErr_SetObject(exc, v);
+ PyErr_SyntaxLocation(c->c_filename, c->c_lineno);
+ }
exit:
Py_XDECREF(t);
Py_XDECREF(v);
@@ -1153,7 +1160,8 @@
s++;
len = strlen(s);
if (len > INT_MAX) {
- PyErr_SetString(PyExc_OverflowError, "string to parse is too long");
+ com_error(com, PyExc_OverflowError,
+ "string to parse is too long");
return NULL;
}
if (s[--len] != quote) {
@@ -1171,11 +1179,15 @@
#ifdef Py_USING_UNICODE
if (unicode || Py_UnicodeFlag) {
if (rawmode)
- return PyUnicode_DecodeRawUnicodeEscape(
- s, len, NULL);
+ v = PyUnicode_DecodeRawUnicodeEscape(
+ s, len, NULL);
else
- return PyUnicode_DecodeUnicodeEscape(
+ v = PyUnicode_DecodeUnicodeEscape(
s, len, NULL);
+ if (v == NULL)
+ PyErr_SyntaxLocation(com->c_filename, com->c_lineno);
+ return v;
+
}
#endif
if (rawmode || strchr(s, '\\') == NULL)
@@ -1238,9 +1250,9 @@
*p++ = x;
break;
}
- PyErr_SetString(PyExc_ValueError,
- "invalid \\x escape");
Py_DECREF(v);
+ com_error(com, PyExc_ValueError,
+ "invalid \\x escape");
return NULL;
default:
*p++ = '\\';
diff --git a/Python/errors.c b/Python/errors.c
index 2799cff..13b3d11 100644
--- a/Python/errors.c
+++ b/Python/errors.c
@@ -561,7 +561,9 @@
}
-/* XXX There's a comment missing here */
+/* Set file and line information for the current exception.
+ If the exception is not a SyntaxError, also sets additional attributes
+ to make printing of exceptions believe it is a syntax error. */
void
PyErr_SyntaxLocation(char *filename, int lineno)
@@ -596,6 +598,26 @@
Py_DECREF(tmp);
}
}
+ if (PyObject_SetAttrString(v, "offset", Py_None)) {
+ PyErr_Clear();
+ }
+ if (exc != PyExc_SyntaxError) {
+ if (!PyObject_HasAttrString(v, "msg")) {
+ tmp = PyObject_Str(v);
+ if (tmp) {
+ if (PyObject_SetAttrString(v, "msg", tmp))
+ PyErr_Clear();
+ Py_DECREF(tmp);
+ } else {
+ PyErr_Clear();
+ }
+ }
+ if (!PyObject_HasAttrString(v, "print_file_and_line")) {
+ if (PyObject_SetAttrString(v, "print_file_and_line",
+ Py_None))
+ PyErr_Clear();
+ }
+ }
PyErr_Restore(exc, v, tb);
}
diff --git a/Python/exceptions.c b/Python/exceptions.c
index 99002bf..adfd699 100644
--- a/Python/exceptions.c
+++ b/Python/exceptions.c
@@ -670,7 +670,8 @@
PyObject_SetAttrString(klass, "filename", Py_None) ||
PyObject_SetAttrString(klass, "lineno", Py_None) ||
PyObject_SetAttrString(klass, "offset", Py_None) ||
- PyObject_SetAttrString(klass, "text", Py_None))
+ PyObject_SetAttrString(klass, "text", Py_None) ||
+ PyObject_SetAttrString(klass, "print_file_and_line", Py_None))
{
retval = -1;
}
diff --git a/Python/pythonrun.c b/Python/pythonrun.c
index 6b70739..ad92004 100644
--- a/Python/pythonrun.c
+++ b/Python/pythonrun.c
@@ -920,7 +920,7 @@
if (tb && tb != Py_None)
err = PyTraceBack_Print(tb, f);
if (err == 0 &&
- PyErr_GivenExceptionMatches(exception, PyExc_SyntaxError))
+ PyObject_HasAttrString(v, "print_file_and_line"))
{
PyObject *message;
char *filename, *text;