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