| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent b2fdafe commit 0ddbf47
8 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -24,6 +24,7 @@ PyAPI_FUNC(int) PyTraceBack_Here(struct _frame *); | |||
| 24 | 24 | PyAPI_FUNC(int) PyTraceBack_Print(PyObject *, PyObject *); | |
| 25 | 25 | #ifndef Py_LIMITED_API | |
| 26 | 26 | PyAPI_FUNC(int) _Py_DisplaySourceLine(PyObject *, PyObject *, int, int); | |
| 27 | + PyAPI_FUNC(void) _PyTraceback_Add(char *, char *, int); | ||
| 27 | 28 | #endif | |
| 28 | 29 | ||
| 29 | 30 | /* Reveal traceback type so we can typecheck traceback objects */ | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -2,7 +2,9 @@ | |||
| 2 | 2 | # handler, are obscure and unhelpful. | |
| 3 | 3 | ||
| 4 | 4 | from io import BytesIO | |
| 5 | + import os | ||
| 5 | 6 | import unittest | |
| 7 | + import traceback | ||
| 6 | 8 | ||
| 7 | 9 | from xml.parsers import expat | |
| 8 | 10 | from xml.parsers.expat import errors | |
@@ -419,7 +421,11 @@ class HandlerExceptionTest(unittest.TestCase): | |||
| 419 | 421 | def StartElementHandler(self, name, attrs): | |
| 420 | 422 | raise RuntimeError(name) | |
| 421 | 423 | ||
| 422 | - def test(self): | ||
| 424 | + def check_traceback_entry(self, entry, filename, funcname): | ||
| 425 | + self.assertEqual(os.path.basename(entry[0]), filename) | ||
| 426 | + self.assertEqual(entry[2], funcname) | ||
| 427 | + | ||
| 428 | + def test_exception(self): | ||
| 423 | 429 | parser = expat.ParserCreate() | |
| 424 | 430 | parser.StartElementHandler = self.StartElementHandler | |
| 425 | 431 | try: | |
@@ -429,6 +435,16 @@ def test(self): | |||
| 429 | 435 | self.assertEqual(e.args[0], 'a', | |
| 430 | 436 | "Expected RuntimeError for element 'a', but" + \ | |
| 431 | 437 | " found %r" % e.args[0]) | |
| 438 | + # Check that the traceback contains the relevant line in pyexpat.c | ||
| 439 | + entries = traceback.extract_tb(e.__traceback__) | ||
| 440 | + self.assertEqual(len(entries), 3) | ||
| 441 | + self.check_traceback_entry(entries[0], | ||
| 442 | + "test_pyexpat.py", "test_exception") | ||
| 443 | + self.check_traceback_entry(entries[1], | ||
| 444 | + "pyexpat.c", "StartElement") | ||
| 445 | + self.check_traceback_entry(entries[2], | ||
| 446 | + "test_pyexpat.py", "StartElementHandler") | ||
| 447 | + self.assertIn('call_with_frame("StartElement"', entries[1][3]) | ||
| 432 | 448 | ||
| 433 | 449 | ||
| 434 | 450 | # Test Current* members: | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -24,6 +24,9 @@ Core and Builtins | |||
| 24 | 24 | Library | |
| 25 | 25 | ------- | |
| 26 | 26 | ||
| 27 | + - Issue #22462: Fix pyexpat's creation of a dummy frame to make it | ||
| 28 | + appear in exception tracebacks. | ||
| 29 | + | ||
| 27 | 30 | - Issue #21173: Fix len() on a WeakKeyDictionary when .clear() was called | |
| 28 | 31 | with an iterator alive. | |
| 29 | 32 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -92,49 +92,6 @@ PrintError(char *msg, ...) | |||
| 92 | 92 | } | |
| 93 | 93 | ||
| 94 | 94 | ||
| 95 | - /* after code that pyrex generates */ | ||
| 96 | - void _ctypes_add_traceback(char *funcname, char *filename, int lineno) | ||
| 97 | - { | ||
| 98 | - PyObject *py_globals = 0; | ||
| 99 | - PyCodeObject *py_code = 0; | ||
| 100 | - PyFrameObject *py_frame = 0; | ||
| 101 | - PyObject *exception, *value, *tb; | ||
| 102 | - | ||
| 103 | - /* (Save and) Clear the current exception. Python functions must not be | ||
| 104 | - called with an exception set. Calling Python functions happens when | ||
| 105 | - the codec of the filesystem encoding is implemented in pure Python. */ | ||
| 106 | - PyErr_Fetch(&exception, &value, &tb); | ||
| 107 | - | ||
| 108 | - py_globals = PyDict_New(); | ||
| 109 | - if (!py_globals) | ||
| 110 | - goto bad; | ||
| 111 | - py_code = PyCode_NewEmpty(filename, funcname, lineno); | ||
| 112 | - if (!py_code) | ||
| 113 | - goto bad; | ||
| 114 | - py_frame = PyFrame_New( | ||
| 115 | - PyThreadState_Get(), /*PyThreadState *tstate,*/ | ||
| 116 | - py_code, /*PyCodeObject *code,*/ | ||
| 117 | - py_globals, /*PyObject *globals,*/ | ||
| 118 | - 0 /*PyObject *locals*/ | ||
| 119 | - ); | ||
| 120 | - if (!py_frame) | ||
| 121 | - goto bad; | ||
| 122 | - py_frame->f_lineno = lineno; | ||
| 123 | - | ||
| 124 | - PyErr_Restore(exception, value, tb); | ||
| 125 | - PyTraceBack_Here(py_frame); | ||
| 126 | - | ||
| 127 | - Py_DECREF(py_globals); | ||
| 128 | - Py_DECREF(py_code); | ||
| 129 | - Py_DECREF(py_frame); | ||
| 130 | - return; | ||
| 131 | - | ||
| 132 | - bad: | ||
| 133 | - Py_XDECREF(py_globals); | ||
| 134 | - Py_XDECREF(py_code); | ||
| 135 | - Py_XDECREF(py_frame); | ||
| 136 | - } | ||
| 137 | - | ||
| 138 | 95 | #ifdef MS_WIN32 | |
| 139 | 96 | /* | |
| 140 | 97 | * We must call AddRef() on non-NULL COM pointers we receive as arguments | |
@@ -254,7 +211,7 @@ static void _CallPythonObject(void *mem, | |||
| 254 | 211 | } | |
| 255 | 212 | ||
| 256 | 213 | #define CHECK(what, x) \ | |
| 257 | - if (x == NULL) _ctypes_add_traceback(what, "_ctypes/callbacks.c", __LINE__ - 1), PyErr_Print() | ||
| 214 | + if (x == NULL) _PyTraceback_Add(what, "_ctypes/callbacks.c", __LINE__ - 1), PyErr_Print() | ||
| 258 | 215 | ||
| 259 | 216 | if (flags & (FUNCFLAG_USE_ERRNO | FUNCFLAG_USE_LASTERROR)) { | |
| 260 | 217 | error_object = _ctypes_get_errobj(&space); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -919,7 +919,7 @@ static PyObject *GetResult(PyObject *restype, void *result, PyObject *checker) | |||
| 919 | 919 | ||
| 920 | 920 | v = PyObject_CallFunctionObjArgs(checker, retval, NULL); | |
| 921 | 921 | if (v == NULL) | |
| 922 | - _ctypes_add_traceback("GetResult", "_ctypes/callproc.c", __LINE__-2); | ||
| 922 | + _PyTraceback_Add("GetResult", "_ctypes/callproc.c", __LINE__-2); | ||
| 923 | 923 | Py_DECREF(retval); | |
| 924 | 924 | return v; | |
| 925 | 925 | } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -353,8 +353,6 @@ extern char *_ctypes_conversion_errors; | |||
| 353 | 353 | extern void _ctypes_free_closure(void *); | |
| 354 | 354 | extern void *_ctypes_alloc_closure(void); | |
| 355 | 355 | ||
| 356 | - extern void _ctypes_add_traceback(char *, char *, int); | ||
| 357 | - | ||
| 358 | 356 | extern PyObject *PyCData_FromBaseObj(PyObject *type, PyObject *base, Py_ssize_t index, char *adr); | |
| 359 | 357 | extern char *_ctypes_alloc_format_string(const char *prefix, const char *suffix); | |
| 360 | 358 | extern char *_ctypes_alloc_format_string_with_shape(int ndim, | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -8,8 +8,6 @@ | |||
| 8 | 8 | ||
| 9 | 9 | #define XML_COMBINED_VERSION (10000*XML_MAJOR_VERSION+100*XML_MINOR_VERSION+XML_MICRO_VERSION) | |
| 10 | 10 | ||
| 11 | - #define FIX_TRACE | ||
| 12 | - | ||
| 13 | 11 | static XML_Memory_Handling_Suite ExpatMemoryHandler = { | |
| 14 | 12 | PyObject_Malloc, PyObject_Realloc, PyObject_Free}; | |
| 15 | 13 | ||
@@ -210,121 +208,17 @@ flag_error(xmlparseobject *self) | |||
| 210 | 208 | error_external_entity_ref_handler); | |
| 211 | 209 | } | |
| 212 | 210 | ||
| 213 | - static PyCodeObject* | ||
| 214 | - getcode(enum HandlerTypes slot, char* func_name, int lineno) | ||
| 215 | - { | ||
| 216 | - if (handler_info[slot].tb_code == NULL) { | ||
| 217 | - handler_info[slot].tb_code = | ||
| 218 | - PyCode_NewEmpty(__FILE__, func_name, lineno); | ||
| 219 | - } | ||
| 220 | - return handler_info[slot].tb_code; | ||
| 221 | - } | ||
| 222 | - | ||
| 223 | - #ifdef FIX_TRACE | ||
| 224 | - static int | ||
| 225 | - trace_frame(PyThreadState *tstate, PyFrameObject *f, int code, PyObject *val) | ||
| 226 | - { | ||
| 227 | - int result = 0; | ||
| 228 | - if (!tstate->use_tracing || tstate->tracing) | ||
| 229 | - return 0; | ||
| 230 | - if (tstate->c_profilefunc != NULL) { | ||
| 231 | - tstate->tracing++; | ||
| 232 | - result = tstate->c_profilefunc(tstate->c_profileobj, | ||
| 233 | - f, code , val); | ||
| 234 | - tstate->use_tracing = ((tstate->c_tracefunc != NULL) | ||
| 235 | - || (tstate->c_profilefunc != NULL)); | ||
| 236 | - tstate->tracing--; | ||
| 237 | - if (result) | ||
| 238 | - return result; | ||
| 239 | - } | ||
| 240 | - if (tstate->c_tracefunc != NULL) { | ||
| 241 | - tstate->tracing++; | ||
| 242 | - result = tstate->c_tracefunc(tstate->c_traceobj, | ||
| 243 | - f, code , val); | ||
| 244 | - tstate->use_tracing = ((tstate->c_tracefunc != NULL) | ||
| 245 | - || (tstate->c_profilefunc != NULL)); | ||
| 246 | - tstate->tracing--; | ||
| 247 | - } | ||
| 248 | - return result; | ||
| 249 | - } | ||
| 250 | - | ||
| 251 | - static int | ||
| 252 | - trace_frame_exc(PyThreadState *tstate, PyFrameObject *f) | ||
| 253 | - { | ||
| 254 | - PyObject *type, *value, *traceback, *arg; | ||
| 255 | - int err; | ||
| 256 | - | ||
| 257 | - if (tstate->c_tracefunc == NULL) | ||
| 258 | - return 0; | ||
| 259 | - | ||
| 260 | - PyErr_Fetch(&type, &value, &traceback); | ||
| 261 | - if (value == NULL) { | ||
| 262 | - value = Py_None; | ||
| 263 | - Py_INCREF(value); | ||
| 264 | - } | ||
| 265 | - arg = PyTuple_Pack(3, type, value, traceback); | ||
| 266 | - if (arg == NULL) { | ||
| 267 | - PyErr_Restore(type, value, traceback); | ||
| 268 | - return 0; | ||
| 269 | - } | ||
| 270 | - err = trace_frame(tstate, f, PyTrace_EXCEPTION, arg); | ||
| 271 | - Py_DECREF(arg); | ||
| 272 | - if (err == 0) | ||
| 273 | - PyErr_Restore(type, value, traceback); | ||
| 274 | - else { | ||
| 275 | - Py_XDECREF(type); | ||
| 276 | - Py_XDECREF(value); | ||
| 277 | - Py_XDECREF(traceback); | ||
| 278 | - } | ||
| 279 | - return err; | ||
| 280 | - } | ||
| 281 | - #endif | ||
| 282 | - | ||
| 283 | 211 | static PyObject* | |
| 284 | - call_with_frame(PyCodeObject *c, PyObject* func, PyObject* args, | ||
| 212 | + call_with_frame(char *funcname, int lineno, PyObject* func, PyObject* args, | ||
| 285 | 213 | xmlparseobject *self) | |
| 286 | 214 | { | |
| 287 | - PyThreadState *tstate = PyThreadState_GET(); | ||
| 288 | - PyFrameObject *f; | ||
| 289 | - PyObject *res, *globals; | ||
| 215 | + PyObject *res; | ||
| 290 | 216 | ||
| 291 | - if (c == NULL) | ||
| 292 | - return NULL; | ||
| 293 | - | ||
| 294 | - globals = PyEval_GetGlobals(); | ||
| 295 | - if (globals == NULL) { | ||
| 296 | - return NULL; | ||
| 297 | - } | ||
| 298 | - | ||
| 299 | - f = PyFrame_New(tstate, c, globals, NULL); | ||
| 300 | - if (f == NULL) | ||
| 301 | - return NULL; | ||
| 302 | - tstate->frame = f; | ||
| 303 | - #ifdef FIX_TRACE | ||
| 304 | - if (trace_frame(tstate, f, PyTrace_CALL, Py_None) < 0) { | ||
| 305 | - return NULL; | ||
| 306 | - } | ||
| 307 | - #endif | ||
| 308 | 217 | res = PyEval_CallObject(func, args); | |
| 309 | 218 | if (res == NULL) { | |
| 310 | - if (tstate->curexc_traceback == NULL) | ||
| 311 | - PyTraceBack_Here(f); | ||
| 219 | + _PyTraceback_Add(funcname, __FILE__, lineno); | ||
| 312 | 220 | XML_StopParser(self->itself, XML_FALSE); | |
| 313 | - #ifdef FIX_TRACE | ||
| 314 | - if (trace_frame_exc(tstate, f) < 0) { | ||
| 315 | - return NULL; | ||
| 316 | - } | ||
| 317 | 221 | } | |
| 318 | - else { | ||
| 319 | - if (trace_frame(tstate, f, PyTrace_RETURN, res) < 0) { | ||
| 320 | - Py_CLEAR(res); | ||
| 321 | - } | ||
| 322 | - } | ||
| 323 | - #else | ||
| 324 | - } | ||
| 325 | - #endif | ||
| 326 | - tstate->frame = f->f_back; | ||
| 327 | - Py_DECREF(f); | ||
| 328 | 222 | return res; | |
| 329 | 223 | } | |
| 330 | 224 | ||
@@ -376,7 +270,7 @@ call_character_handler(xmlparseobject *self, const XML_Char *buffer, int len) | |||
| 376 | 270 | PyTuple_SET_ITEM(args, 0, temp); | |
| 377 | 271 | /* temp is now a borrowed reference; consider it unused. */ | |
| 378 | 272 | self->in_callback = 1; | |
| 379 | - temp = call_with_frame(getcode(CharacterData, "CharacterData", __LINE__), | ||
| 273 | + temp = call_with_frame("CharacterData", __LINE__, | ||
| 380 | 274 | self->handlers[CharacterData], args, self); | |
| 381 | 275 | /* temp is an owned reference again, or NULL */ | |
| 382 | 276 | self->in_callback = 0; | |
@@ -508,7 +402,7 @@ my_StartElementHandler(void *userData, | |||
| 508 | 402 | } | |
| 509 | 403 | /* Container is now a borrowed reference; ignore it. */ | |
| 510 | 404 | self->in_callback = 1; | |
| 511 | - rv = call_with_frame(getcode(StartElement, "StartElement", __LINE__), | ||
| 405 | + rv = call_with_frame("StartElement", __LINE__, | ||
| 512 | 406 | self->handlers[StartElement], args, self); | |
| 513 | 407 | self->in_callback = 0; | |
| 514 | 408 | Py_DECREF(args); | |
@@ -537,7 +431,7 @@ my_##NAME##Handler PARAMS {\ | |||
| 537 | 431 | args = Py_BuildValue PARAM_FORMAT ;\ | |
| 538 | 432 | if (!args) { flag_error(self); return RETURN;} \ | |
| 539 | 433 | self->in_callback = 1; \ | |
| 540 | - rv = call_with_frame(getcode(NAME,#NAME,__LINE__), \ | ||
| 434 | + rv = call_with_frame(#NAME,__LINE__, \ | ||
| 541 | 435 | self->handlers[NAME], args, self); \ | |
| 542 | 436 | self->in_callback = 0; \ | |
| 543 | 437 | Py_DECREF(args); \ | |
@@ -669,7 +563,7 @@ my_ElementDeclHandler(void *userData, | |||
| 669 | 563 | goto finally; | |
| 670 | 564 | } | |
| 671 | 565 | self->in_callback = 1; | |
| 672 | - rv = call_with_frame(getcode(ElementDecl, "ElementDecl", __LINE__), | ||
| 566 | + rv = call_with_frame("ElementDecl", __LINE__, | ||
| 673 | 567 | self->handlers[ElementDecl], args, self); | |
| 674 | 568 | self->in_callback = 0; | |
| 675 | 569 | if (rv == NULL) { | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -142,6 +142,39 @@ PyTraceBack_Here(PyFrameObject *frame) | |||
| 142 | 142 | return 0; | |
| 143 | 143 | } | |
| 144 | 144 | ||
| 145 | + /* Insert a frame into the traceback for (funcname, filename, lineno). */ | ||
| 146 | + void _PyTraceback_Add(char *funcname, char *filename, int lineno) | ||
| 147 | + { | ||
| 148 | + PyObject *globals = NULL; | ||
| 149 | + PyCodeObject *code = NULL; | ||
| 150 | + PyFrameObject *frame = NULL; | ||
| 151 | + PyObject *exception, *value, *tb; | ||
| 152 | + | ||
| 153 | + /* Save and clear the current exception. Python functions must not be | ||
| 154 | + called with an exception set. Calling Python functions happens when | ||
| 155 | + the codec of the filesystem encoding is implemented in pure Python. */ | ||
| 156 | + PyErr_Fetch(&exception, &value, &tb); | ||
| 157 | + | ||
| 158 | + globals = PyDict_New(); | ||
| 159 | + if (!globals) | ||
| 160 | + goto done; | ||
| 161 | + code = PyCode_NewEmpty(filename, funcname, lineno); | ||
| 162 | + if (!code) | ||
| 163 | + goto done; | ||
| 164 | + frame = PyFrame_New(PyThreadState_Get(), code, globals, NULL); | ||
| 165 | + if (!frame) | ||
| 166 | + goto done; | ||
| 167 | + frame->f_lineno = lineno; | ||
| 168 | + | ||
| 169 | + PyErr_Restore(exception, value, tb); | ||
| 170 | + PyTraceBack_Here(frame); | ||
| 171 | + | ||
| 172 | + done: | ||
| 173 | + Py_XDECREF(globals); | ||
| 174 | + Py_XDECREF(code); | ||
| 175 | + Py_XDECREF(frame); | ||
| 176 | + } | ||
| 177 | + | ||
| 145 | 178 | static PyObject * | |
| 146 | 179 | _Py_FindSourceFile(PyObject *filename, char* namebuf, size_t namelen, PyObject *io) | |
| 147 | 180 | { | |
| Back | FazBrowse Home | New Git URL |
0 commit comments