Coverage Report

Created: 2025-07-11 06:59

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