/src/Python-3.8.3/Python/traceback.c
Line | Count | Source (jump to first uncovered line) |
1 | | |
2 | | /* Traceback implementation */ |
3 | | |
4 | | #include "Python.h" |
5 | | #include "pycore_pystate.h" |
6 | | |
7 | | #include "code.h" |
8 | | #include "frameobject.h" |
9 | | #include "structmember.h" |
10 | | #include "osdefs.h" |
11 | | #ifdef HAVE_FCNTL_H |
12 | | #include <fcntl.h> |
13 | | #endif |
14 | | |
15 | | #define OFF(x) offsetof(PyTracebackObject, x) |
16 | | |
17 | 0 | #define PUTS(fd, str) _Py_write_noraise(fd, str, (int)strlen(str)) |
18 | 0 | #define MAX_STRING_LENGTH 500 |
19 | 0 | #define MAX_FRAME_DEPTH 100 |
20 | 0 | #define MAX_NTHREADS 100 |
21 | | |
22 | | /* Function from Parser/tokenizer.c */ |
23 | | extern char * PyTokenizer_FindEncodingFilename(int, PyObject *); |
24 | | |
25 | | _Py_IDENTIFIER(TextIOWrapper); |
26 | | _Py_IDENTIFIER(close); |
27 | | _Py_IDENTIFIER(open); |
28 | | _Py_IDENTIFIER(path); |
29 | | |
30 | | /*[clinic input] |
31 | | class TracebackType "PyTracebackObject *" "&PyTraceback_Type" |
32 | | [clinic start generated code]*/ |
33 | | /*[clinic end generated code: output=da39a3ee5e6b4b0d input=928fa06c10151120]*/ |
34 | | |
35 | | #include "clinic/traceback.c.h" |
36 | | |
37 | | static PyObject * |
38 | | tb_create_raw(PyTracebackObject *next, PyFrameObject *frame, int lasti, |
39 | | int lineno) |
40 | 3.53k | { |
41 | 3.53k | PyTracebackObject *tb; |
42 | 3.53k | if ((next != NULL && !PyTraceBack_Check(next)) || |
43 | 3.53k | frame == NULL || !PyFrame_Check(frame)) { |
44 | 0 | PyErr_BadInternalCall(); |
45 | 0 | return NULL; |
46 | 0 | } |
47 | 3.53k | tb = PyObject_GC_New(PyTracebackObject, &PyTraceBack_Type); |
48 | 3.53k | if (tb != NULL) { |
49 | 3.53k | Py_XINCREF(next); |
50 | 3.53k | tb->tb_next = next; |
51 | 3.53k | Py_XINCREF(frame); |
52 | 3.53k | tb->tb_frame = frame; |
53 | 3.53k | tb->tb_lasti = lasti; |
54 | 3.53k | tb->tb_lineno = lineno; |
55 | 3.53k | PyObject_GC_Track(tb); |
56 | 3.53k | } |
57 | 3.53k | return (PyObject *)tb; |
58 | 3.53k | } |
59 | | |
60 | | /*[clinic input] |
61 | | @classmethod |
62 | | TracebackType.__new__ as tb_new |
63 | | |
64 | | tb_next: object |
65 | | tb_frame: object(type='PyFrameObject *', subclass_of='&PyFrame_Type') |
66 | | tb_lasti: int |
67 | | tb_lineno: int |
68 | | |
69 | | Create a new traceback object. |
70 | | [clinic start generated code]*/ |
71 | | |
72 | | static PyObject * |
73 | | tb_new_impl(PyTypeObject *type, PyObject *tb_next, PyFrameObject *tb_frame, |
74 | | int tb_lasti, int tb_lineno) |
75 | | /*[clinic end generated code: output=fa077debd72d861a input=01cbe8ec8783fca7]*/ |
76 | 0 | { |
77 | 0 | if (tb_next == Py_None) { |
78 | 0 | tb_next = NULL; |
79 | 0 | } else if (!PyTraceBack_Check(tb_next)) { |
80 | 0 | return PyErr_Format(PyExc_TypeError, |
81 | 0 | "expected traceback object or None, got '%s'", |
82 | 0 | Py_TYPE(tb_next)->tp_name); |
83 | 0 | } |
84 | | |
85 | 0 | return tb_create_raw((PyTracebackObject *)tb_next, tb_frame, tb_lasti, |
86 | 0 | tb_lineno); |
87 | 0 | } |
88 | | |
89 | | static PyObject * |
90 | | tb_dir(PyTracebackObject *self, PyObject *Py_UNUSED(ignored)) |
91 | 0 | { |
92 | 0 | return Py_BuildValue("[ssss]", "tb_frame", "tb_next", |
93 | 0 | "tb_lasti", "tb_lineno"); |
94 | 0 | } |
95 | | |
96 | | static PyObject * |
97 | | tb_next_get(PyTracebackObject *self, void *Py_UNUSED(_)) |
98 | 28 | { |
99 | 28 | PyObject* ret = (PyObject*)self->tb_next; |
100 | 28 | if (!ret) { |
101 | 14 | ret = Py_None; |
102 | 14 | } |
103 | 28 | Py_INCREF(ret); |
104 | 28 | return ret; |
105 | 28 | } |
106 | | |
107 | | static int |
108 | | tb_next_set(PyTracebackObject *self, PyObject *new_next, void *Py_UNUSED(_)) |
109 | 0 | { |
110 | 0 | if (!new_next) { |
111 | 0 | PyErr_Format(PyExc_TypeError, "can't delete tb_next attribute"); |
112 | 0 | return -1; |
113 | 0 | } |
114 | | |
115 | | /* We accept None or a traceback object, and map None -> NULL (inverse of |
116 | | tb_next_get) */ |
117 | 0 | if (new_next == Py_None) { |
118 | 0 | new_next = NULL; |
119 | 0 | } else if (!PyTraceBack_Check(new_next)) { |
120 | 0 | PyErr_Format(PyExc_TypeError, |
121 | 0 | "expected traceback object, got '%s'", |
122 | 0 | Py_TYPE(new_next)->tp_name); |
123 | 0 | return -1; |
124 | 0 | } |
125 | | |
126 | | /* Check for loops */ |
127 | 0 | PyTracebackObject *cursor = (PyTracebackObject *)new_next; |
128 | 0 | while (cursor) { |
129 | 0 | if (cursor == self) { |
130 | 0 | PyErr_Format(PyExc_ValueError, "traceback loop detected"); |
131 | 0 | return -1; |
132 | 0 | } |
133 | 0 | cursor = cursor->tb_next; |
134 | 0 | } |
135 | | |
136 | 0 | PyObject *old_next = (PyObject*)self->tb_next; |
137 | 0 | Py_XINCREF(new_next); |
138 | 0 | self->tb_next = (PyTracebackObject *)new_next; |
139 | 0 | Py_XDECREF(old_next); |
140 | |
|
141 | 0 | return 0; |
142 | 0 | } |
143 | | |
144 | | |
145 | | static PyMethodDef tb_methods[] = { |
146 | | {"__dir__", (PyCFunction)tb_dir, METH_NOARGS}, |
147 | | {NULL, NULL, 0, NULL}, |
148 | | }; |
149 | | |
150 | | static PyMemberDef tb_memberlist[] = { |
151 | | {"tb_frame", T_OBJECT, OFF(tb_frame), READONLY}, |
152 | | {"tb_lasti", T_INT, OFF(tb_lasti), READONLY}, |
153 | | {"tb_lineno", T_INT, OFF(tb_lineno), READONLY}, |
154 | | {NULL} /* Sentinel */ |
155 | | }; |
156 | | |
157 | | static PyGetSetDef tb_getsetters[] = { |
158 | | {"tb_next", (getter)tb_next_get, (setter)tb_next_set, NULL, NULL}, |
159 | | {NULL} /* Sentinel */ |
160 | | }; |
161 | | |
162 | | static void |
163 | | tb_dealloc(PyTracebackObject *tb) |
164 | 3.53k | { |
165 | 3.53k | PyObject_GC_UnTrack(tb); |
166 | 3.53k | Py_TRASHCAN_BEGIN(tb, tb_dealloc) |
167 | 3.53k | Py_XDECREF(tb->tb_next); |
168 | 3.53k | Py_XDECREF(tb->tb_frame); |
169 | 3.53k | PyObject_GC_Del(tb); |
170 | 3.53k | Py_TRASHCAN_END |
171 | 3.53k | } |
172 | | |
173 | | static int |
174 | | tb_traverse(PyTracebackObject *tb, visitproc visit, void *arg) |
175 | 8 | { |
176 | 8 | Py_VISIT(tb->tb_next); |
177 | 8 | Py_VISIT(tb->tb_frame); |
178 | 8 | return 0; |
179 | 8 | } |
180 | | |
181 | | static int |
182 | | tb_clear(PyTracebackObject *tb) |
183 | 0 | { |
184 | 0 | Py_CLEAR(tb->tb_next); |
185 | 0 | Py_CLEAR(tb->tb_frame); |
186 | 0 | return 0; |
187 | 0 | } |
188 | | |
189 | | PyTypeObject PyTraceBack_Type = { |
190 | | PyVarObject_HEAD_INIT(&PyType_Type, 0) |
191 | | "traceback", |
192 | | sizeof(PyTracebackObject), |
193 | | 0, |
194 | | (destructor)tb_dealloc, /*tp_dealloc*/ |
195 | | 0, /*tp_vectorcall_offset*/ |
196 | | 0, /*tp_getattr*/ |
197 | | 0, /*tp_setattr*/ |
198 | | 0, /*tp_as_async*/ |
199 | | 0, /*tp_repr*/ |
200 | | 0, /*tp_as_number*/ |
201 | | 0, /*tp_as_sequence*/ |
202 | | 0, /*tp_as_mapping*/ |
203 | | 0, /* tp_hash */ |
204 | | 0, /* tp_call */ |
205 | | 0, /* tp_str */ |
206 | | PyObject_GenericGetAttr, /* tp_getattro */ |
207 | | 0, /* tp_setattro */ |
208 | | 0, /* tp_as_buffer */ |
209 | | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */ |
210 | | tb_new__doc__, /* tp_doc */ |
211 | | (traverseproc)tb_traverse, /* tp_traverse */ |
212 | | (inquiry)tb_clear, /* tp_clear */ |
213 | | 0, /* tp_richcompare */ |
214 | | 0, /* tp_weaklistoffset */ |
215 | | 0, /* tp_iter */ |
216 | | 0, /* tp_iternext */ |
217 | | tb_methods, /* tp_methods */ |
218 | | tb_memberlist, /* tp_members */ |
219 | | tb_getsetters, /* tp_getset */ |
220 | | 0, /* tp_base */ |
221 | | 0, /* tp_dict */ |
222 | | 0, /* tp_descr_get */ |
223 | | 0, /* tp_descr_set */ |
224 | | 0, /* tp_dictoffset */ |
225 | | 0, /* tp_init */ |
226 | | 0, /* tp_alloc */ |
227 | | tb_new, /* tp_new */ |
228 | | }; |
229 | | |
230 | | |
231 | | PyObject* |
232 | | _PyTraceBack_FromFrame(PyObject *tb_next, PyFrameObject *frame) |
233 | 3.53k | { |
234 | 3.53k | assert(tb_next == NULL || PyTraceBack_Check(tb_next)); |
235 | 3.53k | assert(frame != NULL); |
236 | | |
237 | 3.53k | return tb_create_raw((PyTracebackObject *)tb_next, frame, frame->f_lasti, |
238 | 3.53k | PyFrame_GetLineNumber(frame)); |
239 | 3.53k | } |
240 | | |
241 | | |
242 | | int |
243 | | PyTraceBack_Here(PyFrameObject *frame) |
244 | 3.53k | { |
245 | 3.53k | PyObject *exc, *val, *tb, *newtb; |
246 | 3.53k | PyErr_Fetch(&exc, &val, &tb); |
247 | 3.53k | newtb = _PyTraceBack_FromFrame(tb, frame); |
248 | 3.53k | if (newtb == NULL) { |
249 | 0 | _PyErr_ChainExceptions(exc, val, tb); |
250 | 0 | return -1; |
251 | 0 | } |
252 | 3.53k | PyErr_Restore(exc, val, newtb); |
253 | 3.53k | Py_XDECREF(tb); |
254 | 3.53k | return 0; |
255 | 3.53k | } |
256 | | |
257 | | /* Insert a frame into the traceback for (funcname, filename, lineno). */ |
258 | | void _PyTraceback_Add(const char *funcname, const char *filename, int lineno) |
259 | 0 | { |
260 | 0 | PyObject *globals; |
261 | 0 | PyCodeObject *code; |
262 | 0 | PyFrameObject *frame; |
263 | 0 | PyObject *exc, *val, *tb; |
264 | | |
265 | | /* Save and clear the current exception. Python functions must not be |
266 | | called with an exception set. Calling Python functions happens when |
267 | | the codec of the filesystem encoding is implemented in pure Python. */ |
268 | 0 | PyErr_Fetch(&exc, &val, &tb); |
269 | |
|
270 | 0 | globals = PyDict_New(); |
271 | 0 | if (!globals) |
272 | 0 | goto error; |
273 | 0 | code = PyCode_NewEmpty(filename, funcname, lineno); |
274 | 0 | if (!code) { |
275 | 0 | Py_DECREF(globals); |
276 | 0 | goto error; |
277 | 0 | } |
278 | 0 | frame = PyFrame_New(PyThreadState_Get(), code, globals, NULL); |
279 | 0 | Py_DECREF(globals); |
280 | 0 | Py_DECREF(code); |
281 | 0 | if (!frame) |
282 | 0 | goto error; |
283 | 0 | frame->f_lineno = lineno; |
284 | |
|
285 | 0 | PyErr_Restore(exc, val, tb); |
286 | 0 | PyTraceBack_Here(frame); |
287 | 0 | Py_DECREF(frame); |
288 | 0 | return; |
289 | | |
290 | 0 | error: |
291 | 0 | _PyErr_ChainExceptions(exc, val, tb); |
292 | 0 | } |
293 | | |
294 | | static PyObject * |
295 | | _Py_FindSourceFile(PyObject *filename, char* namebuf, size_t namelen, PyObject *io) |
296 | 0 | { |
297 | 0 | Py_ssize_t i; |
298 | 0 | PyObject *binary; |
299 | 0 | PyObject *v; |
300 | 0 | Py_ssize_t npath; |
301 | 0 | size_t taillen; |
302 | 0 | PyObject *syspath; |
303 | 0 | PyObject *path; |
304 | 0 | const char* tail; |
305 | 0 | PyObject *filebytes; |
306 | 0 | const char* filepath; |
307 | 0 | Py_ssize_t len; |
308 | 0 | PyObject* result; |
309 | |
|
310 | 0 | filebytes = PyUnicode_EncodeFSDefault(filename); |
311 | 0 | if (filebytes == NULL) { |
312 | 0 | PyErr_Clear(); |
313 | 0 | return NULL; |
314 | 0 | } |
315 | 0 | filepath = PyBytes_AS_STRING(filebytes); |
316 | | |
317 | | /* Search tail of filename in sys.path before giving up */ |
318 | 0 | tail = strrchr(filepath, SEP); |
319 | 0 | if (tail == NULL) |
320 | 0 | tail = filepath; |
321 | 0 | else |
322 | 0 | tail++; |
323 | 0 | taillen = strlen(tail); |
324 | |
|
325 | 0 | syspath = _PySys_GetObjectId(&PyId_path); |
326 | 0 | if (syspath == NULL || !PyList_Check(syspath)) |
327 | 0 | goto error; |
328 | 0 | npath = PyList_Size(syspath); |
329 | |
|
330 | 0 | for (i = 0; i < npath; i++) { |
331 | 0 | v = PyList_GetItem(syspath, i); |
332 | 0 | if (v == NULL) { |
333 | 0 | PyErr_Clear(); |
334 | 0 | break; |
335 | 0 | } |
336 | 0 | if (!PyUnicode_Check(v)) |
337 | 0 | continue; |
338 | 0 | path = PyUnicode_EncodeFSDefault(v); |
339 | 0 | if (path == NULL) { |
340 | 0 | PyErr_Clear(); |
341 | 0 | continue; |
342 | 0 | } |
343 | 0 | len = PyBytes_GET_SIZE(path); |
344 | 0 | if (len + 1 + (Py_ssize_t)taillen >= (Py_ssize_t)namelen - 1) { |
345 | 0 | Py_DECREF(path); |
346 | 0 | continue; /* Too long */ |
347 | 0 | } |
348 | 0 | strcpy(namebuf, PyBytes_AS_STRING(path)); |
349 | 0 | Py_DECREF(path); |
350 | 0 | if (strlen(namebuf) != (size_t)len) |
351 | 0 | continue; /* v contains '\0' */ |
352 | 0 | if (len > 0 && namebuf[len-1] != SEP) |
353 | 0 | namebuf[len++] = SEP; |
354 | 0 | strcpy(namebuf+len, tail); |
355 | |
|
356 | 0 | binary = _PyObject_CallMethodId(io, &PyId_open, "ss", namebuf, "rb"); |
357 | 0 | if (binary != NULL) { |
358 | 0 | result = binary; |
359 | 0 | goto finally; |
360 | 0 | } |
361 | 0 | PyErr_Clear(); |
362 | 0 | } |
363 | 0 | goto error; |
364 | | |
365 | 0 | error: |
366 | 0 | result = NULL; |
367 | 0 | finally: |
368 | 0 | Py_DECREF(filebytes); |
369 | 0 | return result; |
370 | 0 | } |
371 | | |
372 | | int |
373 | | _Py_DisplaySourceLine(PyObject *f, PyObject *filename, int lineno, int indent) |
374 | 0 | { |
375 | 0 | int err = 0; |
376 | 0 | int fd; |
377 | 0 | int i; |
378 | 0 | char *found_encoding; |
379 | 0 | char *encoding; |
380 | 0 | PyObject *io; |
381 | 0 | PyObject *binary; |
382 | 0 | PyObject *fob = NULL; |
383 | 0 | PyObject *lineobj = NULL; |
384 | 0 | PyObject *res; |
385 | 0 | char buf[MAXPATHLEN+1]; |
386 | 0 | int kind; |
387 | 0 | void *data; |
388 | | |
389 | | /* open the file */ |
390 | 0 | if (filename == NULL) |
391 | 0 | return 0; |
392 | | |
393 | 0 | io = PyImport_ImportModuleNoBlock("io"); |
394 | 0 | if (io == NULL) |
395 | 0 | return -1; |
396 | 0 | binary = _PyObject_CallMethodId(io, &PyId_open, "Os", filename, "rb"); |
397 | |
|
398 | 0 | if (binary == NULL) { |
399 | 0 | PyErr_Clear(); |
400 | |
|
401 | 0 | binary = _Py_FindSourceFile(filename, buf, sizeof(buf), io); |
402 | 0 | if (binary == NULL) { |
403 | 0 | Py_DECREF(io); |
404 | 0 | return -1; |
405 | 0 | } |
406 | 0 | } |
407 | | |
408 | | /* use the right encoding to decode the file as unicode */ |
409 | 0 | fd = PyObject_AsFileDescriptor(binary); |
410 | 0 | if (fd < 0) { |
411 | 0 | Py_DECREF(io); |
412 | 0 | Py_DECREF(binary); |
413 | 0 | return 0; |
414 | 0 | } |
415 | 0 | found_encoding = PyTokenizer_FindEncodingFilename(fd, filename); |
416 | 0 | if (found_encoding == NULL) |
417 | 0 | PyErr_Clear(); |
418 | 0 | encoding = (found_encoding != NULL) ? found_encoding : "utf-8"; |
419 | | /* Reset position */ |
420 | 0 | if (lseek(fd, 0, SEEK_SET) == (off_t)-1) { |
421 | 0 | Py_DECREF(io); |
422 | 0 | Py_DECREF(binary); |
423 | 0 | PyMem_FREE(found_encoding); |
424 | 0 | return 0; |
425 | 0 | } |
426 | 0 | fob = _PyObject_CallMethodId(io, &PyId_TextIOWrapper, "Os", binary, encoding); |
427 | 0 | Py_DECREF(io); |
428 | 0 | PyMem_FREE(found_encoding); |
429 | |
|
430 | 0 | if (fob == NULL) { |
431 | 0 | PyErr_Clear(); |
432 | |
|
433 | 0 | res = _PyObject_CallMethodId(binary, &PyId_close, NULL); |
434 | 0 | Py_DECREF(binary); |
435 | 0 | if (res) |
436 | 0 | Py_DECREF(res); |
437 | 0 | else |
438 | 0 | PyErr_Clear(); |
439 | 0 | return 0; |
440 | 0 | } |
441 | 0 | Py_DECREF(binary); |
442 | | |
443 | | /* get the line number lineno */ |
444 | 0 | for (i = 0; i < lineno; i++) { |
445 | 0 | Py_XDECREF(lineobj); |
446 | 0 | lineobj = PyFile_GetLine(fob, -1); |
447 | 0 | if (!lineobj) { |
448 | 0 | PyErr_Clear(); |
449 | 0 | err = -1; |
450 | 0 | break; |
451 | 0 | } |
452 | 0 | } |
453 | 0 | res = _PyObject_CallMethodId(fob, &PyId_close, NULL); |
454 | 0 | if (res) |
455 | 0 | Py_DECREF(res); |
456 | 0 | else |
457 | 0 | PyErr_Clear(); |
458 | 0 | Py_DECREF(fob); |
459 | 0 | if (!lineobj || !PyUnicode_Check(lineobj)) { |
460 | 0 | Py_XDECREF(lineobj); |
461 | 0 | return err; |
462 | 0 | } |
463 | | |
464 | | /* remove the indentation of the line */ |
465 | 0 | kind = PyUnicode_KIND(lineobj); |
466 | 0 | data = PyUnicode_DATA(lineobj); |
467 | 0 | for (i=0; i < PyUnicode_GET_LENGTH(lineobj); i++) { |
468 | 0 | Py_UCS4 ch = PyUnicode_READ(kind, data, i); |
469 | 0 | if (ch != ' ' && ch != '\t' && ch != '\014') |
470 | 0 | break; |
471 | 0 | } |
472 | 0 | if (i) { |
473 | 0 | PyObject *truncated; |
474 | 0 | truncated = PyUnicode_Substring(lineobj, i, PyUnicode_GET_LENGTH(lineobj)); |
475 | 0 | if (truncated) { |
476 | 0 | Py_DECREF(lineobj); |
477 | 0 | lineobj = truncated; |
478 | 0 | } else { |
479 | 0 | PyErr_Clear(); |
480 | 0 | } |
481 | 0 | } |
482 | | |
483 | | /* Write some spaces before the line */ |
484 | 0 | strcpy(buf, " "); |
485 | 0 | assert (strlen(buf) == 10); |
486 | 0 | while (indent > 0) { |
487 | 0 | if (indent < 10) |
488 | 0 | buf[indent] = '\0'; |
489 | 0 | err = PyFile_WriteString(buf, f); |
490 | 0 | if (err != 0) |
491 | 0 | break; |
492 | 0 | indent -= 10; |
493 | 0 | } |
494 | | |
495 | | /* finally display the line */ |
496 | 0 | if (err == 0) |
497 | 0 | err = PyFile_WriteObject(lineobj, f, Py_PRINT_RAW); |
498 | 0 | Py_DECREF(lineobj); |
499 | 0 | if (err == 0) |
500 | 0 | err = PyFile_WriteString("\n", f); |
501 | 0 | return err; |
502 | 0 | } |
503 | | |
504 | | static int |
505 | | tb_displayline(PyObject *f, PyObject *filename, int lineno, PyObject *name) |
506 | 0 | { |
507 | 0 | int err; |
508 | 0 | PyObject *line; |
509 | |
|
510 | 0 | if (filename == NULL || name == NULL) |
511 | 0 | return -1; |
512 | 0 | line = PyUnicode_FromFormat(" File \"%U\", line %d, in %U\n", |
513 | 0 | filename, lineno, name); |
514 | 0 | if (line == NULL) |
515 | 0 | return -1; |
516 | 0 | err = PyFile_WriteObject(line, f, Py_PRINT_RAW); |
517 | 0 | Py_DECREF(line); |
518 | 0 | if (err != 0) |
519 | 0 | return err; |
520 | | /* ignore errors since we can't report them, can we? */ |
521 | 0 | if (_Py_DisplaySourceLine(f, filename, lineno, 4)) |
522 | 0 | PyErr_Clear(); |
523 | 0 | return err; |
524 | 0 | } |
525 | | |
526 | | static const int TB_RECURSIVE_CUTOFF = 3; // Also hardcoded in traceback.py. |
527 | | |
528 | | static int |
529 | | tb_print_line_repeated(PyObject *f, long cnt) |
530 | 0 | { |
531 | 0 | cnt -= TB_RECURSIVE_CUTOFF; |
532 | 0 | PyObject *line = PyUnicode_FromFormat( |
533 | 0 | (cnt > 1) |
534 | 0 | ? " [Previous line repeated %ld more times]\n" |
535 | 0 | : " [Previous line repeated %ld more time]\n", |
536 | 0 | cnt); |
537 | 0 | if (line == NULL) { |
538 | 0 | return -1; |
539 | 0 | } |
540 | 0 | int err = PyFile_WriteObject(line, f, Py_PRINT_RAW); |
541 | 0 | Py_DECREF(line); |
542 | 0 | return err; |
543 | 0 | } |
544 | | |
545 | | static int |
546 | | tb_printinternal(PyTracebackObject *tb, PyObject *f, long limit) |
547 | 0 | { |
548 | 0 | int err = 0; |
549 | 0 | Py_ssize_t depth = 0; |
550 | 0 | PyObject *last_file = NULL; |
551 | 0 | int last_line = -1; |
552 | 0 | PyObject *last_name = NULL; |
553 | 0 | long cnt = 0; |
554 | 0 | PyTracebackObject *tb1 = tb; |
555 | 0 | while (tb1 != NULL) { |
556 | 0 | depth++; |
557 | 0 | tb1 = tb1->tb_next; |
558 | 0 | } |
559 | 0 | while (tb != NULL && depth > limit) { |
560 | 0 | depth--; |
561 | 0 | tb = tb->tb_next; |
562 | 0 | } |
563 | 0 | while (tb != NULL && err == 0) { |
564 | 0 | if (last_file == NULL || |
565 | 0 | tb->tb_frame->f_code->co_filename != last_file || |
566 | 0 | last_line == -1 || tb->tb_lineno != last_line || |
567 | 0 | last_name == NULL || tb->tb_frame->f_code->co_name != last_name) { |
568 | 0 | if (cnt > TB_RECURSIVE_CUTOFF) { |
569 | 0 | err = tb_print_line_repeated(f, cnt); |
570 | 0 | } |
571 | 0 | last_file = tb->tb_frame->f_code->co_filename; |
572 | 0 | last_line = tb->tb_lineno; |
573 | 0 | last_name = tb->tb_frame->f_code->co_name; |
574 | 0 | cnt = 0; |
575 | 0 | } |
576 | 0 | cnt++; |
577 | 0 | if (err == 0 && cnt <= TB_RECURSIVE_CUTOFF) { |
578 | 0 | err = tb_displayline(f, |
579 | 0 | tb->tb_frame->f_code->co_filename, |
580 | 0 | tb->tb_lineno, |
581 | 0 | tb->tb_frame->f_code->co_name); |
582 | 0 | if (err == 0) { |
583 | 0 | err = PyErr_CheckSignals(); |
584 | 0 | } |
585 | 0 | } |
586 | 0 | tb = tb->tb_next; |
587 | 0 | } |
588 | 0 | if (err == 0 && cnt > TB_RECURSIVE_CUTOFF) { |
589 | 0 | err = tb_print_line_repeated(f, cnt); |
590 | 0 | } |
591 | 0 | return err; |
592 | 0 | } |
593 | | |
594 | 0 | #define PyTraceBack_LIMIT 1000 |
595 | | |
596 | | int |
597 | | PyTraceBack_Print(PyObject *v, PyObject *f) |
598 | 0 | { |
599 | 0 | int err; |
600 | 0 | PyObject *limitv; |
601 | 0 | long limit = PyTraceBack_LIMIT; |
602 | |
|
603 | 0 | if (v == NULL) |
604 | 0 | return 0; |
605 | 0 | if (!PyTraceBack_Check(v)) { |
606 | 0 | PyErr_BadInternalCall(); |
607 | 0 | return -1; |
608 | 0 | } |
609 | 0 | limitv = PySys_GetObject("tracebacklimit"); |
610 | 0 | if (limitv && PyLong_Check(limitv)) { |
611 | 0 | int overflow; |
612 | 0 | limit = PyLong_AsLongAndOverflow(limitv, &overflow); |
613 | 0 | if (overflow > 0) { |
614 | 0 | limit = LONG_MAX; |
615 | 0 | } |
616 | 0 | else if (limit <= 0) { |
617 | 0 | return 0; |
618 | 0 | } |
619 | 0 | } |
620 | 0 | err = PyFile_WriteString("Traceback (most recent call last):\n", f); |
621 | 0 | if (!err) |
622 | 0 | err = tb_printinternal((PyTracebackObject *)v, f, limit); |
623 | 0 | return err; |
624 | 0 | } |
625 | | |
626 | | /* Reverse a string. For example, "abcd" becomes "dcba". |
627 | | |
628 | | This function is signal safe. */ |
629 | | |
630 | | void |
631 | | _Py_DumpDecimal(int fd, unsigned long value) |
632 | 0 | { |
633 | | /* maximum number of characters required for output of %lld or %p. |
634 | | We need at most ceil(log10(256)*SIZEOF_LONG_LONG) digits, |
635 | | plus 1 for the null byte. 53/22 is an upper bound for log10(256). */ |
636 | 0 | char buffer[1 + (sizeof(unsigned long)*53-1) / 22 + 1]; |
637 | 0 | char *ptr, *end; |
638 | |
|
639 | 0 | end = &buffer[Py_ARRAY_LENGTH(buffer) - 1]; |
640 | 0 | ptr = end; |
641 | 0 | *ptr = '\0'; |
642 | 0 | do { |
643 | 0 | --ptr; |
644 | 0 | assert(ptr >= buffer); |
645 | 0 | *ptr = '0' + (value % 10); |
646 | 0 | value /= 10; |
647 | 0 | } while (value); |
648 | |
|
649 | 0 | _Py_write_noraise(fd, ptr, end - ptr); |
650 | 0 | } |
651 | | |
652 | | /* Format an integer in range [0; 0xffffffff] to hexadecimal of 'width' digits, |
653 | | and write it into the file fd. |
654 | | |
655 | | This function is signal safe. */ |
656 | | |
657 | | void |
658 | | _Py_DumpHexadecimal(int fd, unsigned long value, Py_ssize_t width) |
659 | 0 | { |
660 | 0 | char buffer[sizeof(unsigned long) * 2 + 1], *ptr, *end; |
661 | 0 | const Py_ssize_t size = Py_ARRAY_LENGTH(buffer) - 1; |
662 | |
|
663 | 0 | if (width > size) |
664 | 0 | width = size; |
665 | | /* it's ok if width is negative */ |
666 | |
|
667 | 0 | end = &buffer[size]; |
668 | 0 | ptr = end; |
669 | 0 | *ptr = '\0'; |
670 | 0 | do { |
671 | 0 | --ptr; |
672 | 0 | assert(ptr >= buffer); |
673 | 0 | *ptr = Py_hexdigits[value & 15]; |
674 | 0 | value >>= 4; |
675 | 0 | } while ((end - ptr) < width || value); |
676 | |
|
677 | 0 | _Py_write_noraise(fd, ptr, end - ptr); |
678 | 0 | } |
679 | | |
680 | | void |
681 | | _Py_DumpASCII(int fd, PyObject *text) |
682 | 0 | { |
683 | 0 | PyASCIIObject *ascii = (PyASCIIObject *)text; |
684 | 0 | Py_ssize_t i, size; |
685 | 0 | int truncated; |
686 | 0 | int kind; |
687 | 0 | void *data = NULL; |
688 | 0 | wchar_t *wstr = NULL; |
689 | 0 | Py_UCS4 ch; |
690 | |
|
691 | 0 | if (!PyUnicode_Check(text)) |
692 | 0 | return; |
693 | | |
694 | 0 | size = ascii->length; |
695 | 0 | kind = ascii->state.kind; |
696 | 0 | if (kind == PyUnicode_WCHAR_KIND) { |
697 | 0 | wstr = ((PyASCIIObject *)text)->wstr; |
698 | 0 | if (wstr == NULL) |
699 | 0 | return; |
700 | 0 | size = ((PyCompactUnicodeObject *)text)->wstr_length; |
701 | 0 | } |
702 | 0 | else if (ascii->state.compact) { |
703 | 0 | if (ascii->state.ascii) |
704 | 0 | data = ((PyASCIIObject*)text) + 1; |
705 | 0 | else |
706 | 0 | data = ((PyCompactUnicodeObject*)text) + 1; |
707 | 0 | } |
708 | 0 | else { |
709 | 0 | data = ((PyUnicodeObject *)text)->data.any; |
710 | 0 | if (data == NULL) |
711 | 0 | return; |
712 | 0 | } |
713 | | |
714 | 0 | if (MAX_STRING_LENGTH < size) { |
715 | 0 | size = MAX_STRING_LENGTH; |
716 | 0 | truncated = 1; |
717 | 0 | } |
718 | 0 | else { |
719 | 0 | truncated = 0; |
720 | 0 | } |
721 | |
|
722 | 0 | for (i=0; i < size; i++) { |
723 | 0 | if (kind != PyUnicode_WCHAR_KIND) |
724 | 0 | ch = PyUnicode_READ(kind, data, i); |
725 | 0 | else |
726 | 0 | ch = wstr[i]; |
727 | 0 | if (' ' <= ch && ch <= 126) { |
728 | | /* printable ASCII character */ |
729 | 0 | char c = (char)ch; |
730 | 0 | _Py_write_noraise(fd, &c, 1); |
731 | 0 | } |
732 | 0 | else if (ch <= 0xff) { |
733 | 0 | PUTS(fd, "\\x"); |
734 | 0 | _Py_DumpHexadecimal(fd, ch, 2); |
735 | 0 | } |
736 | 0 | else if (ch <= 0xffff) { |
737 | 0 | PUTS(fd, "\\u"); |
738 | 0 | _Py_DumpHexadecimal(fd, ch, 4); |
739 | 0 | } |
740 | 0 | else { |
741 | 0 | PUTS(fd, "\\U"); |
742 | 0 | _Py_DumpHexadecimal(fd, ch, 8); |
743 | 0 | } |
744 | 0 | } |
745 | 0 | if (truncated) { |
746 | 0 | PUTS(fd, "..."); |
747 | 0 | } |
748 | 0 | } |
749 | | |
750 | | /* Write a frame into the file fd: "File "xxx", line xxx in xxx". |
751 | | |
752 | | This function is signal safe. */ |
753 | | |
754 | | static void |
755 | | dump_frame(int fd, PyFrameObject *frame) |
756 | 0 | { |
757 | 0 | PyCodeObject *code; |
758 | 0 | int lineno; |
759 | |
|
760 | 0 | code = frame->f_code; |
761 | 0 | PUTS(fd, " File "); |
762 | 0 | if (code != NULL && code->co_filename != NULL |
763 | 0 | && PyUnicode_Check(code->co_filename)) |
764 | 0 | { |
765 | 0 | PUTS(fd, "\""); |
766 | 0 | _Py_DumpASCII(fd, code->co_filename); |
767 | 0 | PUTS(fd, "\""); |
768 | 0 | } else { |
769 | 0 | PUTS(fd, "???"); |
770 | 0 | } |
771 | | |
772 | | /* PyFrame_GetLineNumber() was introduced in Python 2.7.0 and 3.2.0 */ |
773 | 0 | lineno = PyCode_Addr2Line(code, frame->f_lasti); |
774 | 0 | PUTS(fd, ", line "); |
775 | 0 | if (lineno >= 0) { |
776 | 0 | _Py_DumpDecimal(fd, (unsigned long)lineno); |
777 | 0 | } |
778 | 0 | else { |
779 | 0 | PUTS(fd, "???"); |
780 | 0 | } |
781 | 0 | PUTS(fd, " in "); |
782 | |
|
783 | 0 | if (code != NULL && code->co_name != NULL |
784 | 0 | && PyUnicode_Check(code->co_name)) { |
785 | 0 | _Py_DumpASCII(fd, code->co_name); |
786 | 0 | } |
787 | 0 | else { |
788 | 0 | PUTS(fd, "???"); |
789 | 0 | } |
790 | |
|
791 | 0 | PUTS(fd, "\n"); |
792 | 0 | } |
793 | | |
794 | | static void |
795 | | dump_traceback(int fd, PyThreadState *tstate, int write_header) |
796 | 0 | { |
797 | 0 | PyFrameObject *frame; |
798 | 0 | unsigned int depth; |
799 | |
|
800 | 0 | if (write_header) { |
801 | 0 | PUTS(fd, "Stack (most recent call first):\n"); |
802 | 0 | } |
803 | |
|
804 | 0 | frame = _PyThreadState_GetFrame(tstate); |
805 | 0 | if (frame == NULL) { |
806 | 0 | PUTS(fd, "<no Python frame>\n"); |
807 | 0 | return; |
808 | 0 | } |
809 | | |
810 | 0 | depth = 0; |
811 | 0 | while (frame != NULL) { |
812 | 0 | if (MAX_FRAME_DEPTH <= depth) { |
813 | 0 | PUTS(fd, " ...\n"); |
814 | 0 | break; |
815 | 0 | } |
816 | 0 | if (!PyFrame_Check(frame)) |
817 | 0 | break; |
818 | 0 | dump_frame(fd, frame); |
819 | 0 | frame = frame->f_back; |
820 | 0 | depth++; |
821 | 0 | } |
822 | 0 | } |
823 | | |
824 | | /* Dump the traceback of a Python thread into fd. Use write() to write the |
825 | | traceback and retry if write() is interrupted by a signal (failed with |
826 | | EINTR), but don't call the Python signal handler. |
827 | | |
828 | | The caller is responsible to call PyErr_CheckSignals() to call Python signal |
829 | | handlers if signals were received. */ |
830 | | void |
831 | | _Py_DumpTraceback(int fd, PyThreadState *tstate) |
832 | 0 | { |
833 | 0 | dump_traceback(fd, tstate, 1); |
834 | 0 | } |
835 | | |
836 | | /* Write the thread identifier into the file 'fd': "Current thread 0xHHHH:\" if |
837 | | is_current is true, "Thread 0xHHHH:\n" otherwise. |
838 | | |
839 | | This function is signal safe. */ |
840 | | |
841 | | static void |
842 | | write_thread_id(int fd, PyThreadState *tstate, int is_current) |
843 | 0 | { |
844 | 0 | if (is_current) |
845 | 0 | PUTS(fd, "Current thread 0x"); |
846 | 0 | else |
847 | 0 | PUTS(fd, "Thread 0x"); |
848 | 0 | _Py_DumpHexadecimal(fd, |
849 | 0 | tstate->thread_id, |
850 | 0 | sizeof(unsigned long) * 2); |
851 | 0 | PUTS(fd, " (most recent call first):\n"); |
852 | 0 | } |
853 | | |
854 | | /* Dump the traceback of all Python threads into fd. Use write() to write the |
855 | | traceback and retry if write() is interrupted by a signal (failed with |
856 | | EINTR), but don't call the Python signal handler. |
857 | | |
858 | | The caller is responsible to call PyErr_CheckSignals() to call Python signal |
859 | | handlers if signals were received. */ |
860 | | const char* |
861 | | _Py_DumpTracebackThreads(int fd, PyInterpreterState *interp, |
862 | | PyThreadState *current_tstate) |
863 | 0 | { |
864 | 0 | PyThreadState *tstate; |
865 | 0 | unsigned int nthreads; |
866 | |
|
867 | 0 | if (current_tstate == NULL) { |
868 | | /* _Py_DumpTracebackThreads() is called from signal handlers by |
869 | | faulthandler. |
870 | | |
871 | | SIGSEGV, SIGFPE, SIGABRT, SIGBUS and SIGILL are synchronous signals |
872 | | and are thus delivered to the thread that caused the fault. Get the |
873 | | Python thread state of the current thread. |
874 | | |
875 | | PyThreadState_Get() doesn't give the state of the thread that caused |
876 | | the fault if the thread released the GIL, and so |
877 | | _PyThreadState_GET() cannot be used. Read the thread specific |
878 | | storage (TSS) instead: call PyGILState_GetThisThreadState(). */ |
879 | 0 | current_tstate = PyGILState_GetThisThreadState(); |
880 | 0 | } |
881 | |
|
882 | 0 | if (interp == NULL) { |
883 | 0 | if (current_tstate == NULL) { |
884 | 0 | interp = _PyGILState_GetInterpreterStateUnsafe(); |
885 | 0 | if (interp == NULL) { |
886 | | /* We need the interpreter state to get Python threads */ |
887 | 0 | return "unable to get the interpreter state"; |
888 | 0 | } |
889 | 0 | } |
890 | 0 | else { |
891 | 0 | interp = current_tstate->interp; |
892 | 0 | } |
893 | 0 | } |
894 | 0 | assert(interp != NULL); |
895 | | |
896 | | /* Get the current interpreter from the current thread */ |
897 | 0 | tstate = PyInterpreterState_ThreadHead(interp); |
898 | 0 | if (tstate == NULL) |
899 | 0 | return "unable to get the thread head state"; |
900 | | |
901 | | /* Dump the traceback of each thread */ |
902 | 0 | tstate = PyInterpreterState_ThreadHead(interp); |
903 | 0 | nthreads = 0; |
904 | 0 | _Py_BEGIN_SUPPRESS_IPH |
905 | 0 | do |
906 | 0 | { |
907 | 0 | if (nthreads != 0) |
908 | 0 | PUTS(fd, "\n"); |
909 | 0 | if (nthreads >= MAX_NTHREADS) { |
910 | 0 | PUTS(fd, "...\n"); |
911 | 0 | break; |
912 | 0 | } |
913 | 0 | write_thread_id(fd, tstate, tstate == current_tstate); |
914 | 0 | dump_traceback(fd, tstate, 0); |
915 | 0 | tstate = PyThreadState_Next(tstate); |
916 | 0 | nthreads++; |
917 | 0 | } while (tstate != NULL); |
918 | 0 | _Py_END_SUPPRESS_IPH |
919 | | |
920 | 0 | return NULL; |
921 | 0 | } |
922 | | |