Skip to content

Commit cfeb3b6

Browse files
committed
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
1 parent 290d31e commit cfeb3b6

File tree

5 files changed

+55
-17
lines changed

5 files changed

+55
-17
lines changed

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ Type/class unification and new-style classes
66

77
Core and builtins
88

9+
- PyErr_Display will provide file and line information for all exceptions
10+
that have an attribute print_file_and_line, not just SyntaxErrors.
11+
912
- The UTF-8 codec will now encode and decode Unicode surrogates
1013
correctly and without raising exceptions for unpaired ones.
1114

Python/compile.c

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -465,14 +465,21 @@ com_error(struct compiling *c, PyObject *exc, char *msg)
465465
Py_INCREF(Py_None);
466466
line = Py_None;
467467
}
468-
t = Py_BuildValue("(ziOO)", c->c_filename, c->c_lineno,
469-
Py_None, line);
470-
if (t == NULL)
471-
goto exit;
472-
w = Py_BuildValue("(OO)", v, t);
473-
if (w == NULL)
474-
goto exit;
475-
PyErr_SetObject(exc, w);
468+
if (exc == PyExc_SyntaxError) {
469+
t = Py_BuildValue("(ziOO)", c->c_filename, c->c_lineno,
470+
Py_None, line);
471+
if (t == NULL)
472+
goto exit;
473+
w = Py_BuildValue("(OO)", v, t);
474+
if (w == NULL)
475+
goto exit;
476+
PyErr_SetObject(exc, w);
477+
} else {
478+
/* Make sure additional exceptions are printed with
479+
file and line, also. */
480+
PyErr_SetObject(exc, v);
481+
PyErr_SyntaxLocation(c->c_filename, c->c_lineno);
482+
}
476483
exit:
477484
Py_XDECREF(t);
478485
Py_XDECREF(v);
@@ -1153,7 +1160,8 @@ parsestr(struct compiling *com, char *s)
11531160
s++;
11541161
len = strlen(s);
11551162
if (len > INT_MAX) {
1156-
PyErr_SetString(PyExc_OverflowError, "string to parse is too long");
1163+
com_error(com, PyExc_OverflowError,
1164+
"string to parse is too long");
11571165
return NULL;
11581166
}
11591167
if (s[--len] != quote) {
@@ -1171,11 +1179,15 @@ parsestr(struct compiling *com, char *s)
11711179
#ifdef Py_USING_UNICODE
11721180
if (unicode || Py_UnicodeFlag) {
11731181
if (rawmode)
1174-
return PyUnicode_DecodeRawUnicodeEscape(
1175-
s, len, NULL);
1182+
v = PyUnicode_DecodeRawUnicodeEscape(
1183+
s, len, NULL);
11761184
else
1177-
return PyUnicode_DecodeUnicodeEscape(
1185+
v = PyUnicode_DecodeUnicodeEscape(
11781186
s, len, NULL);
1187+
if (v == NULL)
1188+
PyErr_SyntaxLocation(com->c_filename, com->c_lineno);
1189+
return v;
1190+
11791191
}
11801192
#endif
11811193
if (rawmode || strchr(s, '\\') == NULL)
@@ -1238,9 +1250,9 @@ parsestr(struct compiling *com, char *s)
12381250
*p++ = x;
12391251
break;
12401252
}
1241-
PyErr_SetString(PyExc_ValueError,
1242-
"invalid \\x escape");
12431253
Py_DECREF(v);
1254+
com_error(com, PyExc_ValueError,
1255+
"invalid \\x escape");
12441256
return NULL;
12451257
default:
12461258
*p++ = '\\';

Python/errors.c

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -561,7 +561,9 @@ PyErr_WarnExplicit(PyObject *category, char *message,
561561
}
562562

563563

564-
/* XXX There's a comment missing here */
564+
/* Set file and line information for the current exception.
565+
If the exception is not a SyntaxError, also sets additional attributes
566+
to make printing of exceptions believe it is a syntax error. */
565567

566568
void
567569
PyErr_SyntaxLocation(char *filename, int lineno)
@@ -596,6 +598,26 @@ PyErr_SyntaxLocation(char *filename, int lineno)
596598
Py_DECREF(tmp);
597599
}
598600
}
601+
if (PyObject_SetAttrString(v, "offset", Py_None)) {
602+
PyErr_Clear();
603+
}
604+
if (exc != PyExc_SyntaxError) {
605+
if (!PyObject_HasAttrString(v, "msg")) {
606+
tmp = PyObject_Str(v);
607+
if (tmp) {
608+
if (PyObject_SetAttrString(v, "msg", tmp))
609+
PyErr_Clear();
610+
Py_DECREF(tmp);
611+
} else {
612+
PyErr_Clear();
613+
}
614+
}
615+
if (!PyObject_HasAttrString(v, "print_file_and_line")) {
616+
if (PyObject_SetAttrString(v, "print_file_and_line",
617+
Py_None))
618+
PyErr_Clear();
619+
}
620+
}
599621
PyErr_Restore(exc, v, tb);
600622
}
601623

Python/exceptions.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -670,7 +670,8 @@ SyntaxError__classinit__(PyObject *klass)
670670
PyObject_SetAttrString(klass, "filename", Py_None) ||
671671
PyObject_SetAttrString(klass, "lineno", Py_None) ||
672672
PyObject_SetAttrString(klass, "offset", Py_None) ||
673-
PyObject_SetAttrString(klass, "text", Py_None))
673+
PyObject_SetAttrString(klass, "text", Py_None) ||
674+
PyObject_SetAttrString(klass, "print_file_and_line", Py_None))
674675
{
675676
retval = -1;
676677
}

Python/pythonrun.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -920,7 +920,7 @@ void PyErr_Display(PyObject *exception, PyObject *value, PyObject *tb)
920920
if (tb && tb != Py_None)
921921
err = PyTraceBack_Print(tb, f);
922922
if (err == 0 &&
923-
PyErr_GivenExceptionMatches(exception, PyExc_SyntaxError))
923+
PyObject_HasAttrString(v, "print_file_and_line"))
924924
{
925925
PyObject *message;
926926
char *filename, *text;

0 commit comments

Comments
 (0)