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