/src/cpython/Python/traceback.c
Line | Count | Source (jump to first uncovered line) |
1 | | |
2 | | /* Traceback implementation */ |
3 | | |
4 | | #include "Python.h" |
5 | | #include "pycore_call.h" // _PyObject_CallMethodFormat() |
6 | | #include "pycore_fileutils.h" // _Py_BEGIN_SUPPRESS_IPH |
7 | | #include "pycore_frame.h" // PyFrameObject |
8 | | #include "pycore_interp.h" // PyInterpreterState.gc |
9 | | #include "pycore_interpframe.h" // _PyFrame_GetCode() |
10 | | #include "pycore_pyerrors.h" // _PyErr_GetRaisedException() |
11 | | #include "pycore_pystate.h" // _PyThreadState_GET() |
12 | | #include "pycore_traceback.h" // EXCEPTION_TB_HEADER |
13 | | |
14 | | #include "frameobject.h" // PyFrame_New() |
15 | | |
16 | | #include "osdefs.h" // SEP |
17 | | #ifdef HAVE_UNISTD_H |
18 | | # include <unistd.h> // lseek() |
19 | | #endif |
20 | | |
21 | | #if (defined(HAVE_EXECINFO_H) && defined(HAVE_DLFCN_H) && defined(HAVE_LINK_H)) |
22 | | # define _PY_HAS_BACKTRACE_HEADERS 1 |
23 | | #endif |
24 | | |
25 | | #if (defined(__APPLE__) && defined(HAVE_EXECINFO_H) && defined(HAVE_DLFCN_H)) |
26 | | # define _PY_HAS_BACKTRACE_HEADERS 1 |
27 | | #endif |
28 | | |
29 | | #ifdef _PY_HAS_BACKTRACE_HEADERS |
30 | | # include <execinfo.h> // backtrace(), backtrace_symbols() |
31 | | # include <dlfcn.h> // dladdr1() |
32 | | #ifdef HAVE_LINK_H |
33 | | # include <link.h> // struct DL_info |
34 | | #endif |
35 | | # if defined(__APPLE__) && defined(HAVE_BACKTRACE) && defined(HAVE_DLADDR) |
36 | | # define CAN_C_BACKTRACE |
37 | | # elif defined(HAVE_BACKTRACE) && defined(HAVE_DLADDR1) |
38 | | # define CAN_C_BACKTRACE |
39 | | # endif |
40 | | #endif |
41 | | |
42 | | #if defined(__STDC_NO_VLA__) && (__STDC_NO_VLA__ == 1) |
43 | | /* Use alloca() for VLAs. */ |
44 | | # define VLA(type, name, size) type *name = alloca(size) |
45 | | #elif !defined(__STDC_NO_VLA__) || (__STDC_NO_VLA__ == 0) |
46 | | /* Use actual C VLAs.*/ |
47 | 0 | # define VLA(type, name, size) type name[size] |
48 | | #elif defined(CAN_C_BACKTRACE) |
49 | | /* VLAs are not possible. Disable C stack trace functions. */ |
50 | | # undef CAN_C_BACKTRACE |
51 | | #endif |
52 | | |
53 | | #define OFF(x) offsetof(PyTracebackObject, x) |
54 | 0 | #define PUTS(fd, str) (void)_Py_write_noraise(fd, str, strlen(str)) |
55 | | |
56 | 0 | #define MAX_STRING_LENGTH 500 |
57 | 0 | #define MAX_FRAME_DEPTH 100 |
58 | 0 | #define MAX_NTHREADS 100 |
59 | | |
60 | | /* Function from Parser/tokenizer/file_tokenizer.c */ |
61 | | extern char* _PyTokenizer_FindEncodingFilename(int, PyObject *); |
62 | | |
63 | | /*[clinic input] |
64 | | class traceback "PyTracebackObject *" "&PyTraceback_Type" |
65 | | [clinic start generated code]*/ |
66 | | /*[clinic end generated code: output=da39a3ee5e6b4b0d input=cf96294b2bebc811]*/ |
67 | | |
68 | 33.5M | #define _PyTracebackObject_CAST(op) ((PyTracebackObject *)(op)) |
69 | | |
70 | | #include "clinic/traceback.c.h" |
71 | | |
72 | | static PyObject * |
73 | | tb_create_raw(PyTracebackObject *next, PyFrameObject *frame, int lasti, |
74 | | int lineno) |
75 | 33.4M | { |
76 | 33.4M | PyTracebackObject *tb; |
77 | 33.4M | if ((next != NULL && !PyTraceBack_Check(next)) || |
78 | 33.4M | frame == NULL || !PyFrame_Check(frame)) { |
79 | 0 | PyErr_BadInternalCall(); |
80 | 0 | return NULL; |
81 | 0 | } |
82 | 33.4M | tb = PyObject_GC_New(PyTracebackObject, &PyTraceBack_Type); |
83 | 33.4M | if (tb != NULL) { |
84 | 33.4M | tb->tb_next = (PyTracebackObject*)Py_XNewRef(next); |
85 | 33.4M | tb->tb_frame = (PyFrameObject*)Py_XNewRef(frame); |
86 | 33.4M | tb->tb_lasti = lasti; |
87 | 33.4M | tb->tb_lineno = lineno; |
88 | 33.4M | PyObject_GC_Track(tb); |
89 | 33.4M | } |
90 | 33.4M | return (PyObject *)tb; |
91 | 33.4M | } |
92 | | |
93 | | /*[clinic input] |
94 | | @classmethod |
95 | | traceback.__new__ as tb_new |
96 | | |
97 | | tb_next: object |
98 | | tb_frame: object(type='PyFrameObject *', subclass_of='&PyFrame_Type') |
99 | | tb_lasti: int |
100 | | tb_lineno: int |
101 | | |
102 | | Create a new traceback object. |
103 | | [clinic start generated code]*/ |
104 | | |
105 | | static PyObject * |
106 | | tb_new_impl(PyTypeObject *type, PyObject *tb_next, PyFrameObject *tb_frame, |
107 | | int tb_lasti, int tb_lineno) |
108 | | /*[clinic end generated code: output=fa077debd72d861a input=b88143145454cb59]*/ |
109 | 0 | { |
110 | 0 | if (tb_next == Py_None) { |
111 | 0 | tb_next = NULL; |
112 | 0 | } else if (!PyTraceBack_Check(tb_next)) { |
113 | 0 | return PyErr_Format(PyExc_TypeError, |
114 | 0 | "expected traceback object or None, got '%s'", |
115 | 0 | Py_TYPE(tb_next)->tp_name); |
116 | 0 | } |
117 | | |
118 | 0 | return tb_create_raw((PyTracebackObject *)tb_next, tb_frame, tb_lasti, |
119 | 0 | tb_lineno); |
120 | 0 | } |
121 | | |
122 | | static PyObject * |
123 | | tb_dir(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored)) |
124 | 0 | { |
125 | 0 | return Py_BuildValue("[ssss]", "tb_frame", "tb_next", |
126 | 0 | "tb_lasti", "tb_lineno"); |
127 | 0 | } |
128 | | |
129 | | /*[clinic input] |
130 | | @critical_section |
131 | | @getter |
132 | | traceback.tb_next |
133 | | [clinic start generated code]*/ |
134 | | |
135 | | static PyObject * |
136 | | traceback_tb_next_get_impl(PyTracebackObject *self) |
137 | | /*[clinic end generated code: output=963634df7d5fc837 input=8f6345f2b73cb965]*/ |
138 | 0 | { |
139 | 0 | PyObject* ret = (PyObject*)self->tb_next; |
140 | 0 | if (!ret) { |
141 | 0 | ret = Py_None; |
142 | 0 | } |
143 | 0 | return Py_NewRef(ret); |
144 | 0 | } |
145 | | |
146 | | static int |
147 | | tb_get_lineno(PyObject *op) |
148 | 0 | { |
149 | 0 | PyTracebackObject *tb = _PyTracebackObject_CAST(op); |
150 | 0 | _PyInterpreterFrame* frame = tb->tb_frame->f_frame; |
151 | 0 | assert(frame != NULL); |
152 | 0 | return PyCode_Addr2Line(_PyFrame_GetCode(frame), tb->tb_lasti); |
153 | 0 | } |
154 | | |
155 | | static PyObject * |
156 | | tb_lineno_get(PyObject *op, void *Py_UNUSED(_)) |
157 | 0 | { |
158 | 0 | PyTracebackObject *self = _PyTracebackObject_CAST(op); |
159 | 0 | int lineno = self->tb_lineno; |
160 | 0 | if (lineno == -1) { |
161 | 0 | lineno = tb_get_lineno(op); |
162 | 0 | if (lineno < 0) { |
163 | 0 | Py_RETURN_NONE; |
164 | 0 | } |
165 | 0 | } |
166 | 0 | return PyLong_FromLong(lineno); |
167 | 0 | } |
168 | | |
169 | | /*[clinic input] |
170 | | @critical_section |
171 | | @setter |
172 | | traceback.tb_next |
173 | | [clinic start generated code]*/ |
174 | | |
175 | | static int |
176 | | traceback_tb_next_set_impl(PyTracebackObject *self, PyObject *value) |
177 | | /*[clinic end generated code: output=d4868cbc48f2adac input=ce66367f85e3c443]*/ |
178 | 0 | { |
179 | 0 | if (!value) { |
180 | 0 | PyErr_Format(PyExc_TypeError, "can't delete tb_next attribute"); |
181 | 0 | return -1; |
182 | 0 | } |
183 | | |
184 | | /* We accept None or a traceback object, and map None -> NULL (inverse of |
185 | | tb_next_get) */ |
186 | 0 | if (value == Py_None) { |
187 | 0 | value = NULL; |
188 | 0 | } else if (!PyTraceBack_Check(value)) { |
189 | 0 | PyErr_Format(PyExc_TypeError, |
190 | 0 | "expected traceback object, got '%s'", |
191 | 0 | Py_TYPE(value)->tp_name); |
192 | 0 | return -1; |
193 | 0 | } |
194 | | |
195 | | /* Check for loops */ |
196 | 0 | PyTracebackObject *cursor = (PyTracebackObject *)value; |
197 | 0 | Py_XINCREF(cursor); |
198 | 0 | while (cursor) { |
199 | 0 | if (cursor == self) { |
200 | 0 | PyErr_Format(PyExc_ValueError, "traceback loop detected"); |
201 | 0 | Py_DECREF(cursor); |
202 | 0 | return -1; |
203 | 0 | } |
204 | 0 | Py_BEGIN_CRITICAL_SECTION(cursor); |
205 | 0 | Py_XINCREF(cursor->tb_next); |
206 | 0 | Py_SETREF(cursor, cursor->tb_next); |
207 | 0 | Py_END_CRITICAL_SECTION(); |
208 | 0 | } |
209 | | |
210 | 0 | Py_XSETREF(self->tb_next, (PyTracebackObject *)Py_XNewRef(value)); |
211 | |
|
212 | 0 | return 0; |
213 | 0 | } |
214 | | |
215 | | |
216 | | static PyMethodDef tb_methods[] = { |
217 | | {"__dir__", tb_dir, METH_NOARGS, NULL}, |
218 | | {NULL, NULL, 0, NULL}, |
219 | | }; |
220 | | |
221 | | static PyMemberDef tb_memberlist[] = { |
222 | | {"tb_frame", _Py_T_OBJECT, OFF(tb_frame), Py_READONLY|Py_AUDIT_READ}, |
223 | | {"tb_lasti", Py_T_INT, OFF(tb_lasti), Py_READONLY}, |
224 | | {NULL} /* Sentinel */ |
225 | | }; |
226 | | |
227 | | static PyGetSetDef tb_getsetters[] = { |
228 | | TRACEBACK_TB_NEXT_GETSETDEF |
229 | | {"tb_lineno", tb_lineno_get, NULL, NULL, NULL}, |
230 | | {NULL} /* Sentinel */ |
231 | | }; |
232 | | |
233 | | static void |
234 | | tb_dealloc(PyObject *op) |
235 | 33.4M | { |
236 | 33.4M | PyTracebackObject *tb = _PyTracebackObject_CAST(op); |
237 | 33.4M | PyObject_GC_UnTrack(tb); |
238 | 33.4M | Py_XDECREF(tb->tb_next); |
239 | 33.4M | Py_XDECREF(tb->tb_frame); |
240 | 33.4M | PyObject_GC_Del(tb); |
241 | 33.4M | } |
242 | | |
243 | | static int |
244 | | tb_traverse(PyObject *op, visitproc visit, void *arg) |
245 | 137k | { |
246 | 137k | PyTracebackObject *tb = _PyTracebackObject_CAST(op); |
247 | 137k | Py_VISIT(tb->tb_next); |
248 | 137k | Py_VISIT(tb->tb_frame); |
249 | 137k | return 0; |
250 | 137k | } |
251 | | |
252 | | static int |
253 | | tb_clear(PyObject *op) |
254 | 0 | { |
255 | 0 | PyTracebackObject *tb = _PyTracebackObject_CAST(op); |
256 | 0 | Py_CLEAR(tb->tb_next); |
257 | 0 | Py_CLEAR(tb->tb_frame); |
258 | 0 | return 0; |
259 | 0 | } |
260 | | |
261 | | PyTypeObject PyTraceBack_Type = { |
262 | | PyVarObject_HEAD_INIT(&PyType_Type, 0) |
263 | | "traceback", |
264 | | sizeof(PyTracebackObject), |
265 | | 0, |
266 | | tb_dealloc, /*tp_dealloc*/ |
267 | | 0, /*tp_vectorcall_offset*/ |
268 | | 0, /*tp_getattr*/ |
269 | | 0, /*tp_setattr*/ |
270 | | 0, /*tp_as_async*/ |
271 | | 0, /*tp_repr*/ |
272 | | 0, /*tp_as_number*/ |
273 | | 0, /*tp_as_sequence*/ |
274 | | 0, /*tp_as_mapping*/ |
275 | | 0, /* tp_hash */ |
276 | | 0, /* tp_call */ |
277 | | 0, /* tp_str */ |
278 | | PyObject_GenericGetAttr, /* tp_getattro */ |
279 | | 0, /* tp_setattro */ |
280 | | 0, /* tp_as_buffer */ |
281 | | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */ |
282 | | tb_new__doc__, /* tp_doc */ |
283 | | tb_traverse, /* tp_traverse */ |
284 | | tb_clear, /* tp_clear */ |
285 | | 0, /* tp_richcompare */ |
286 | | 0, /* tp_weaklistoffset */ |
287 | | 0, /* tp_iter */ |
288 | | 0, /* tp_iternext */ |
289 | | tb_methods, /* tp_methods */ |
290 | | tb_memberlist, /* tp_members */ |
291 | | tb_getsetters, /* tp_getset */ |
292 | | 0, /* tp_base */ |
293 | | 0, /* tp_dict */ |
294 | | 0, /* tp_descr_get */ |
295 | | 0, /* tp_descr_set */ |
296 | | 0, /* tp_dictoffset */ |
297 | | 0, /* tp_init */ |
298 | | 0, /* tp_alloc */ |
299 | | tb_new, /* tp_new */ |
300 | | }; |
301 | | |
302 | | |
303 | | PyObject* |
304 | | _PyTraceBack_FromFrame(PyObject *tb_next, PyFrameObject *frame) |
305 | 33.4M | { |
306 | 33.4M | assert(tb_next == NULL || PyTraceBack_Check(tb_next)); |
307 | 33.4M | assert(frame != NULL); |
308 | 33.4M | int addr = _PyInterpreterFrame_LASTI(frame->f_frame) * sizeof(_Py_CODEUNIT); |
309 | 33.4M | return tb_create_raw((PyTracebackObject *)tb_next, frame, addr, -1); |
310 | 33.4M | } |
311 | | |
312 | | |
313 | | int |
314 | | PyTraceBack_Here(PyFrameObject *frame) |
315 | 33.4M | { |
316 | 33.4M | PyObject *exc = PyErr_GetRaisedException(); |
317 | 33.4M | assert(PyExceptionInstance_Check(exc)); |
318 | 33.4M | PyObject *tb = PyException_GetTraceback(exc); |
319 | 33.4M | PyObject *newtb = _PyTraceBack_FromFrame(tb, frame); |
320 | 33.4M | Py_XDECREF(tb); |
321 | 33.4M | if (newtb == NULL) { |
322 | 0 | _PyErr_ChainExceptions1(exc); |
323 | 0 | return -1; |
324 | 0 | } |
325 | 33.4M | PyException_SetTraceback(exc, newtb); |
326 | 33.4M | Py_XDECREF(newtb); |
327 | 33.4M | PyErr_SetRaisedException(exc); |
328 | 33.4M | return 0; |
329 | 33.4M | } |
330 | | |
331 | | /* Insert a frame into the traceback for (funcname, filename, lineno). */ |
332 | | void _PyTraceback_Add(const char *funcname, const char *filename, int lineno) |
333 | 0 | { |
334 | 0 | PyObject *globals; |
335 | 0 | PyCodeObject *code; |
336 | 0 | PyFrameObject *frame; |
337 | 0 | PyThreadState *tstate = _PyThreadState_GET(); |
338 | | |
339 | | /* Save and clear the current exception. Python functions must not be |
340 | | called with an exception set. Calling Python functions happens when |
341 | | the codec of the filesystem encoding is implemented in pure Python. */ |
342 | 0 | PyObject *exc = _PyErr_GetRaisedException(tstate); |
343 | |
|
344 | 0 | globals = PyDict_New(); |
345 | 0 | if (!globals) |
346 | 0 | goto error; |
347 | 0 | code = PyCode_NewEmpty(filename, funcname, lineno); |
348 | 0 | if (!code) { |
349 | 0 | Py_DECREF(globals); |
350 | 0 | goto error; |
351 | 0 | } |
352 | 0 | frame = PyFrame_New(tstate, code, globals, NULL); |
353 | 0 | Py_DECREF(globals); |
354 | 0 | Py_DECREF(code); |
355 | 0 | if (!frame) |
356 | 0 | goto error; |
357 | 0 | frame->f_lineno = lineno; |
358 | |
|
359 | 0 | _PyErr_SetRaisedException(tstate, exc); |
360 | 0 | PyTraceBack_Here(frame); |
361 | 0 | Py_DECREF(frame); |
362 | 0 | return; |
363 | | |
364 | 0 | error: |
365 | 0 | _PyErr_ChainExceptions1(exc); |
366 | 0 | } |
367 | | |
368 | | static PyObject * |
369 | | _Py_FindSourceFile(PyObject *filename, char* namebuf, size_t namelen, PyObject *io) |
370 | 0 | { |
371 | 0 | Py_ssize_t i; |
372 | 0 | PyObject *binary; |
373 | 0 | PyObject *v; |
374 | 0 | Py_ssize_t npath; |
375 | 0 | size_t taillen; |
376 | 0 | PyObject *syspath; |
377 | 0 | PyObject *path; |
378 | 0 | const char* tail; |
379 | 0 | PyObject *filebytes; |
380 | 0 | const char* filepath; |
381 | 0 | Py_ssize_t len; |
382 | 0 | PyObject* result; |
383 | 0 | PyObject *open = NULL; |
384 | |
|
385 | 0 | filebytes = PyUnicode_EncodeFSDefault(filename); |
386 | 0 | if (filebytes == NULL) { |
387 | 0 | PyErr_Clear(); |
388 | 0 | return NULL; |
389 | 0 | } |
390 | 0 | filepath = PyBytes_AS_STRING(filebytes); |
391 | | |
392 | | /* Search tail of filename in sys.path before giving up */ |
393 | 0 | tail = strrchr(filepath, SEP); |
394 | 0 | if (tail == NULL) |
395 | 0 | tail = filepath; |
396 | 0 | else |
397 | 0 | tail++; |
398 | 0 | taillen = strlen(tail); |
399 | |
|
400 | 0 | PyThreadState *tstate = _PyThreadState_GET(); |
401 | 0 | if (PySys_GetOptionalAttr(&_Py_ID(path), &syspath) < 0) { |
402 | 0 | PyErr_Clear(); |
403 | 0 | goto error; |
404 | 0 | } |
405 | 0 | if (syspath == NULL || !PyList_Check(syspath)) { |
406 | 0 | goto error; |
407 | 0 | } |
408 | 0 | npath = PyList_Size(syspath); |
409 | |
|
410 | 0 | open = PyObject_GetAttr(io, &_Py_ID(open)); |
411 | 0 | for (i = 0; i < npath; i++) { |
412 | 0 | v = PyList_GetItem(syspath, i); |
413 | 0 | if (v == NULL) { |
414 | 0 | PyErr_Clear(); |
415 | 0 | break; |
416 | 0 | } |
417 | 0 | if (!PyUnicode_Check(v)) |
418 | 0 | continue; |
419 | 0 | path = PyUnicode_EncodeFSDefault(v); |
420 | 0 | if (path == NULL) { |
421 | 0 | PyErr_Clear(); |
422 | 0 | continue; |
423 | 0 | } |
424 | 0 | len = PyBytes_GET_SIZE(path); |
425 | 0 | if (len + 1 + (Py_ssize_t)taillen >= (Py_ssize_t)namelen - 1) { |
426 | 0 | Py_DECREF(path); |
427 | 0 | continue; /* Too long */ |
428 | 0 | } |
429 | 0 | strcpy(namebuf, PyBytes_AS_STRING(path)); |
430 | 0 | Py_DECREF(path); |
431 | 0 | if (strlen(namebuf) != (size_t)len) |
432 | 0 | continue; /* v contains '\0' */ |
433 | 0 | if (len > 0 && namebuf[len-1] != SEP) |
434 | 0 | namebuf[len++] = SEP; |
435 | 0 | strcpy(namebuf+len, tail); |
436 | |
|
437 | 0 | binary = _PyObject_CallMethodFormat(tstate, open, "ss", namebuf, "rb"); |
438 | 0 | if (binary != NULL) { |
439 | 0 | result = binary; |
440 | 0 | goto finally; |
441 | 0 | } |
442 | 0 | PyErr_Clear(); |
443 | 0 | } |
444 | 0 | goto error; |
445 | | |
446 | 0 | error: |
447 | 0 | result = NULL; |
448 | 0 | finally: |
449 | 0 | Py_XDECREF(open); |
450 | 0 | Py_XDECREF(syspath); |
451 | 0 | Py_DECREF(filebytes); |
452 | 0 | return result; |
453 | 0 | } |
454 | | |
455 | | /* Writes indent spaces. Returns 0 on success and non-zero on failure. |
456 | | */ |
457 | | int |
458 | | _Py_WriteIndent(int indent, PyObject *f) |
459 | 0 | { |
460 | 0 | char buf[11] = " "; |
461 | 0 | assert(strlen(buf) == 10); |
462 | 0 | while (indent > 0) { |
463 | 0 | if (indent < 10) { |
464 | 0 | buf[indent] = '\0'; |
465 | 0 | } |
466 | 0 | if (PyFile_WriteString(buf, f) < 0) { |
467 | 0 | return -1; |
468 | 0 | } |
469 | 0 | indent -= 10; |
470 | 0 | } |
471 | 0 | return 0; |
472 | 0 | } |
473 | | |
474 | | static int |
475 | | display_source_line(PyObject *f, PyObject *filename, int lineno, int indent, |
476 | | int *truncation, PyObject **line) |
477 | 0 | { |
478 | 0 | int fd; |
479 | 0 | int i; |
480 | 0 | char *found_encoding; |
481 | 0 | const char *encoding; |
482 | 0 | PyObject *io; |
483 | 0 | PyObject *binary; |
484 | 0 | PyObject *fob = NULL; |
485 | 0 | PyObject *lineobj = NULL; |
486 | 0 | PyObject *res; |
487 | 0 | char buf[MAXPATHLEN+1]; |
488 | 0 | int kind; |
489 | 0 | const void *data; |
490 | | |
491 | | /* open the file */ |
492 | 0 | if (filename == NULL) |
493 | 0 | return 0; |
494 | | |
495 | | /* Do not attempt to open things like <string> or <stdin> */ |
496 | 0 | assert(PyUnicode_Check(filename)); |
497 | 0 | if (PyUnicode_READ_CHAR(filename, 0) == '<') { |
498 | 0 | Py_ssize_t len = PyUnicode_GET_LENGTH(filename); |
499 | 0 | if (len > 0 && PyUnicode_READ_CHAR(filename, len - 1) == '>') { |
500 | 0 | return 0; |
501 | 0 | } |
502 | 0 | } |
503 | | |
504 | 0 | io = PyImport_ImportModule("io"); |
505 | 0 | if (io == NULL) { |
506 | 0 | return -1; |
507 | 0 | } |
508 | | |
509 | 0 | binary = _PyObject_CallMethod(io, &_Py_ID(open), "Os", filename, "rb"); |
510 | 0 | if (binary == NULL) { |
511 | 0 | PyErr_Clear(); |
512 | |
|
513 | 0 | binary = _Py_FindSourceFile(filename, buf, sizeof(buf), io); |
514 | 0 | if (binary == NULL) { |
515 | 0 | Py_DECREF(io); |
516 | 0 | return -1; |
517 | 0 | } |
518 | 0 | } |
519 | | |
520 | | /* use the right encoding to decode the file as unicode */ |
521 | 0 | fd = PyObject_AsFileDescriptor(binary); |
522 | 0 | if (fd < 0) { |
523 | 0 | Py_DECREF(io); |
524 | 0 | Py_DECREF(binary); |
525 | 0 | return 0; |
526 | 0 | } |
527 | 0 | found_encoding = _PyTokenizer_FindEncodingFilename(fd, filename); |
528 | 0 | if (found_encoding == NULL) |
529 | 0 | PyErr_Clear(); |
530 | 0 | encoding = (found_encoding != NULL) ? found_encoding : "utf-8"; |
531 | | /* Reset position */ |
532 | 0 | if (lseek(fd, 0, SEEK_SET) == (off_t)-1) { |
533 | 0 | Py_DECREF(io); |
534 | 0 | Py_DECREF(binary); |
535 | 0 | PyMem_Free(found_encoding); |
536 | 0 | return 0; |
537 | 0 | } |
538 | 0 | fob = _PyObject_CallMethod(io, &_Py_ID(TextIOWrapper), |
539 | 0 | "Os", binary, encoding); |
540 | 0 | Py_DECREF(io); |
541 | 0 | PyMem_Free(found_encoding); |
542 | |
|
543 | 0 | if (fob == NULL) { |
544 | 0 | PyErr_Clear(); |
545 | |
|
546 | 0 | res = PyObject_CallMethodNoArgs(binary, &_Py_ID(close)); |
547 | 0 | Py_DECREF(binary); |
548 | 0 | if (res) |
549 | 0 | Py_DECREF(res); |
550 | 0 | else |
551 | 0 | PyErr_Clear(); |
552 | 0 | return 0; |
553 | 0 | } |
554 | 0 | Py_DECREF(binary); |
555 | | |
556 | | /* get the line number lineno */ |
557 | 0 | for (i = 0; i < lineno; i++) { |
558 | 0 | Py_XDECREF(lineobj); |
559 | 0 | lineobj = PyFile_GetLine(fob, -1); |
560 | 0 | if (!lineobj) { |
561 | 0 | PyErr_Clear(); |
562 | 0 | break; |
563 | 0 | } |
564 | 0 | } |
565 | 0 | res = PyObject_CallMethodNoArgs(fob, &_Py_ID(close)); |
566 | 0 | if (res) { |
567 | 0 | Py_DECREF(res); |
568 | 0 | } |
569 | 0 | else { |
570 | 0 | PyErr_Clear(); |
571 | 0 | } |
572 | 0 | Py_DECREF(fob); |
573 | 0 | if (!lineobj || !PyUnicode_Check(lineobj)) { |
574 | 0 | Py_XDECREF(lineobj); |
575 | 0 | return -1; |
576 | 0 | } |
577 | | |
578 | 0 | if (line) { |
579 | 0 | *line = Py_NewRef(lineobj); |
580 | 0 | } |
581 | | |
582 | | /* remove the indentation of the line */ |
583 | 0 | kind = PyUnicode_KIND(lineobj); |
584 | 0 | data = PyUnicode_DATA(lineobj); |
585 | 0 | for (i=0; i < PyUnicode_GET_LENGTH(lineobj); i++) { |
586 | 0 | Py_UCS4 ch = PyUnicode_READ(kind, data, i); |
587 | 0 | if (ch != ' ' && ch != '\t' && ch != '\014') |
588 | 0 | break; |
589 | 0 | } |
590 | 0 | if (i) { |
591 | 0 | PyObject *truncated; |
592 | 0 | truncated = PyUnicode_Substring(lineobj, i, PyUnicode_GET_LENGTH(lineobj)); |
593 | 0 | if (truncated) { |
594 | 0 | Py_SETREF(lineobj, truncated); |
595 | 0 | } else { |
596 | 0 | PyErr_Clear(); |
597 | 0 | } |
598 | 0 | } |
599 | |
|
600 | 0 | if (truncation != NULL) { |
601 | 0 | *truncation = i - indent; |
602 | 0 | } |
603 | | |
604 | | /* Write some spaces before the line */ |
605 | 0 | if (_Py_WriteIndent(indent, f) < 0) { |
606 | 0 | goto error; |
607 | 0 | } |
608 | | |
609 | | /* finally display the line */ |
610 | 0 | if (PyFile_WriteObject(lineobj, f, Py_PRINT_RAW) < 0) { |
611 | 0 | goto error; |
612 | 0 | } |
613 | | |
614 | 0 | if (PyFile_WriteString("\n", f) < 0) { |
615 | 0 | goto error; |
616 | 0 | } |
617 | | |
618 | 0 | Py_DECREF(lineobj); |
619 | 0 | return 0; |
620 | 0 | error: |
621 | 0 | Py_DECREF(lineobj); |
622 | 0 | return -1; |
623 | 0 | } |
624 | | |
625 | | int |
626 | | _Py_DisplaySourceLine(PyObject *f, PyObject *filename, int lineno, int indent, |
627 | | int *truncation, PyObject **line) |
628 | 0 | { |
629 | 0 | return display_source_line(f, filename, lineno, indent, truncation, line); |
630 | 0 | } |
631 | | |
632 | | |
633 | | #define IS_WHITESPACE(c) (((c) == ' ') || ((c) == '\t') || ((c) == '\f')) |
634 | 0 | #define _TRACEBACK_SOURCE_LINE_INDENT 4 |
635 | | |
636 | | static inline int |
637 | 0 | ignore_source_errors(void) { |
638 | 0 | if (PyErr_Occurred()) { |
639 | 0 | if (PyErr_ExceptionMatches(PyExc_KeyboardInterrupt)) { |
640 | 0 | return -1; |
641 | 0 | } |
642 | 0 | PyErr_Clear(); |
643 | 0 | } |
644 | 0 | return 0; |
645 | 0 | } |
646 | | |
647 | | static int |
648 | | tb_displayline(PyTracebackObject* tb, PyObject *f, PyObject *filename, int lineno, |
649 | | PyFrameObject *frame, PyObject *name) |
650 | 0 | { |
651 | 0 | if (filename == NULL || name == NULL) { |
652 | 0 | return -1; |
653 | 0 | } |
654 | | |
655 | 0 | PyObject *line = PyUnicode_FromFormat(" File \"%U\", line %d, in %U\n", |
656 | 0 | filename, lineno, name); |
657 | 0 | if (line == NULL) { |
658 | 0 | return -1; |
659 | 0 | } |
660 | | |
661 | 0 | int res = PyFile_WriteObject(line, f, Py_PRINT_RAW); |
662 | 0 | Py_DECREF(line); |
663 | 0 | if (res < 0) { |
664 | 0 | return -1; |
665 | 0 | } |
666 | | |
667 | 0 | int err = 0; |
668 | |
|
669 | 0 | int truncation = _TRACEBACK_SOURCE_LINE_INDENT; |
670 | 0 | PyObject* source_line = NULL; |
671 | 0 | int rc = display_source_line( |
672 | 0 | f, filename, lineno, _TRACEBACK_SOURCE_LINE_INDENT, |
673 | 0 | &truncation, &source_line); |
674 | 0 | if (rc != 0 || !source_line) { |
675 | | /* ignore errors since we can't report them, can we? */ |
676 | 0 | err = ignore_source_errors(); |
677 | 0 | } |
678 | 0 | Py_XDECREF(source_line); |
679 | 0 | return err; |
680 | 0 | } |
681 | | |
682 | | static const int TB_RECURSIVE_CUTOFF = 3; // Also hardcoded in traceback.py. |
683 | | |
684 | | static int |
685 | | tb_print_line_repeated(PyObject *f, long cnt) |
686 | 0 | { |
687 | 0 | cnt -= TB_RECURSIVE_CUTOFF; |
688 | 0 | PyObject *line = PyUnicode_FromFormat( |
689 | 0 | (cnt > 1) |
690 | 0 | ? " [Previous line repeated %ld more times]\n" |
691 | 0 | : " [Previous line repeated %ld more time]\n", |
692 | 0 | cnt); |
693 | 0 | if (line == NULL) { |
694 | 0 | return -1; |
695 | 0 | } |
696 | 0 | int err = PyFile_WriteObject(line, f, Py_PRINT_RAW); |
697 | 0 | Py_DECREF(line); |
698 | 0 | return err; |
699 | 0 | } |
700 | | |
701 | | static int |
702 | | tb_printinternal(PyTracebackObject *tb, PyObject *f, long limit) |
703 | 0 | { |
704 | 0 | PyCodeObject *code = NULL; |
705 | 0 | Py_ssize_t depth = 0; |
706 | 0 | PyObject *last_file = NULL; |
707 | 0 | int last_line = -1; |
708 | 0 | PyObject *last_name = NULL; |
709 | 0 | long cnt = 0; |
710 | 0 | PyTracebackObject *tb1 = tb; |
711 | 0 | while (tb1 != NULL) { |
712 | 0 | depth++; |
713 | 0 | tb1 = tb1->tb_next; |
714 | 0 | } |
715 | 0 | while (tb != NULL && depth > limit) { |
716 | 0 | depth--; |
717 | 0 | tb = tb->tb_next; |
718 | 0 | } |
719 | 0 | while (tb != NULL) { |
720 | 0 | code = PyFrame_GetCode(tb->tb_frame); |
721 | 0 | int tb_lineno = tb->tb_lineno; |
722 | 0 | if (tb_lineno == -1) { |
723 | 0 | tb_lineno = tb_get_lineno((PyObject *)tb); |
724 | 0 | } |
725 | 0 | if (last_file == NULL || |
726 | 0 | code->co_filename != last_file || |
727 | 0 | last_line == -1 || tb_lineno != last_line || |
728 | 0 | last_name == NULL || code->co_name != last_name) { |
729 | 0 | if (cnt > TB_RECURSIVE_CUTOFF) { |
730 | 0 | if (tb_print_line_repeated(f, cnt) < 0) { |
731 | 0 | goto error; |
732 | 0 | } |
733 | 0 | } |
734 | 0 | last_file = code->co_filename; |
735 | 0 | last_line = tb_lineno; |
736 | 0 | last_name = code->co_name; |
737 | 0 | cnt = 0; |
738 | 0 | } |
739 | 0 | cnt++; |
740 | 0 | if (cnt <= TB_RECURSIVE_CUTOFF) { |
741 | 0 | if (tb_displayline(tb, f, code->co_filename, tb_lineno, |
742 | 0 | tb->tb_frame, code->co_name) < 0) { |
743 | 0 | goto error; |
744 | 0 | } |
745 | | |
746 | 0 | if (PyErr_CheckSignals() < 0) { |
747 | 0 | goto error; |
748 | 0 | } |
749 | 0 | } |
750 | 0 | Py_CLEAR(code); |
751 | 0 | tb = tb->tb_next; |
752 | 0 | } |
753 | 0 | if (cnt > TB_RECURSIVE_CUTOFF) { |
754 | 0 | if (tb_print_line_repeated(f, cnt) < 0) { |
755 | 0 | goto error; |
756 | 0 | } |
757 | 0 | } |
758 | 0 | return 0; |
759 | 0 | error: |
760 | 0 | Py_XDECREF(code); |
761 | 0 | return -1; |
762 | 0 | } |
763 | | |
764 | 0 | #define PyTraceBack_LIMIT 1000 |
765 | | |
766 | | int |
767 | | _PyTraceBack_Print(PyObject *v, const char *header, PyObject *f) |
768 | 0 | { |
769 | 0 | PyObject *limitv; |
770 | 0 | long limit = PyTraceBack_LIMIT; |
771 | |
|
772 | 0 | if (v == NULL) { |
773 | 0 | return 0; |
774 | 0 | } |
775 | 0 | if (!PyTraceBack_Check(v)) { |
776 | 0 | PyErr_BadInternalCall(); |
777 | 0 | return -1; |
778 | 0 | } |
779 | 0 | if (PySys_GetOptionalAttrString("tracebacklimit", &limitv) < 0) { |
780 | 0 | return -1; |
781 | 0 | } |
782 | 0 | else if (limitv != NULL && PyLong_Check(limitv)) { |
783 | 0 | int overflow; |
784 | 0 | limit = PyLong_AsLongAndOverflow(limitv, &overflow); |
785 | 0 | if (overflow > 0) { |
786 | 0 | limit = LONG_MAX; |
787 | 0 | } |
788 | 0 | else if (limit <= 0) { |
789 | 0 | Py_DECREF(limitv); |
790 | 0 | return 0; |
791 | 0 | } |
792 | 0 | } |
793 | 0 | Py_XDECREF(limitv); |
794 | |
|
795 | 0 | if (PyFile_WriteString(header, f) < 0) { |
796 | 0 | return -1; |
797 | 0 | } |
798 | | |
799 | 0 | if (tb_printinternal((PyTracebackObject *)v, f, limit) < 0) { |
800 | 0 | return -1; |
801 | 0 | } |
802 | | |
803 | 0 | return 0; |
804 | 0 | } |
805 | | |
806 | | int |
807 | | PyTraceBack_Print(PyObject *v, PyObject *f) |
808 | 0 | { |
809 | 0 | const char *header = EXCEPTION_TB_HEADER; |
810 | 0 | return _PyTraceBack_Print(v, header, f); |
811 | 0 | } |
812 | | |
813 | | /* Format an integer in range [0; 0xffffffff] to decimal and write it |
814 | | into the file fd. |
815 | | |
816 | | This function is signal safe. */ |
817 | | |
818 | | void |
819 | | _Py_DumpDecimal(int fd, size_t value) |
820 | 0 | { |
821 | | /* maximum number of characters required for output of %lld or %p. |
822 | | We need at most ceil(log10(256)*SIZEOF_LONG_LONG) digits, |
823 | | plus 1 for the null byte. 53/22 is an upper bound for log10(256). */ |
824 | 0 | char buffer[1 + (sizeof(size_t)*53-1) / 22 + 1]; |
825 | 0 | char *ptr, *end; |
826 | |
|
827 | 0 | end = &buffer[Py_ARRAY_LENGTH(buffer) - 1]; |
828 | 0 | ptr = end; |
829 | 0 | *ptr = '\0'; |
830 | 0 | do { |
831 | 0 | --ptr; |
832 | 0 | assert(ptr >= buffer); |
833 | 0 | *ptr = '0' + (value % 10); |
834 | 0 | value /= 10; |
835 | 0 | } while (value); |
836 | |
|
837 | 0 | (void)_Py_write_noraise(fd, ptr, end - ptr); |
838 | 0 | } |
839 | | |
840 | | /* Format an integer as hexadecimal with width digits into fd file descriptor. |
841 | | The function is signal safe. */ |
842 | | static void |
843 | | dump_hexadecimal(int fd, uintptr_t value, Py_ssize_t width, int strip_zeros) |
844 | 0 | { |
845 | 0 | char buffer[sizeof(uintptr_t) * 2 + 1], *ptr, *end; |
846 | 0 | Py_ssize_t size = Py_ARRAY_LENGTH(buffer) - 1; |
847 | |
|
848 | 0 | if (width > size) |
849 | 0 | width = size; |
850 | | /* it's ok if width is negative */ |
851 | |
|
852 | 0 | end = &buffer[size]; |
853 | 0 | ptr = end; |
854 | 0 | *ptr = '\0'; |
855 | 0 | do { |
856 | 0 | --ptr; |
857 | 0 | assert(ptr >= buffer); |
858 | 0 | *ptr = Py_hexdigits[value & 15]; |
859 | 0 | value >>= 4; |
860 | 0 | } while ((end - ptr) < width || value); |
861 | |
|
862 | 0 | size = end - ptr; |
863 | 0 | if (strip_zeros) { |
864 | 0 | while (*ptr == '0' && size >= 2) { |
865 | 0 | ptr++; |
866 | 0 | size--; |
867 | 0 | } |
868 | 0 | } |
869 | |
|
870 | 0 | (void)_Py_write_noraise(fd, ptr, size); |
871 | 0 | } |
872 | | |
873 | | void |
874 | | _Py_DumpHexadecimal(int fd, uintptr_t value, Py_ssize_t width) |
875 | 0 | { |
876 | 0 | dump_hexadecimal(fd, value, width, 0); |
877 | 0 | } |
878 | | |
879 | | #ifdef CAN_C_BACKTRACE |
880 | | static void |
881 | | dump_pointer(int fd, void *ptr) |
882 | 0 | { |
883 | 0 | PUTS(fd, "0x"); |
884 | 0 | dump_hexadecimal(fd, (uintptr_t)ptr, sizeof(void*), 1); |
885 | 0 | } |
886 | | #endif |
887 | | |
888 | | static void |
889 | | dump_char(int fd, char ch) |
890 | 0 | { |
891 | 0 | char buf[1] = {ch}; |
892 | 0 | (void)_Py_write_noraise(fd, buf, 1); |
893 | 0 | } |
894 | | |
895 | | void |
896 | | _Py_DumpASCII(int fd, PyObject *text) |
897 | 0 | { |
898 | 0 | PyASCIIObject *ascii = _PyASCIIObject_CAST(text); |
899 | 0 | Py_ssize_t i, size; |
900 | 0 | int truncated; |
901 | 0 | int kind; |
902 | 0 | void *data = NULL; |
903 | 0 | Py_UCS4 ch; |
904 | |
|
905 | 0 | if (!PyUnicode_Check(text)) |
906 | 0 | return; |
907 | | |
908 | 0 | size = ascii->length; |
909 | 0 | kind = ascii->state.kind; |
910 | 0 | if (ascii->state.compact) { |
911 | 0 | if (ascii->state.ascii) |
912 | 0 | data = ascii + 1; |
913 | 0 | else |
914 | 0 | data = _PyCompactUnicodeObject_CAST(text) + 1; |
915 | 0 | } |
916 | 0 | else { |
917 | 0 | data = _PyUnicodeObject_CAST(text)->data.any; |
918 | 0 | if (data == NULL) |
919 | 0 | return; |
920 | 0 | } |
921 | | |
922 | 0 | if (MAX_STRING_LENGTH < size) { |
923 | 0 | size = MAX_STRING_LENGTH; |
924 | 0 | truncated = 1; |
925 | 0 | } |
926 | 0 | else { |
927 | 0 | truncated = 0; |
928 | 0 | } |
929 | | |
930 | | // Is an ASCII string? |
931 | 0 | if (ascii->state.ascii) { |
932 | 0 | assert(kind == PyUnicode_1BYTE_KIND); |
933 | 0 | char *str = data; |
934 | |
|
935 | 0 | int need_escape = 0; |
936 | 0 | for (i=0; i < size; i++) { |
937 | 0 | ch = str[i]; |
938 | 0 | if (!(' ' <= ch && ch <= 126)) { |
939 | 0 | need_escape = 1; |
940 | 0 | break; |
941 | 0 | } |
942 | 0 | } |
943 | 0 | if (!need_escape) { |
944 | | // The string can be written with a single write() syscall |
945 | 0 | (void)_Py_write_noraise(fd, str, size); |
946 | 0 | goto done; |
947 | 0 | } |
948 | 0 | } |
949 | | |
950 | 0 | for (i=0; i < size; i++) { |
951 | 0 | ch = PyUnicode_READ(kind, data, i); |
952 | 0 | if (' ' <= ch && ch <= 126) { |
953 | | /* printable ASCII character */ |
954 | 0 | dump_char(fd, (char)ch); |
955 | 0 | } |
956 | 0 | else if (ch <= 0xff) { |
957 | 0 | PUTS(fd, "\\x"); |
958 | 0 | _Py_DumpHexadecimal(fd, ch, 2); |
959 | 0 | } |
960 | 0 | else if (ch <= 0xffff) { |
961 | 0 | PUTS(fd, "\\u"); |
962 | 0 | _Py_DumpHexadecimal(fd, ch, 4); |
963 | 0 | } |
964 | 0 | else { |
965 | 0 | PUTS(fd, "\\U"); |
966 | 0 | _Py_DumpHexadecimal(fd, ch, 8); |
967 | 0 | } |
968 | 0 | } |
969 | |
|
970 | 0 | done: |
971 | 0 | if (truncated) { |
972 | 0 | PUTS(fd, "..."); |
973 | 0 | } |
974 | 0 | } |
975 | | |
976 | | /* Write a frame into the file fd: "File "xxx", line xxx in xxx". |
977 | | |
978 | | This function is signal safe. */ |
979 | | |
980 | | static void |
981 | | dump_frame(int fd, _PyInterpreterFrame *frame) |
982 | 0 | { |
983 | 0 | assert(frame->owner < FRAME_OWNED_BY_INTERPRETER); |
984 | |
|
985 | 0 | PyCodeObject *code =_PyFrame_GetCode(frame); |
986 | 0 | PUTS(fd, " File "); |
987 | 0 | if (code->co_filename != NULL |
988 | 0 | && PyUnicode_Check(code->co_filename)) |
989 | 0 | { |
990 | 0 | PUTS(fd, "\""); |
991 | 0 | _Py_DumpASCII(fd, code->co_filename); |
992 | 0 | PUTS(fd, "\""); |
993 | 0 | } else { |
994 | 0 | PUTS(fd, "???"); |
995 | 0 | } |
996 | |
|
997 | 0 | int lineno = PyUnstable_InterpreterFrame_GetLine(frame); |
998 | 0 | PUTS(fd, ", line "); |
999 | 0 | if (lineno >= 0) { |
1000 | 0 | _Py_DumpDecimal(fd, (size_t)lineno); |
1001 | 0 | } |
1002 | 0 | else { |
1003 | 0 | PUTS(fd, "???"); |
1004 | 0 | } |
1005 | 0 | PUTS(fd, " in "); |
1006 | |
|
1007 | 0 | if (code->co_name != NULL |
1008 | 0 | && PyUnicode_Check(code->co_name)) { |
1009 | 0 | _Py_DumpASCII(fd, code->co_name); |
1010 | 0 | } |
1011 | 0 | else { |
1012 | 0 | PUTS(fd, "???"); |
1013 | 0 | } |
1014 | |
|
1015 | 0 | PUTS(fd, "\n"); |
1016 | 0 | } |
1017 | | |
1018 | | static int |
1019 | | tstate_is_freed(PyThreadState *tstate) |
1020 | 0 | { |
1021 | 0 | if (_PyMem_IsPtrFreed(tstate)) { |
1022 | 0 | return 1; |
1023 | 0 | } |
1024 | 0 | if (_PyMem_IsPtrFreed(tstate->interp)) { |
1025 | 0 | return 1; |
1026 | 0 | } |
1027 | 0 | return 0; |
1028 | 0 | } |
1029 | | |
1030 | | |
1031 | | static int |
1032 | | interp_is_freed(PyInterpreterState *interp) |
1033 | 0 | { |
1034 | 0 | return _PyMem_IsPtrFreed(interp); |
1035 | 0 | } |
1036 | | |
1037 | | |
1038 | | static void |
1039 | | dump_traceback(int fd, PyThreadState *tstate, int write_header) |
1040 | 0 | { |
1041 | 0 | if (write_header) { |
1042 | 0 | PUTS(fd, "Stack (most recent call first):\n"); |
1043 | 0 | } |
1044 | |
|
1045 | 0 | if (tstate_is_freed(tstate)) { |
1046 | 0 | PUTS(fd, " <tstate is freed>\n"); |
1047 | 0 | return; |
1048 | 0 | } |
1049 | | |
1050 | 0 | _PyInterpreterFrame *frame = tstate->current_frame; |
1051 | 0 | if (frame == NULL) { |
1052 | 0 | PUTS(fd, " <no Python frame>\n"); |
1053 | 0 | return; |
1054 | 0 | } |
1055 | | |
1056 | 0 | unsigned int depth = 0; |
1057 | 0 | while (1) { |
1058 | 0 | if (frame->owner == FRAME_OWNED_BY_INTERPRETER) { |
1059 | | /* Trampoline frame */ |
1060 | 0 | frame = frame->previous; |
1061 | 0 | if (frame == NULL) { |
1062 | 0 | break; |
1063 | 0 | } |
1064 | | |
1065 | | /* Can't have more than one shim frame in a row */ |
1066 | 0 | assert(frame->owner != FRAME_OWNED_BY_INTERPRETER); |
1067 | 0 | } |
1068 | | |
1069 | 0 | if (MAX_FRAME_DEPTH <= depth) { |
1070 | 0 | if (MAX_FRAME_DEPTH < depth) { |
1071 | 0 | PUTS(fd, "plus "); |
1072 | 0 | _Py_DumpDecimal(fd, depth); |
1073 | 0 | PUTS(fd, " frames\n"); |
1074 | 0 | } |
1075 | 0 | break; |
1076 | 0 | } |
1077 | | |
1078 | 0 | dump_frame(fd, frame); |
1079 | 0 | frame = frame->previous; |
1080 | 0 | if (frame == NULL) { |
1081 | 0 | break; |
1082 | 0 | } |
1083 | 0 | depth++; |
1084 | 0 | } |
1085 | 0 | } |
1086 | | |
1087 | | /* Dump the traceback of a Python thread into fd. Use write() to write the |
1088 | | traceback and retry if write() is interrupted by a signal (failed with |
1089 | | EINTR), but don't call the Python signal handler. |
1090 | | |
1091 | | The caller is responsible to call PyErr_CheckSignals() to call Python signal |
1092 | | handlers if signals were received. */ |
1093 | | void |
1094 | | _Py_DumpTraceback(int fd, PyThreadState *tstate) |
1095 | 0 | { |
1096 | 0 | dump_traceback(fd, tstate, 1); |
1097 | 0 | } |
1098 | | |
1099 | | #if defined(HAVE_PTHREAD_GETNAME_NP) || defined(HAVE_PTHREAD_GET_NAME_NP) |
1100 | | # if defined(__OpenBSD__) |
1101 | | /* pthread_*_np functions, especially pthread_{get,set}_name_np(). |
1102 | | pthread_np.h exists on both OpenBSD and FreeBSD but the latter declares |
1103 | | pthread_getname_np() and pthread_setname_np() in pthread.h as long as |
1104 | | __BSD_VISIBLE remains set. |
1105 | | */ |
1106 | | # include <pthread_np.h> |
1107 | | # endif |
1108 | | #endif |
1109 | | |
1110 | | /* Write the thread identifier into the file 'fd': "Current thread 0xHHHH:\" if |
1111 | | is_current is true, "Thread 0xHHHH:\n" otherwise. |
1112 | | |
1113 | | This function is signal safe. */ |
1114 | | |
1115 | | static void |
1116 | | write_thread_id(int fd, PyThreadState *tstate, int is_current) |
1117 | 0 | { |
1118 | 0 | if (is_current) |
1119 | 0 | PUTS(fd, "Current thread 0x"); |
1120 | 0 | else |
1121 | 0 | PUTS(fd, "Thread 0x"); |
1122 | 0 | _Py_DumpHexadecimal(fd, |
1123 | 0 | tstate->thread_id, |
1124 | 0 | sizeof(unsigned long) * 2); |
1125 | | |
1126 | | // Write the thread name |
1127 | 0 | #if defined(HAVE_PTHREAD_GETNAME_NP) || defined(HAVE_PTHREAD_GET_NAME_NP) |
1128 | 0 | char name[100]; |
1129 | 0 | pthread_t thread = (pthread_t)tstate->thread_id; |
1130 | 0 | #ifdef HAVE_PTHREAD_GETNAME_NP |
1131 | 0 | int rc = pthread_getname_np(thread, name, Py_ARRAY_LENGTH(name)); |
1132 | | #else /* defined(HAVE_PTHREAD_GET_NAME_NP) */ |
1133 | | int rc = 0; /* pthread_get_name_np() returns void */ |
1134 | | pthread_get_name_np(thread, name, Py_ARRAY_LENGTH(name)); |
1135 | | #endif |
1136 | 0 | if (!rc) { |
1137 | 0 | size_t len = strlen(name); |
1138 | 0 | if (len) { |
1139 | 0 | PUTS(fd, " ["); |
1140 | 0 | (void)_Py_write_noraise(fd, name, len); |
1141 | 0 | PUTS(fd, "]"); |
1142 | 0 | } |
1143 | 0 | } |
1144 | 0 | #endif |
1145 | |
|
1146 | 0 | PUTS(fd, " (most recent call first):\n"); |
1147 | 0 | } |
1148 | | |
1149 | | /* Dump the traceback of all Python threads into fd. Use write() to write the |
1150 | | traceback and retry if write() is interrupted by a signal (failed with |
1151 | | EINTR), but don't call the Python signal handler. |
1152 | | |
1153 | | The caller is responsible to call PyErr_CheckSignals() to call Python signal |
1154 | | handlers if signals were received. */ |
1155 | | const char* |
1156 | | _Py_DumpTracebackThreads(int fd, PyInterpreterState *interp, |
1157 | | PyThreadState *current_tstate) |
1158 | 0 | { |
1159 | 0 | if (current_tstate == NULL) { |
1160 | | /* _Py_DumpTracebackThreads() is called from signal handlers by |
1161 | | faulthandler. |
1162 | | |
1163 | | SIGSEGV, SIGFPE, SIGABRT, SIGBUS and SIGILL are synchronous signals |
1164 | | and are thus delivered to the thread that caused the fault. Get the |
1165 | | Python thread state of the current thread. |
1166 | | |
1167 | | PyThreadState_Get() doesn't give the state of the thread that caused |
1168 | | the fault if the thread released the GIL, and so |
1169 | | _PyThreadState_GET() cannot be used. Read the thread specific |
1170 | | storage (TSS) instead: call PyGILState_GetThisThreadState(). */ |
1171 | 0 | current_tstate = PyGILState_GetThisThreadState(); |
1172 | 0 | } |
1173 | |
|
1174 | 0 | if (current_tstate != NULL && tstate_is_freed(current_tstate)) { |
1175 | 0 | return "tstate is freed"; |
1176 | 0 | } |
1177 | | |
1178 | 0 | if (interp == NULL) { |
1179 | 0 | if (current_tstate == NULL) { |
1180 | 0 | interp = _PyGILState_GetInterpreterStateUnsafe(); |
1181 | 0 | if (interp == NULL) { |
1182 | | /* We need the interpreter state to get Python threads */ |
1183 | 0 | return "unable to get the interpreter state"; |
1184 | 0 | } |
1185 | 0 | } |
1186 | 0 | else { |
1187 | 0 | interp = current_tstate->interp; |
1188 | 0 | } |
1189 | 0 | } |
1190 | 0 | assert(interp != NULL); |
1191 | |
|
1192 | 0 | if (interp_is_freed(interp)) { |
1193 | 0 | return "interp is freed"; |
1194 | 0 | } |
1195 | | |
1196 | | /* Get the current interpreter from the current thread */ |
1197 | 0 | PyThreadState *tstate = PyInterpreterState_ThreadHead(interp); |
1198 | 0 | if (tstate == NULL) |
1199 | 0 | return "unable to get the thread head state"; |
1200 | | |
1201 | | /* Dump the traceback of each thread */ |
1202 | 0 | tstate = PyInterpreterState_ThreadHead(interp); |
1203 | 0 | unsigned int nthreads = 0; |
1204 | 0 | _Py_BEGIN_SUPPRESS_IPH |
1205 | 0 | do |
1206 | 0 | { |
1207 | 0 | if (nthreads != 0) |
1208 | 0 | PUTS(fd, "\n"); |
1209 | 0 | if (nthreads >= MAX_NTHREADS) { |
1210 | 0 | PUTS(fd, "...\n"); |
1211 | 0 | break; |
1212 | 0 | } |
1213 | 0 | write_thread_id(fd, tstate, tstate == current_tstate); |
1214 | 0 | if (tstate == current_tstate && tstate->interp->gc.collecting) { |
1215 | 0 | PUTS(fd, " Garbage-collecting\n"); |
1216 | 0 | } |
1217 | 0 | dump_traceback(fd, tstate, 0); |
1218 | 0 | tstate = PyThreadState_Next(tstate); |
1219 | 0 | nthreads++; |
1220 | 0 | } while (tstate != NULL); |
1221 | 0 | _Py_END_SUPPRESS_IPH |
1222 | | |
1223 | 0 | return NULL; |
1224 | 0 | } |
1225 | | |
1226 | | #ifdef CAN_C_BACKTRACE |
1227 | | /* Based on glibc's implementation of backtrace_symbols(), but only uses stack memory. */ |
1228 | | void |
1229 | | _Py_backtrace_symbols_fd(int fd, void *const *array, Py_ssize_t size) |
1230 | 0 | { |
1231 | 0 | VLA(Dl_info, info, size); |
1232 | 0 | VLA(int, status, size); |
1233 | | /* Fill in the information we can get from dladdr() */ |
1234 | 0 | for (Py_ssize_t i = 0; i < size; ++i) { |
1235 | | #ifdef __APPLE__ |
1236 | | status[i] = dladdr(array[i], &info[i]); |
1237 | | #else |
1238 | 0 | struct link_map *map; |
1239 | 0 | status[i] = dladdr1(array[i], &info[i], (void **)&map, RTLD_DL_LINKMAP); |
1240 | 0 | if (status[i] != 0 |
1241 | 0 | && info[i].dli_fname != NULL |
1242 | 0 | && info[i].dli_fname[0] != '\0') { |
1243 | | /* The load bias is more useful to the user than the load |
1244 | | address. The use of these addresses is to calculate an |
1245 | | address in the ELF file, so its prelinked bias is not |
1246 | | something we want to subtract out */ |
1247 | 0 | info[i].dli_fbase = (void *) map->l_addr; |
1248 | 0 | } |
1249 | 0 | #endif |
1250 | 0 | } |
1251 | 0 | for (Py_ssize_t i = 0; i < size; ++i) { |
1252 | 0 | if (status[i] == 0 |
1253 | 0 | || info[i].dli_fname == NULL |
1254 | 0 | || info[i].dli_fname[0] == '\0' |
1255 | 0 | ) { |
1256 | 0 | PUTS(fd, " Binary file '<unknown>' ["); |
1257 | 0 | dump_pointer(fd, array[i]); |
1258 | 0 | PUTS(fd, "]\n"); |
1259 | 0 | continue; |
1260 | 0 | } |
1261 | | |
1262 | 0 | if (info[i].dli_sname == NULL) { |
1263 | | /* We found no symbol name to use, so describe it as |
1264 | | relative to the file. */ |
1265 | 0 | info[i].dli_saddr = info[i].dli_fbase; |
1266 | 0 | } |
1267 | |
|
1268 | 0 | if (info[i].dli_sname == NULL && info[i].dli_saddr == 0) { |
1269 | 0 | PUTS(fd, " Binary file \""); |
1270 | 0 | PUTS(fd, info[i].dli_fname); |
1271 | 0 | PUTS(fd, "\" ["); |
1272 | 0 | dump_pointer(fd, array[i]); |
1273 | 0 | PUTS(fd, "]\n"); |
1274 | 0 | } |
1275 | 0 | else { |
1276 | 0 | char sign; |
1277 | 0 | ptrdiff_t offset; |
1278 | 0 | if (array[i] >= (void *) info[i].dli_saddr) { |
1279 | 0 | sign = '+'; |
1280 | 0 | offset = array[i] - info[i].dli_saddr; |
1281 | 0 | } |
1282 | 0 | else { |
1283 | 0 | sign = '-'; |
1284 | 0 | offset = info[i].dli_saddr - array[i]; |
1285 | 0 | } |
1286 | 0 | const char *symbol_name = info[i].dli_sname != NULL ? info[i].dli_sname : ""; |
1287 | 0 | PUTS(fd, " Binary file \""); |
1288 | 0 | PUTS(fd, info[i].dli_fname); |
1289 | 0 | PUTS(fd, "\", at "); |
1290 | 0 | PUTS(fd, symbol_name); |
1291 | 0 | dump_char(fd, sign); |
1292 | 0 | PUTS(fd, "0x"); |
1293 | 0 | dump_hexadecimal(fd, offset, sizeof(offset), 1); |
1294 | 0 | PUTS(fd, " ["); |
1295 | 0 | dump_pointer(fd, array[i]); |
1296 | 0 | PUTS(fd, "]\n"); |
1297 | 0 | } |
1298 | 0 | } |
1299 | 0 | } |
1300 | | |
1301 | | void |
1302 | | _Py_DumpStack(int fd) |
1303 | 0 | { |
1304 | 0 | #define BACKTRACE_SIZE 32 |
1305 | 0 | PUTS(fd, "Current thread's C stack trace (most recent call first):\n"); |
1306 | 0 | VLA(void *, callstack, BACKTRACE_SIZE); |
1307 | 0 | int frames = backtrace(callstack, BACKTRACE_SIZE); |
1308 | 0 | if (frames == 0) { |
1309 | | // Some systems won't return anything for the stack trace |
1310 | 0 | PUTS(fd, " <system returned no stack trace>\n"); |
1311 | 0 | return; |
1312 | 0 | } |
1313 | | |
1314 | 0 | _Py_backtrace_symbols_fd(fd, callstack, frames); |
1315 | 0 | if (frames == BACKTRACE_SIZE) { |
1316 | 0 | PUTS(fd, " <truncated rest of calls>\n"); |
1317 | 0 | } |
1318 | |
|
1319 | 0 | #undef BACKTRACE_SIZE |
1320 | 0 | } |
1321 | | #else |
1322 | | void |
1323 | | _Py_DumpStack(int fd) |
1324 | | { |
1325 | | PUTS(fd, "Current thread's C stack trace (most recent call first):\n"); |
1326 | | PUTS(fd, " <cannot get C stack on this system>\n"); |
1327 | | } |
1328 | | #endif |