summaryrefslogtreecommitdiffstats
path: root/Python/errors.c
diff options
context:
space:
mode:
Diffstat (limited to 'Python/errors.c')
-rw-r--r--Python/errors.c403
1 files changed, 289 insertions, 114 deletions
diff --git a/Python/errors.c b/Python/errors.c
index 64ba05d..626b16e 100644
--- a/Python/errors.c
+++ b/Python/errors.c
@@ -10,8 +10,8 @@ extern char *strerror(int);
#endif
#ifdef MS_WINDOWS
-#include "windows.h"
-#include "winbase.h"
+#include <windows.h>
+#include <winbase.h>
#endif
#include <ctype.h>
@@ -52,9 +52,64 @@ PyErr_Restore(PyObject *type, PyObject *value, PyObject *traceback)
void
PyErr_SetObject(PyObject *exception, PyObject *value)
{
- Py_XINCREF(exception);
+ PyThreadState *tstate = PyThreadState_GET();
+ PyObject *exc_value;
+ PyObject *tb = NULL;
+
+ if (exception != NULL &&
+ !PyExceptionClass_Check(exception)) {
+ PyErr_Format(PyExc_SystemError,
+ "exception %R not a BaseException subclass",
+ exception);
+ return;
+ }
Py_XINCREF(value);
- PyErr_Restore(exception, value, (PyObject *)NULL);
+ exc_value = tstate->exc_value;
+ if (exc_value != NULL && exc_value != Py_None) {
+ /* Implicit exception chaining */
+ Py_INCREF(exc_value);
+ if (value == NULL || !PyExceptionInstance_Check(value)) {
+ /* We must normalize the value right now */
+ PyObject *args, *fixed_value;
+ if (value == NULL || value == Py_None)
+ args = PyTuple_New(0);
+ else if (PyTuple_Check(value)) {
+ Py_INCREF(value);
+ args = value;
+ }
+ else
+ args = PyTuple_Pack(1, value);
+ fixed_value = args ?
+ PyEval_CallObject(exception, args) : NULL;
+ Py_XDECREF(args);
+ Py_XDECREF(value);
+ if (fixed_value == NULL)
+ return;
+ value = fixed_value;
+ }
+ /* Avoid reference cycles through the context chain.
+ This is O(chain length) but context chains are
+ usually very short. Sensitive readers may try
+ to inline the call to PyException_GetContext. */
+ if (exc_value != value) {
+ PyObject *o = exc_value, *context;
+ while ((context = PyException_GetContext(o))) {
+ Py_DECREF(context);
+ if (context == value) {
+ PyException_SetContext(o, NULL);
+ break;
+ }
+ o = context;
+ }
+ PyException_SetContext(value, exc_value);
+ } else {
+ Py_DECREF(exc_value);
+ }
+ }
+ if (value != NULL && PyExceptionInstance_Check(value))
+ tb = PyException_GetTraceback(value);
+ Py_XINCREF(exception);
+ PyErr_Restore(exception, value, tb);
}
void
@@ -66,7 +121,7 @@ PyErr_SetNone(PyObject *exception)
void
PyErr_SetString(PyObject *exception, const char *string)
{
- PyObject *value = PyString_FromString(string);
+ PyObject *value = PyUnicode_FromString(string);
PyErr_SetObject(exception, value);
Py_XDECREF(value);
}
@@ -75,9 +130,14 @@ PyErr_SetString(PyObject *exception, const char *string)
PyObject *
PyErr_Occurred(void)
{
- PyThreadState *tstate = PyThreadState_GET();
+ /* If there is no thread state, PyThreadState_GET calls
+ Py_FatalError, which calls PyErr_Occurred. To avoid the
+ resulting infinite loop, we inline PyThreadState_GET here and
+ treat no thread as no error. */
+ PyThreadState *tstate =
+ ((PyThreadState*)_Py_atomic_load_relaxed(&_PyThreadState_Current));
- return tstate->curexc_type;
+ return tstate == NULL ? NULL : tstate->curexc_type;
}
@@ -106,18 +166,12 @@ PyErr_GivenExceptionMatches(PyObject *err, PyObject *exc)
err = PyExceptionInstance_Class(err);
if (PyExceptionClass_Check(err) && PyExceptionClass_Check(exc)) {
- int res = 0, reclimit;
+ int res = 0;
PyObject *exception, *value, *tb;
PyErr_Fetch(&exception, &value, &tb);
- /* Temporarily bump the recursion limit, so that in the most
- common case PyObject_IsSubclass will not raise a recursion
- error we have to ignore anyway. Don't do it when the limit
- is already insanely high, to avoid overflow */
- reclimit = Py_GetRecursionLimit();
- if (reclimit < (1 << 30))
- Py_SetRecursionLimit(reclimit + 5);
- res = PyObject_IsSubclass(err, exc);
- Py_SetRecursionLimit(reclimit);
+ /* PyObject_IsSubclass() can recurse and therefore is
+ not safe (see test_bad_getattr in test.pickletester). */
+ res = PyType_IsSubtype((PyTypeObject *)err, (PyTypeObject *)exc);
/* This function must not fail, so print the error here */
if (res == -1) {
PyErr_WriteUnraisable(err);
@@ -140,6 +194,9 @@ PyErr_ExceptionMatches(PyObject *exc)
/* Used in many places to normalize a raised exception, including in
eval_code2(), do_raise(), and PyErr_Print()
+
+ XXX: should PyErr_NormalizeException() also call
+ PyException_SetTraceback() with the resulting value and tb?
*/
void
PyErr_NormalizeException(PyObject **exc, PyObject **val, PyObject **tb)
@@ -263,6 +320,39 @@ PyErr_Clear(void)
PyErr_Restore(NULL, NULL, NULL);
}
+void
+PyErr_GetExcInfo(PyObject **p_type, PyObject **p_value, PyObject **p_traceback)
+{
+ PyThreadState *tstate = PyThreadState_GET();
+
+ *p_type = tstate->exc_type;
+ *p_value = tstate->exc_value;
+ *p_traceback = tstate->exc_traceback;
+
+ Py_XINCREF(*p_type);
+ Py_XINCREF(*p_value);
+ Py_XINCREF(*p_traceback);
+}
+
+void
+PyErr_SetExcInfo(PyObject *p_type, PyObject *p_value, PyObject *p_traceback)
+{
+ PyObject *oldtype, *oldvalue, *oldtraceback;
+ PyThreadState *tstate = PyThreadState_GET();
+
+ oldtype = tstate->exc_type;
+ oldvalue = tstate->exc_value;
+ oldtraceback = tstate->exc_traceback;
+
+ tstate->exc_type = p_type;
+ tstate->exc_value = p_value;
+ tstate->exc_traceback = p_traceback;
+
+ Py_XDECREF(oldtype);
+ Py_XDECREF(oldvalue);
+ Py_XDECREF(oldtraceback);
+}
+
/* Convenience functions to set a type error exception and return 0 */
int
@@ -276,49 +366,38 @@ PyErr_BadArgument(void)
PyObject *
PyErr_NoMemory(void)
{
- if (PyErr_ExceptionMatches(PyExc_MemoryError))
- /* already current */
- return NULL;
-
- /* raise the pre-allocated instance if it still exists */
- if (PyExc_MemoryErrorInst)
- PyErr_SetObject(PyExc_MemoryError, PyExc_MemoryErrorInst);
- else
- /* this will probably fail since there's no memory and hee,
- hee, we have to instantiate this class
- */
- PyErr_SetNone(PyExc_MemoryError);
-
+ PyErr_SetNone(PyExc_MemoryError);
return NULL;
}
PyObject *
PyErr_SetFromErrnoWithFilenameObject(PyObject *exc, PyObject *filenameObject)
{
- PyObject *v;
- char *s;
+ PyObject *message;
+ PyObject *v, *args;
int i = errno;
-#ifdef PLAN9
- char errbuf[ERRMAX];
-#endif
#ifdef MS_WINDOWS
- char *s_buf = NULL;
- char s_small_buf[28]; /* Room for "Windows Error 0xFFFFFFFF" */
-#endif
+ WCHAR *s_buf = NULL;
+#endif /* Unix/Windows */
+
#ifdef EINTR
if (i == EINTR && PyErr_CheckSignals())
return NULL;
#endif
-#ifdef PLAN9
- rerrstr(errbuf, sizeof errbuf);
- s = errbuf;
+
+#ifndef MS_WINDOWS
+ if (i != 0) {
+ char *s = strerror(i);
+ message = PyUnicode_DecodeLocale(s, "surrogateescape");
+ }
+ else {
+ /* Sometimes errno didn't get set */
+ message = PyUnicode_FromString("Error");
+ }
#else
if (i == 0)
- s = "Error"; /* Sometimes errno didn't get set */
+ message = PyUnicode_FromString("Error"); /* Sometimes errno didn't get set */
else
-#ifndef MS_WINDOWS
- s = strerror(i);
-#else
{
/* Note that the Win32 errors do not lineup with the
errno error. So if the error is in the MSVC error
@@ -326,10 +405,10 @@ PyErr_SetFromErrnoWithFilenameObject(PyObject *exc, PyObject *filenameObject)
a Win32 error code
*/
if (i > 0 && i < _sys_nerr) {
- s = _sys_errlist[i];
+ message = PyUnicode_FromString(_sys_errlist[i]);
}
else {
- int len = FormatMessage(
+ int len = FormatMessageW(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
@@ -338,32 +417,45 @@ PyErr_SetFromErrnoWithFilenameObject(PyObject *exc, PyObject *filenameObject)
MAKELANGID(LANG_NEUTRAL,
SUBLANG_DEFAULT),
/* Default language */
- (LPTSTR) &s_buf,
+ (LPWSTR) &s_buf,
0, /* size not used */
NULL); /* no args */
if (len==0) {
/* Only ever seen this in out-of-mem
situations */
- sprintf(s_small_buf, "Windows Error 0x%X", i);
- s = s_small_buf;
s_buf = NULL;
+ message = PyUnicode_FromFormat("Windows Error 0x%X", i);
} else {
- s = s_buf;
/* remove trailing cr/lf and dots */
- while (len > 0 && (s[len-1] <= ' ' || s[len-1] == '.'))
- s[--len] = '\0';
+ while (len > 0 && (s_buf[len-1] <= L' ' || s_buf[len-1] == L'.'))
+ s_buf[--len] = L'\0';
+ message = PyUnicode_FromWideChar(s_buf, len);
}
}
}
#endif /* Unix/Windows */
-#endif /* PLAN 9*/
+
+ if (message == NULL)
+ {
+#ifdef MS_WINDOWS
+ LocalFree(s_buf);
+#endif
+ return NULL;
+ }
+
if (filenameObject != NULL)
- v = Py_BuildValue("(isO)", i, s, filenameObject);
+ args = Py_BuildValue("(iOO)", i, message, filenameObject);
else
- v = Py_BuildValue("(is)", i, s);
- if (v != NULL) {
- PyErr_SetObject(exc, v);
- Py_DECREF(v);
+ args = Py_BuildValue("(iO)", i, message);
+ Py_DECREF(message);
+
+ if (args != NULL) {
+ v = PyObject_Call(exc, args, NULL);
+ Py_DECREF(args);
+ if (v != NULL) {
+ PyErr_SetObject((PyObject *) Py_TYPE(v), v);
+ Py_DECREF(v);
+ }
}
#ifdef MS_WINDOWS
LocalFree(s_buf);
@@ -375,7 +467,7 @@ PyErr_SetFromErrnoWithFilenameObject(PyObject *exc, PyObject *filenameObject)
PyObject *
PyErr_SetFromErrnoWithFilename(PyObject *exc, const char *filename)
{
- PyObject *name = filename ? PyString_FromString(filename) : NULL;
+ PyObject *name = filename ? PyUnicode_DecodeFSDefault(filename) : NULL;
PyObject *result = PyErr_SetFromErrnoWithFilenameObject(exc, name);
Py_XDECREF(name);
return result;
@@ -408,13 +500,12 @@ PyObject *PyErr_SetExcFromWindowsErrWithFilenameObject(
PyObject *filenameObject)
{
int len;
- char *s;
- char *s_buf = NULL; /* Free via LocalFree */
- char s_small_buf[28]; /* Room for "Windows Error 0xFFFFFFFF" */
- PyObject *v;
+ WCHAR *s_buf = NULL; /* Free via LocalFree */
+ PyObject *message;
+ PyObject *args, *v;
DWORD err = (DWORD)ierr;
if (err==0) err = GetLastError();
- len = FormatMessage(
+ len = FormatMessageW(
/* Error API error */
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
@@ -423,27 +514,40 @@ PyObject *PyErr_SetExcFromWindowsErrWithFilenameObject(
err,
MAKELANGID(LANG_NEUTRAL,
SUBLANG_DEFAULT), /* Default language */
- (LPTSTR) &s_buf,
+ (LPWSTR) &s_buf,
0, /* size not used */
NULL); /* no args */
if (len==0) {
/* Only seen this in out of mem situations */
- sprintf(s_small_buf, "Windows Error 0x%X", err);
- s = s_small_buf;
+ message = PyUnicode_FromFormat("Windows Error 0x%X", err);
s_buf = NULL;
} else {
- s = s_buf;
/* remove trailing cr/lf and dots */
- while (len > 0 && (s[len-1] <= ' ' || s[len-1] == '.'))
- s[--len] = '\0';
+ while (len > 0 && (s_buf[len-1] <= L' ' || s_buf[len-1] == L'.'))
+ s_buf[--len] = L'\0';
+ message = PyUnicode_FromWideChar(s_buf, len);
}
- if (filenameObject != NULL)
- v = Py_BuildValue("(isO)", err, s, filenameObject);
- else
- v = Py_BuildValue("(is)", err, s);
- if (v != NULL) {
- PyErr_SetObject(exc, v);
- Py_DECREF(v);
+
+ if (message == NULL)
+ {
+ LocalFree(s_buf);
+ return NULL;
+ }
+
+ if (filenameObject == NULL)
+ filenameObject = Py_None;
+ /* This is the constructor signature for passing a Windows error code.
+ The POSIX translation will be figured out by the constructor. */
+ args = Py_BuildValue("(iOOi)", 0, message, filenameObject, err);
+ Py_DECREF(message);
+
+ if (args != NULL) {
+ v = PyObject_Call(exc, args, NULL);
+ Py_DECREF(args);
+ if (v != NULL) {
+ PyErr_SetObject((PyObject *) Py_TYPE(v), v);
+ Py_DECREF(v);
+ }
}
LocalFree(s_buf);
return NULL;
@@ -454,7 +558,7 @@ PyObject *PyErr_SetExcFromWindowsErrWithFilename(
int ierr,
const char *filename)
{
- PyObject *name = filename ? PyString_FromString(filename) : NULL;
+ PyObject *name = filename ? PyUnicode_DecodeFSDefault(filename) : NULL;
PyObject *ret = PyErr_SetExcFromWindowsErrWithFilenameObject(exc,
ierr,
name);
@@ -491,7 +595,7 @@ PyObject *PyErr_SetFromWindowsErrWithFilename(
int ierr,
const char *filename)
{
- PyObject *name = filename ? PyString_FromString(filename) : NULL;
+ PyObject *name = filename ? PyUnicode_DecodeFSDefault(filename) : NULL;
PyObject *result = PyErr_SetExcFromWindowsErrWithFilenameObject(
PyExc_WindowsError,
ierr, name);
@@ -514,8 +618,51 @@ PyObject *PyErr_SetFromWindowsErrWithUnicodeFilename(
}
#endif /* MS_WINDOWS */
+PyObject *
+PyErr_SetImportError(PyObject *msg, PyObject *name, PyObject *path)
+{
+ PyObject *args, *kwargs, *error;
+
+ if (msg == NULL)
+ return NULL;
+
+ args = PyTuple_New(1);
+ if (args == NULL)
+ return NULL;
+
+ kwargs = PyDict_New();
+ if (kwargs == NULL) {
+ Py_DECREF(args);
+ return NULL;
+ }
+
+ if (name == NULL) {
+ name = Py_None;
+ }
+
+ if (path == NULL) {
+ path = Py_None;
+ }
+
+ Py_INCREF(msg);
+ PyTuple_SET_ITEM(args, 0, msg);
+ PyDict_SetItemString(kwargs, "name", name);
+ PyDict_SetItemString(kwargs, "path", path);
+
+ error = PyObject_Call(PyExc_ImportError, args, kwargs);
+ if (error != NULL) {
+ PyErr_SetObject((PyObject *)Py_TYPE(error), error);
+ Py_DECREF(error);
+ }
+
+ Py_DECREF(args);
+ Py_DECREF(kwargs);
+
+ return NULL;
+}
+
void
-_PyErr_BadInternalCall(char *filename, int lineno)
+_PyErr_BadInternalCall(const char *filename, int lineno)
{
PyErr_Format(PyExc_SystemError,
"%s:%d: bad argument to internal function",
@@ -547,7 +694,7 @@ PyErr_Format(PyObject *exception, const char *format, ...)
va_start(vargs);
#endif
- string = PyString_FromFormatV(format, vargs);
+ string = PyUnicode_FromFormatV(format, vargs);
PyErr_SetObject(exception, string);
Py_XDECREF(string);
va_end(vargs);
@@ -557,9 +704,9 @@ PyErr_Format(PyObject *exception, const char *format, ...)
PyObject *
-PyErr_NewException(char *name, PyObject *base, PyObject *dict)
+PyErr_NewException(const char *name, PyObject *base, PyObject *dict)
{
- char *dot;
+ const char *dot;
PyObject *modulename = NULL;
PyObject *classname = NULL;
PyObject *mydict = NULL;
@@ -579,7 +726,7 @@ PyErr_NewException(char *name, PyObject *base, PyObject *dict)
goto failure;
}
if (PyDict_GetItemString(dict, "__module__") == NULL) {
- modulename = PyString_FromStringAndSize(name,
+ modulename = PyUnicode_FromStringAndSize(name,
(Py_ssize_t)(dot-name));
if (modulename == NULL)
goto failure;
@@ -595,7 +742,7 @@ PyErr_NewException(char *name, PyObject *base, PyObject *dict)
if (bases == NULL)
goto failure;
}
- /* Create a real new-style class. */
+ /* Create a real class. */
result = PyObject_CallFunction((PyObject *)&PyType_Type, "sOO",
dot+1, bases, dict);
failure:
@@ -609,7 +756,8 @@ PyErr_NewException(char *name, PyObject *base, PyObject *dict)
/* Create an exception with docstring */
PyObject *
-PyErr_NewExceptionWithDoc(char *name, char *doc, PyObject *base, PyObject *dict)
+PyErr_NewExceptionWithDoc(const char *name, const char *doc,
+ PyObject *base, PyObject *dict)
{
int result;
PyObject *ret = NULL;
@@ -624,7 +772,7 @@ PyErr_NewExceptionWithDoc(char *name, char *doc, PyObject *base, PyObject *dict)
}
if (doc != NULL) {
- docobj = PyString_FromString(doc);
+ docobj = PyUnicode_FromString(doc);
if (docobj == NULL)
goto failure;
result = PyDict_SetItemString(dict, "__doc__", docobj);
@@ -645,10 +793,11 @@ PyErr_NewExceptionWithDoc(char *name, char *doc, PyObject *base, PyObject *dict)
void
PyErr_WriteUnraisable(PyObject *obj)
{
+ _Py_IDENTIFIER(__module__);
PyObject *f, *t, *v, *tb;
PyErr_Fetch(&t, &v, &tb);
f = PySys_GetObject("stderr");
- if (f != NULL) {
+ if (f != NULL && f != Py_None) {
PyFile_WriteString("Exception ", f);
if (t) {
PyObject* moduleName;
@@ -661,13 +810,13 @@ PyErr_WriteUnraisable(PyObject *obj)
className = dot+1;
}
- moduleName = PyObject_GetAttrString(t, "__module__");
+ moduleName = _PyObject_GetAttrId(t, &PyId___module__);
if (moduleName == NULL)
PyFile_WriteString("<unknown>", f);
else {
- char* modstr = PyString_AsString(moduleName);
+ char* modstr = _PyUnicode_AsString(moduleName);
if (modstr &&
- strcmp(modstr, "exceptions") != 0)
+ strcmp(modstr, "builtins") != 0)
{
PyFile_WriteString(modstr, f);
PyFile_WriteString(".", f);
@@ -683,8 +832,10 @@ PyErr_WriteUnraisable(PyObject *obj)
}
Py_XDECREF(moduleName);
}
- PyFile_WriteString(" in ", f);
- PyFile_WriteObject(obj, f, 0);
+ if (obj) {
+ PyFile_WriteString(" in ", f);
+ PyFile_WriteObject(obj, f, 0);
+ }
PyFile_WriteString(" ignored\n", f);
PyErr_Clear(); /* Just in case */
}
@@ -696,75 +847,95 @@ PyErr_WriteUnraisable(PyObject *obj)
extern PyObject *PyModule_GetWarningsModule(void);
+void
+PyErr_SyntaxLocation(const char *filename, int lineno) {
+ PyErr_SyntaxLocationEx(filename, lineno, -1);
+}
+
+
/* 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(const char *filename, int lineno)
+PyErr_SyntaxLocationEx(const char *filename, int lineno, int col_offset)
{
PyObject *exc, *v, *tb, *tmp;
+ _Py_IDENTIFIER(filename);
+ _Py_IDENTIFIER(lineno);
+ _Py_IDENTIFIER(msg);
+ _Py_IDENTIFIER(offset);
+ _Py_IDENTIFIER(print_file_and_line);
+ _Py_IDENTIFIER(text);
/* add attributes for the line number and filename for the error */
PyErr_Fetch(&exc, &v, &tb);
PyErr_NormalizeException(&exc, &v, &tb);
/* XXX check that it is, indeed, a syntax error. It might not
* be, though. */
- tmp = PyInt_FromLong(lineno);
+ tmp = PyLong_FromLong(lineno);
if (tmp == NULL)
PyErr_Clear();
else {
- if (PyObject_SetAttrString(v, "lineno", tmp))
+ if (_PyObject_SetAttrId(v, &PyId_lineno, tmp))
PyErr_Clear();
Py_DECREF(tmp);
}
+ if (col_offset >= 0) {
+ tmp = PyLong_FromLong(col_offset);
+ if (tmp == NULL)
+ PyErr_Clear();
+ else {
+ if (_PyObject_SetAttrId(v, &PyId_offset, tmp))
+ PyErr_Clear();
+ Py_DECREF(tmp);
+ }
+ }
if (filename != NULL) {
- tmp = PyString_FromString(filename);
+ tmp = PyUnicode_DecodeFSDefault(filename);
if (tmp == NULL)
PyErr_Clear();
else {
- if (PyObject_SetAttrString(v, "filename", tmp))
+ if (_PyObject_SetAttrId(v, &PyId_filename, tmp))
PyErr_Clear();
Py_DECREF(tmp);
}
tmp = PyErr_ProgramText(filename, lineno);
if (tmp) {
- if (PyObject_SetAttrString(v, "text", tmp))
+ if (_PyObject_SetAttrId(v, &PyId_text, tmp))
PyErr_Clear();
Py_DECREF(tmp);
}
}
- if (PyObject_SetAttrString(v, "offset", Py_None)) {
+ if (_PyObject_SetAttrId(v, &PyId_offset, Py_None)) {
PyErr_Clear();
}
if (exc != PyExc_SyntaxError) {
- if (!PyObject_HasAttrString(v, "msg")) {
+ if (!_PyObject_HasAttrId(v, &PyId_msg)) {
tmp = PyObject_Str(v);
if (tmp) {
- if (PyObject_SetAttrString(v, "msg", tmp))
+ if (_PyObject_SetAttrId(v, &PyId_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))
+ if (!_PyObject_HasAttrId(v, &PyId_print_file_and_line)) {
+ if (_PyObject_SetAttrId(v, &PyId_print_file_and_line,
+ Py_None))
PyErr_Clear();
}
}
PyErr_Restore(exc, v, tb);
}
-/* com_fetch_program_text will attempt to load the line of text that
- the exception refers to. If it fails, it will return NULL but will
- not set an exception.
+/* Attempt to load the line of text that the exception refers to. If it
+ fails, it will return NULL but will not set an exception.
XXX The functionality of this function is quite similar to the
- functionality in tb_displayline() in traceback.c.
-*/
+ functionality in tb_displayline() in traceback.c. */
PyObject *
PyErr_ProgramText(const char *filename, int lineno)
@@ -782,7 +953,8 @@ PyErr_ProgramText(const char *filename, int lineno)
char *pLastChar = &linebuf[sizeof(linebuf) - 2];
do {
*pLastChar = '\0';
- if (Py_UniversalNewlineFgets(linebuf, sizeof linebuf, fp, NULL) == NULL)
+ if (Py_UniversalNewlineFgets(linebuf, sizeof linebuf,
+ fp, NULL) == NULL)
break;
/* fgets read *something*; if it didn't get as
far as pLastChar, it must have found a newline
@@ -794,9 +966,13 @@ PyErr_ProgramText(const char *filename, int lineno)
fclose(fp);
if (i == lineno) {
char *p = linebuf;
+ PyObject *res;
while (*p == ' ' || *p == '\t' || *p == '\014')
p++;
- return PyString_FromString(p);
+ res = PyUnicode_FromString(p);
+ if (res == NULL)
+ PyErr_Clear();
+ return res;
}
return NULL;
}
@@ -804,4 +980,3 @@ PyErr_ProgramText(const char *filename, int lineno)
#ifdef __cplusplus
}
#endif
-