ยปCore Development>Code coverage>Modules/_tracemalloc.c

Python code coverage for Modules/_tracemalloc.c

#countcontent
1n/a#include "Python.h"
2n/a#include "hashtable.h"
3n/a#include "frameobject.h"
4n/a#include "pythread.h"
5n/a#include "osdefs.h"
6n/a
7n/a#include "clinic/_tracemalloc.c.h"
8n/a/*[clinic input]
9n/amodule _tracemalloc
10n/a[clinic start generated code]*/
11n/a/*[clinic end generated code: output=da39a3ee5e6b4b0d input=708a98302fc46e5f]*/
12n/a
13n/a/* Trace memory blocks allocated by PyMem_RawMalloc() */
14n/a#define TRACE_RAW_MALLOC
15n/a
16n/a/* Forward declaration */
17n/astatic void tracemalloc_stop(void);
18n/astatic void* raw_malloc(size_t size);
19n/astatic void raw_free(void *ptr);
20n/a
21n/a#ifdef Py_DEBUG
22n/a# define TRACE_DEBUG
23n/a#endif
24n/a
25n/a/* Protected by the GIL */
26n/astatic struct {
27n/a PyMemAllocatorEx mem;
28n/a PyMemAllocatorEx raw;
29n/a PyMemAllocatorEx obj;
30n/a} allocators;
31n/a
32n/astatic struct {
33n/a /* Module initialized?
34n/a Variable protected by the GIL */
35n/a enum {
36n/a TRACEMALLOC_NOT_INITIALIZED,
37n/a TRACEMALLOC_INITIALIZED,
38n/a TRACEMALLOC_FINALIZED
39n/a } initialized;
40n/a
41n/a /* Is tracemalloc tracing memory allocations?
42n/a Variable protected by the GIL */
43n/a int tracing;
44n/a
45n/a /* limit of the number of frames in a traceback, 1 by default.
46n/a Variable protected by the GIL. */
47n/a int max_nframe;
48n/a
49n/a /* use domain in trace key?
50n/a Variable protected by the GIL. */
51n/a int use_domain;
52n/a} tracemalloc_config = {TRACEMALLOC_NOT_INITIALIZED, 0, 1, 0};
53n/a
54n/a#if defined(TRACE_RAW_MALLOC) && defined(WITH_THREAD)
55n/a/* This lock is needed because tracemalloc_free() is called without
56n/a the GIL held from PyMem_RawFree(). It cannot acquire the lock because it
57n/a would introduce a deadlock in PyThreadState_DeleteCurrent(). */
58n/astatic PyThread_type_lock tables_lock;
59n/a# define TABLES_LOCK() PyThread_acquire_lock(tables_lock, 1)
60n/a# define TABLES_UNLOCK() PyThread_release_lock(tables_lock)
61n/a#else
62n/a /* variables are protected by the GIL */
63n/a# define TABLES_LOCK()
64n/a# define TABLES_UNLOCK()
65n/a#endif
66n/a
67n/a
68n/a#define DEFAULT_DOMAIN 0
69n/a
70n/a/* Pack the frame_t structure to reduce the memory footprint. */
71n/atypedef struct
72n/a#ifdef __GNUC__
73n/a__attribute__((packed))
74n/a#endif
75n/a{
76n/a uintptr_t ptr;
77n/a _PyTraceMalloc_domain_t domain;
78n/a} pointer_t;
79n/a
80n/a/* Pack the frame_t structure to reduce the memory footprint on 64-bit
81n/a architectures: 12 bytes instead of 16. */
82n/atypedef struct
83n/a#ifdef __GNUC__
84n/a__attribute__((packed))
85n/a#elif defined(_MSC_VER)
86n/a_declspec(align(4))
87n/a#endif
88n/a{
89n/a /* filename cannot be NULL: "<unknown>" is used if the Python frame
90n/a filename is NULL */
91n/a PyObject *filename;
92n/a unsigned int lineno;
93n/a} frame_t;
94n/a
95n/a
96n/atypedef struct {
97n/a Py_uhash_t hash;
98n/a int nframe;
99n/a frame_t frames[1];
100n/a} traceback_t;
101n/a
102n/a#define TRACEBACK_SIZE(NFRAME) \
103n/a (sizeof(traceback_t) + sizeof(frame_t) * (NFRAME - 1))
104n/a
105n/a#define MAX_NFRAME \
106n/a ((INT_MAX - (int)sizeof(traceback_t)) / (int)sizeof(frame_t) + 1)
107n/a
108n/a
109n/astatic PyObject *unknown_filename = NULL;
110n/astatic traceback_t tracemalloc_empty_traceback;
111n/a
112n/a/* Trace of a memory block */
113n/atypedef struct {
114n/a /* Size of the memory block in bytes */
115n/a size_t size;
116n/a
117n/a /* Traceback where the memory block was allocated */
118n/a traceback_t *traceback;
119n/a} trace_t;
120n/a
121n/a
122n/a/* Size in bytes of currently traced memory.
123n/a Protected by TABLES_LOCK(). */
124n/astatic size_t tracemalloc_traced_memory = 0;
125n/a
126n/a/* Peak size in bytes of traced memory.
127n/a Protected by TABLES_LOCK(). */
128n/astatic size_t tracemalloc_peak_traced_memory = 0;
129n/a
130n/a/* Hash table used as a set to intern filenames:
131n/a PyObject* => PyObject*.
132n/a Protected by the GIL */
133n/astatic _Py_hashtable_t *tracemalloc_filenames = NULL;
134n/a
135n/a/* Buffer to store a new traceback in traceback_new().
136n/a Protected by the GIL. */
137n/astatic traceback_t *tracemalloc_traceback = NULL;
138n/a
139n/a/* Hash table used as a set to intern tracebacks:
140n/a traceback_t* => traceback_t*
141n/a Protected by the GIL */
142n/astatic _Py_hashtable_t *tracemalloc_tracebacks = NULL;
143n/a
144n/a/* pointer (void*) => trace (trace_t).
145n/a Protected by TABLES_LOCK(). */
146n/astatic _Py_hashtable_t *tracemalloc_traces = NULL;
147n/a
148n/a
149n/a#ifdef TRACE_DEBUG
150n/astatic void
151n/atracemalloc_error(const char *format, ...)
152n/a{
153n/a va_list ap;
154n/a fprintf(stderr, "tracemalloc: ");
155n/a va_start(ap, format);
156n/a vfprintf(stderr, format, ap);
157n/a va_end(ap);
158n/a fprintf(stderr, "\n");
159n/a fflush(stderr);
160n/a}
161n/a#endif
162n/a
163n/a
164n/a#if defined(WITH_THREAD) && defined(TRACE_RAW_MALLOC)
165n/a#define REENTRANT_THREADLOCAL
166n/a
167n/a/* If your OS does not provide native thread local storage, you can implement
168n/a it manually using a lock. Functions of thread.c cannot be used because
169n/a they use PyMem_RawMalloc() which leads to a reentrant call. */
170n/a#if !(defined(_POSIX_THREADS) || defined(NT_THREADS))
171n/a# error "need native thread local storage (TLS)"
172n/a#endif
173n/a
174n/astatic int tracemalloc_reentrant_key = -1;
175n/a
176n/a/* Any non-NULL pointer can be used */
177n/a#define REENTRANT Py_True
178n/a
179n/astatic int
180n/aget_reentrant(void)
181n/a{
182n/a void *ptr;
183n/a
184n/a assert(tracemalloc_reentrant_key != -1);
185n/a ptr = PyThread_get_key_value(tracemalloc_reentrant_key);
186n/a if (ptr != NULL) {
187n/a assert(ptr == REENTRANT);
188n/a return 1;
189n/a }
190n/a else
191n/a return 0;
192n/a}
193n/a
194n/astatic void
195n/aset_reentrant(int reentrant)
196n/a{
197n/a assert(reentrant == 0 || reentrant == 1);
198n/a assert(tracemalloc_reentrant_key != -1);
199n/a
200n/a if (reentrant) {
201n/a assert(!get_reentrant());
202n/a PyThread_set_key_value(tracemalloc_reentrant_key, REENTRANT);
203n/a }
204n/a else {
205n/a assert(get_reentrant());
206n/a PyThread_set_key_value(tracemalloc_reentrant_key, NULL);
207n/a }
208n/a}
209n/a
210n/a#else
211n/a
212n/a/* WITH_THREAD not defined: Python compiled without threads,
213n/a or TRACE_RAW_MALLOC not defined: variable protected by the GIL */
214n/astatic int tracemalloc_reentrant = 0;
215n/a
216n/astatic int
217n/aget_reentrant(void)
218n/a{
219n/a return tracemalloc_reentrant;
220n/a}
221n/a
222n/astatic void
223n/aset_reentrant(int reentrant)
224n/a{
225n/a assert(reentrant != tracemalloc_reentrant);
226n/a tracemalloc_reentrant = reentrant;
227n/a}
228n/a#endif
229n/a
230n/a
231n/astatic Py_uhash_t
232n/ahashtable_hash_pyobject(_Py_hashtable_t *ht, const void *pkey)
233n/a{
234n/a PyObject *obj;
235n/a
236n/a _Py_HASHTABLE_READ_KEY(ht, pkey, obj);
237n/a return PyObject_Hash(obj);
238n/a}
239n/a
240n/a
241n/astatic int
242n/ahashtable_compare_unicode(_Py_hashtable_t *ht, const void *pkey,
243n/a const _Py_hashtable_entry_t *entry)
244n/a{
245n/a PyObject *key1, *key2;
246n/a
247n/a _Py_HASHTABLE_READ_KEY(ht, pkey, key1);
248n/a _Py_HASHTABLE_ENTRY_READ_KEY(ht, entry, key2);
249n/a
250n/a if (key1 != NULL && key2 != NULL)
251n/a return (PyUnicode_Compare(key1, key2) == 0);
252n/a else
253n/a return key1 == key2;
254n/a}
255n/a
256n/a
257n/astatic Py_uhash_t
258n/ahashtable_hash_pointer_t(_Py_hashtable_t *ht, const void *pkey)
259n/a{
260n/a pointer_t ptr;
261n/a Py_uhash_t hash;
262n/a
263n/a _Py_HASHTABLE_READ_KEY(ht, pkey, ptr);
264n/a
265n/a hash = (Py_uhash_t)_Py_HashPointer((void*)ptr.ptr);
266n/a hash ^= ptr.domain;
267n/a return hash;
268n/a}
269n/a
270n/a
271n/astatic int
272n/ahashtable_compare_pointer_t(_Py_hashtable_t *ht, const void *pkey,
273n/a const _Py_hashtable_entry_t *entry)
274n/a{
275n/a pointer_t ptr1, ptr2;
276n/a
277n/a _Py_HASHTABLE_READ_KEY(ht, pkey, ptr1);
278n/a _Py_HASHTABLE_ENTRY_READ_KEY(ht, entry, ptr2);
279n/a
280n/a /* compare pointer before domain, because pointer is more likely to be
281n/a different */
282n/a return (ptr1.ptr == ptr2.ptr && ptr1.domain == ptr2.domain);
283n/a
284n/a}
285n/a
286n/a
287n/astatic _Py_hashtable_t *
288n/ahashtable_new(size_t key_size, size_t data_size,
289n/a _Py_hashtable_hash_func hash_func,
290n/a _Py_hashtable_compare_func compare_func)
291n/a{
292n/a _Py_hashtable_allocator_t hashtable_alloc = {malloc, free};
293n/a return _Py_hashtable_new_full(key_size, data_size, 0,
294n/a hash_func, compare_func,
295n/a &hashtable_alloc);
296n/a}
297n/a
298n/a
299n/astatic void*
300n/araw_malloc(size_t size)
301n/a{
302n/a return allocators.raw.malloc(allocators.raw.ctx, size);
303n/a}
304n/a
305n/astatic void
306n/araw_free(void *ptr)
307n/a{
308n/a allocators.raw.free(allocators.raw.ctx, ptr);
309n/a}
310n/a
311n/a
312n/astatic Py_uhash_t
313n/ahashtable_hash_traceback(_Py_hashtable_t *ht, const void *pkey)
314n/a{
315n/a traceback_t *traceback;
316n/a
317n/a _Py_HASHTABLE_READ_KEY(ht, pkey, traceback);
318n/a return traceback->hash;
319n/a}
320n/a
321n/a
322n/astatic int
323n/ahashtable_compare_traceback(_Py_hashtable_t *ht, const void *pkey,
324n/a const _Py_hashtable_entry_t *entry)
325n/a{
326n/a traceback_t *traceback1, *traceback2;
327n/a const frame_t *frame1, *frame2;
328n/a int i;
329n/a
330n/a _Py_HASHTABLE_READ_KEY(ht, pkey, traceback1);
331n/a _Py_HASHTABLE_ENTRY_READ_KEY(ht, entry, traceback2);
332n/a
333n/a if (traceback1->nframe != traceback2->nframe)
334n/a return 0;
335n/a
336n/a for (i=0; i < traceback1->nframe; i++) {
337n/a frame1 = &traceback1->frames[i];
338n/a frame2 = &traceback2->frames[i];
339n/a
340n/a if (frame1->lineno != frame2->lineno)
341n/a return 0;
342n/a
343n/a if (frame1->filename != frame2->filename) {
344n/a assert(PyUnicode_Compare(frame1->filename, frame2->filename) != 0);
345n/a return 0;
346n/a }
347n/a }
348n/a return 1;
349n/a}
350n/a
351n/a
352n/astatic void
353n/atracemalloc_get_frame(PyFrameObject *pyframe, frame_t *frame)
354n/a{
355n/a PyCodeObject *code;
356n/a PyObject *filename;
357n/a _Py_hashtable_entry_t *entry;
358n/a int lineno;
359n/a
360n/a frame->filename = unknown_filename;
361n/a lineno = PyFrame_GetLineNumber(pyframe);
362n/a if (lineno < 0)
363n/a lineno = 0;
364n/a frame->lineno = (unsigned int)lineno;
365n/a
366n/a code = pyframe->f_code;
367n/a if (code == NULL) {
368n/a#ifdef TRACE_DEBUG
369n/a tracemalloc_error("failed to get the code object of the frame");
370n/a#endif
371n/a return;
372n/a }
373n/a
374n/a if (code->co_filename == NULL) {
375n/a#ifdef TRACE_DEBUG
376n/a tracemalloc_error("failed to get the filename of the code object");
377n/a#endif
378n/a return;
379n/a }
380n/a
381n/a filename = code->co_filename;
382n/a assert(filename != NULL);
383n/a if (filename == NULL)
384n/a return;
385n/a
386n/a if (!PyUnicode_Check(filename)) {
387n/a#ifdef TRACE_DEBUG
388n/a tracemalloc_error("filename is not a unicode string");
389n/a#endif
390n/a return;
391n/a }
392n/a if (!PyUnicode_IS_READY(filename)) {
393n/a /* Don't make a Unicode string ready to avoid reentrant calls
394n/a to tracemalloc_malloc() or tracemalloc_realloc() */
395n/a#ifdef TRACE_DEBUG
396n/a tracemalloc_error("filename is not a ready unicode string");
397n/a#endif
398n/a return;
399n/a }
400n/a
401n/a /* intern the filename */
402n/a entry = _Py_HASHTABLE_GET_ENTRY(tracemalloc_filenames, filename);
403n/a if (entry != NULL) {
404n/a _Py_HASHTABLE_ENTRY_READ_KEY(tracemalloc_filenames, entry, filename);
405n/a }
406n/a else {
407n/a /* tracemalloc_filenames is responsible to keep a reference
408n/a to the filename */
409n/a Py_INCREF(filename);
410n/a if (_Py_HASHTABLE_SET_NODATA(tracemalloc_filenames, filename) < 0) {
411n/a Py_DECREF(filename);
412n/a#ifdef TRACE_DEBUG
413n/a tracemalloc_error("failed to intern the filename");
414n/a#endif
415n/a return;
416n/a }
417n/a }
418n/a
419n/a /* the tracemalloc_filenames table keeps a reference to the filename */
420n/a frame->filename = filename;
421n/a}
422n/a
423n/a
424n/astatic Py_uhash_t
425n/atraceback_hash(traceback_t *traceback)
426n/a{
427n/a /* code based on tuplehash() of Objects/tupleobject.c */
428n/a Py_uhash_t x, y; /* Unsigned for defined overflow behavior. */
429n/a int len = traceback->nframe;
430n/a Py_uhash_t mult = _PyHASH_MULTIPLIER;
431n/a frame_t *frame;
432n/a
433n/a x = 0x345678UL;
434n/a frame = traceback->frames;
435n/a while (--len >= 0) {
436n/a y = (Py_uhash_t)PyObject_Hash(frame->filename);
437n/a y ^= (Py_uhash_t)frame->lineno;
438n/a frame++;
439n/a
440n/a x = (x ^ y) * mult;
441n/a /* the cast might truncate len; that doesn't change hash stability */
442n/a mult += (Py_uhash_t)(82520UL + len + len);
443n/a }
444n/a x += 97531UL;
445n/a return x;
446n/a}
447n/a
448n/a
449n/astatic void
450n/atraceback_get_frames(traceback_t *traceback)
451n/a{
452n/a PyThreadState *tstate;
453n/a PyFrameObject *pyframe;
454n/a
455n/a#ifdef WITH_THREAD
456n/a tstate = PyGILState_GetThisThreadState();
457n/a#else
458n/a tstate = PyThreadState_Get();
459n/a#endif
460n/a if (tstate == NULL) {
461n/a#ifdef TRACE_DEBUG
462n/a tracemalloc_error("failed to get the current thread state");
463n/a#endif
464n/a return;
465n/a }
466n/a
467n/a for (pyframe = tstate->frame; pyframe != NULL; pyframe = pyframe->f_back) {
468n/a tracemalloc_get_frame(pyframe, &traceback->frames[traceback->nframe]);
469n/a assert(traceback->frames[traceback->nframe].filename != NULL);
470n/a traceback->nframe++;
471n/a if (traceback->nframe == tracemalloc_config.max_nframe)
472n/a break;
473n/a }
474n/a}
475n/a
476n/a
477n/astatic traceback_t *
478n/atraceback_new(void)
479n/a{
480n/a traceback_t *traceback;
481n/a _Py_hashtable_entry_t *entry;
482n/a
483n/a#ifdef WITH_THREAD
484n/a assert(PyGILState_Check());
485n/a#endif
486n/a
487n/a /* get frames */
488n/a traceback = tracemalloc_traceback;
489n/a traceback->nframe = 0;
490n/a traceback_get_frames(traceback);
491n/a if (traceback->nframe == 0)
492n/a return &tracemalloc_empty_traceback;
493n/a traceback->hash = traceback_hash(traceback);
494n/a
495n/a /* intern the traceback */
496n/a entry = _Py_HASHTABLE_GET_ENTRY(tracemalloc_tracebacks, traceback);
497n/a if (entry != NULL) {
498n/a _Py_HASHTABLE_ENTRY_READ_KEY(tracemalloc_tracebacks, entry, traceback);
499n/a }
500n/a else {
501n/a traceback_t *copy;
502n/a size_t traceback_size;
503n/a
504n/a traceback_size = TRACEBACK_SIZE(traceback->nframe);
505n/a
506n/a copy = raw_malloc(traceback_size);
507n/a if (copy == NULL) {
508n/a#ifdef TRACE_DEBUG
509n/a tracemalloc_error("failed to intern the traceback: malloc failed");
510n/a#endif
511n/a return NULL;
512n/a }
513n/a memcpy(copy, traceback, traceback_size);
514n/a
515n/a if (_Py_HASHTABLE_SET_NODATA(tracemalloc_tracebacks, copy) < 0) {
516n/a raw_free(copy);
517n/a#ifdef TRACE_DEBUG
518n/a tracemalloc_error("failed to intern the traceback: putdata failed");
519n/a#endif
520n/a return NULL;
521n/a }
522n/a traceback = copy;
523n/a }
524n/a return traceback;
525n/a}
526n/a
527n/a
528n/astatic int
529n/atracemalloc_use_domain_cb(_Py_hashtable_t *old_traces,
530n/a _Py_hashtable_entry_t *entry, void *user_data)
531n/a{
532n/a uintptr_t ptr;
533n/a pointer_t key;
534n/a _Py_hashtable_t *new_traces = (_Py_hashtable_t *)user_data;
535n/a const void *pdata = _Py_HASHTABLE_ENTRY_PDATA(old_traces, entry);
536n/a
537n/a _Py_HASHTABLE_ENTRY_READ_KEY(old_traces, entry, ptr);
538n/a key.ptr = ptr;
539n/a key.domain = DEFAULT_DOMAIN;
540n/a
541n/a return _Py_hashtable_set(new_traces,
542n/a sizeof(key), &key,
543n/a old_traces->data_size, pdata);
544n/a}
545n/a
546n/a
547n/a/* Convert tracemalloc_traces from compact key (uintptr_t) to pointer_t key.
548n/a * Return 0 on success, -1 on error. */
549n/astatic int
550n/atracemalloc_use_domain(void)
551n/a{
552n/a _Py_hashtable_t *new_traces = NULL;
553n/a
554n/a assert(!tracemalloc_config.use_domain);
555n/a
556n/a new_traces = hashtable_new(sizeof(pointer_t),
557n/a sizeof(trace_t),
558n/a hashtable_hash_pointer_t,
559n/a hashtable_compare_pointer_t);
560n/a if (new_traces == NULL) {
561n/a return -1;
562n/a }
563n/a
564n/a if (_Py_hashtable_foreach(tracemalloc_traces, tracemalloc_use_domain_cb,
565n/a new_traces) < 0)
566n/a {
567n/a _Py_hashtable_destroy(new_traces);
568n/a return -1;
569n/a }
570n/a
571n/a _Py_hashtable_destroy(tracemalloc_traces);
572n/a tracemalloc_traces = new_traces;
573n/a
574n/a tracemalloc_config.use_domain = 1;
575n/a
576n/a return 0;
577n/a}
578n/a
579n/a
580n/astatic void
581n/atracemalloc_remove_trace(_PyTraceMalloc_domain_t domain, uintptr_t ptr)
582n/a{
583n/a trace_t trace;
584n/a int removed;
585n/a
586n/a assert(tracemalloc_config.tracing);
587n/a
588n/a if (tracemalloc_config.use_domain) {
589n/a pointer_t key = {ptr, domain};
590n/a removed = _Py_HASHTABLE_POP(tracemalloc_traces, key, trace);
591n/a }
592n/a else {
593n/a removed = _Py_HASHTABLE_POP(tracemalloc_traces, ptr, trace);
594n/a }
595n/a if (!removed) {
596n/a return;
597n/a }
598n/a
599n/a assert(tracemalloc_traced_memory >= trace.size);
600n/a tracemalloc_traced_memory -= trace.size;
601n/a}
602n/a
603n/a#define REMOVE_TRACE(ptr) \
604n/a tracemalloc_remove_trace(DEFAULT_DOMAIN, (uintptr_t)(ptr))
605n/a
606n/a
607n/astatic int
608n/atracemalloc_add_trace(_PyTraceMalloc_domain_t domain, uintptr_t ptr,
609n/a size_t size)
610n/a{
611n/a pointer_t key = {ptr, domain};
612n/a traceback_t *traceback;
613n/a trace_t trace;
614n/a _Py_hashtable_entry_t* entry;
615n/a int res;
616n/a
617n/a assert(tracemalloc_config.tracing);
618n/a
619n/a traceback = traceback_new();
620n/a if (traceback == NULL) {
621n/a return -1;
622n/a }
623n/a
624n/a if (!tracemalloc_config.use_domain && domain != DEFAULT_DOMAIN) {
625n/a /* first trace using a non-zero domain whereas traces use compact
626n/a (uintptr_t) keys: switch to pointer_t keys. */
627n/a if (tracemalloc_use_domain() < 0) {
628n/a return -1;
629n/a }
630n/a }
631n/a
632n/a if (tracemalloc_config.use_domain) {
633n/a entry = _Py_HASHTABLE_GET_ENTRY(tracemalloc_traces, key);
634n/a }
635n/a else {
636n/a entry = _Py_HASHTABLE_GET_ENTRY(tracemalloc_traces, ptr);
637n/a }
638n/a
639n/a if (entry != NULL) {
640n/a /* the memory block is already tracked */
641n/a _Py_HASHTABLE_ENTRY_READ_DATA(tracemalloc_traces, entry, trace);
642n/a assert(tracemalloc_traced_memory >= trace.size);
643n/a tracemalloc_traced_memory -= trace.size;
644n/a
645n/a trace.size = size;
646n/a trace.traceback = traceback;
647n/a _Py_HASHTABLE_ENTRY_WRITE_DATA(tracemalloc_traces, entry, trace);
648n/a }
649n/a else {
650n/a trace.size = size;
651n/a trace.traceback = traceback;
652n/a
653n/a if (tracemalloc_config.use_domain) {
654n/a res = _Py_HASHTABLE_SET(tracemalloc_traces, key, trace);
655n/a }
656n/a else {
657n/a res = _Py_HASHTABLE_SET(tracemalloc_traces, ptr, trace);
658n/a }
659n/a if (res != 0) {
660n/a return res;
661n/a }
662n/a }
663n/a
664n/a assert(tracemalloc_traced_memory <= SIZE_MAX - size);
665n/a tracemalloc_traced_memory += size;
666n/a if (tracemalloc_traced_memory > tracemalloc_peak_traced_memory)
667n/a tracemalloc_peak_traced_memory = tracemalloc_traced_memory;
668n/a return 0;
669n/a}
670n/a
671n/a#define ADD_TRACE(ptr, size) \
672n/a tracemalloc_add_trace(DEFAULT_DOMAIN, (uintptr_t)(ptr), size)
673n/a
674n/a
675n/astatic void*
676n/atracemalloc_alloc(int use_calloc, void *ctx, size_t nelem, size_t elsize)
677n/a{
678n/a PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx;
679n/a void *ptr;
680n/a
681n/a assert(elsize == 0 || nelem <= SIZE_MAX / elsize);
682n/a
683n/a if (use_calloc)
684n/a ptr = alloc->calloc(alloc->ctx, nelem, elsize);
685n/a else
686n/a ptr = alloc->malloc(alloc->ctx, nelem * elsize);
687n/a if (ptr == NULL)
688n/a return NULL;
689n/a
690n/a TABLES_LOCK();
691n/a if (ADD_TRACE(ptr, nelem * elsize) < 0) {
692n/a /* Failed to allocate a trace for the new memory block */
693n/a TABLES_UNLOCK();
694n/a alloc->free(alloc->ctx, ptr);
695n/a return NULL;
696n/a }
697n/a TABLES_UNLOCK();
698n/a return ptr;
699n/a}
700n/a
701n/a
702n/astatic void*
703n/atracemalloc_realloc(void *ctx, void *ptr, size_t new_size)
704n/a{
705n/a PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx;
706n/a void *ptr2;
707n/a
708n/a ptr2 = alloc->realloc(alloc->ctx, ptr, new_size);
709n/a if (ptr2 == NULL)
710n/a return NULL;
711n/a
712n/a if (ptr != NULL) {
713n/a /* an existing memory block has been resized */
714n/a
715n/a TABLES_LOCK();
716n/a
717n/a /* tracemalloc_add_trace() updates the trace if there is already
718n/a a trace at address (domain, ptr2) */
719n/a if (ptr2 != ptr) {
720n/a REMOVE_TRACE(ptr);
721n/a }
722n/a
723n/a if (ADD_TRACE(ptr2, new_size) < 0) {
724n/a /* Memory allocation failed. The error cannot be reported to
725n/a the caller, because realloc() may already have shrunk the
726n/a memory block and so removed bytes.
727n/a
728n/a This case is very unlikely: a hash entry has just been
729n/a released, so the hash table should have at least one free entry.
730n/a
731n/a The GIL and the table lock ensures that only one thread is
732n/a allocating memory. */
733n/a assert(0 && "should never happen");
734n/a }
735n/a TABLES_UNLOCK();
736n/a }
737n/a else {
738n/a /* new allocation */
739n/a
740n/a TABLES_LOCK();
741n/a if (ADD_TRACE(ptr2, new_size) < 0) {
742n/a /* Failed to allocate a trace for the new memory block */
743n/a TABLES_UNLOCK();
744n/a alloc->free(alloc->ctx, ptr2);
745n/a return NULL;
746n/a }
747n/a TABLES_UNLOCK();
748n/a }
749n/a return ptr2;
750n/a}
751n/a
752n/a
753n/astatic void
754n/atracemalloc_free(void *ctx, void *ptr)
755n/a{
756n/a PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx;
757n/a
758n/a if (ptr == NULL)
759n/a return;
760n/a
761n/a /* GIL cannot be locked in PyMem_RawFree() because it would introduce
762n/a a deadlock in PyThreadState_DeleteCurrent(). */
763n/a
764n/a alloc->free(alloc->ctx, ptr);
765n/a
766n/a TABLES_LOCK();
767n/a REMOVE_TRACE(ptr);
768n/a TABLES_UNLOCK();
769n/a}
770n/a
771n/a
772n/astatic void*
773n/atracemalloc_alloc_gil(int use_calloc, void *ctx, size_t nelem, size_t elsize)
774n/a{
775n/a void *ptr;
776n/a
777n/a if (get_reentrant()) {
778n/a PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx;
779n/a if (use_calloc)
780n/a return alloc->calloc(alloc->ctx, nelem, elsize);
781n/a else
782n/a return alloc->malloc(alloc->ctx, nelem * elsize);
783n/a }
784n/a
785n/a /* Ignore reentrant call. PyObjet_Malloc() calls PyMem_Malloc() for
786n/a allocations larger than 512 bytes, don't trace the same memory
787n/a allocation twice. */
788n/a set_reentrant(1);
789n/a
790n/a ptr = tracemalloc_alloc(use_calloc, ctx, nelem, elsize);
791n/a
792n/a set_reentrant(0);
793n/a return ptr;
794n/a}
795n/a
796n/a
797n/astatic void*
798n/atracemalloc_malloc_gil(void *ctx, size_t size)
799n/a{
800n/a return tracemalloc_alloc_gil(0, ctx, 1, size);
801n/a}
802n/a
803n/a
804n/astatic void*
805n/atracemalloc_calloc_gil(void *ctx, size_t nelem, size_t elsize)
806n/a{
807n/a return tracemalloc_alloc_gil(1, ctx, nelem, elsize);
808n/a}
809n/a
810n/a
811n/astatic void*
812n/atracemalloc_realloc_gil(void *ctx, void *ptr, size_t new_size)
813n/a{
814n/a void *ptr2;
815n/a
816n/a if (get_reentrant()) {
817n/a /* Reentrant call to PyMem_Realloc() and PyMem_RawRealloc().
818n/a Example: PyMem_RawRealloc() is called internally by pymalloc
819n/a (_PyObject_Malloc() and _PyObject_Realloc()) to allocate a new
820n/a arena (new_arena()). */
821n/a PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx;
822n/a
823n/a ptr2 = alloc->realloc(alloc->ctx, ptr, new_size);
824n/a if (ptr2 != NULL && ptr != NULL) {
825n/a TABLES_LOCK();
826n/a REMOVE_TRACE(ptr);
827n/a TABLES_UNLOCK();
828n/a }
829n/a return ptr2;
830n/a }
831n/a
832n/a /* Ignore reentrant call. PyObjet_Realloc() calls PyMem_Realloc() for
833n/a allocations larger than 512 bytes. Don't trace the same memory
834n/a allocation twice. */
835n/a set_reentrant(1);
836n/a
837n/a ptr2 = tracemalloc_realloc(ctx, ptr, new_size);
838n/a
839n/a set_reentrant(0);
840n/a return ptr2;
841n/a}
842n/a
843n/a
844n/a#ifdef TRACE_RAW_MALLOC
845n/astatic void*
846n/atracemalloc_raw_alloc(int use_calloc, void *ctx, size_t nelem, size_t elsize)
847n/a{
848n/a#ifdef WITH_THREAD
849n/a PyGILState_STATE gil_state;
850n/a#endif
851n/a void *ptr;
852n/a
853n/a if (get_reentrant()) {
854n/a PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx;
855n/a if (use_calloc)
856n/a return alloc->calloc(alloc->ctx, nelem, elsize);
857n/a else
858n/a return alloc->malloc(alloc->ctx, nelem * elsize);
859n/a }
860n/a
861n/a /* Ignore reentrant call. PyGILState_Ensure() may call PyMem_RawMalloc()
862n/a indirectly which would call PyGILState_Ensure() if reentrant are not
863n/a disabled. */
864n/a set_reentrant(1);
865n/a
866n/a#ifdef WITH_THREAD
867n/a gil_state = PyGILState_Ensure();
868n/a ptr = tracemalloc_alloc(use_calloc, ctx, nelem, elsize);
869n/a PyGILState_Release(gil_state);
870n/a#else
871n/a ptr = tracemalloc_alloc(use_calloc, ctx, nelem, elsize);
872n/a#endif
873n/a
874n/a set_reentrant(0);
875n/a return ptr;
876n/a}
877n/a
878n/a
879n/astatic void*
880n/atracemalloc_raw_malloc(void *ctx, size_t size)
881n/a{
882n/a return tracemalloc_raw_alloc(0, ctx, 1, size);
883n/a}
884n/a
885n/a
886n/astatic void*
887n/atracemalloc_raw_calloc(void *ctx, size_t nelem, size_t elsize)
888n/a{
889n/a return tracemalloc_raw_alloc(1, ctx, nelem, elsize);
890n/a}
891n/a
892n/a
893n/astatic void*
894n/atracemalloc_raw_realloc(void *ctx, void *ptr, size_t new_size)
895n/a{
896n/a#ifdef WITH_THREAD
897n/a PyGILState_STATE gil_state;
898n/a#endif
899n/a void *ptr2;
900n/a
901n/a if (get_reentrant()) {
902n/a /* Reentrant call to PyMem_RawRealloc(). */
903n/a PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx;
904n/a
905n/a ptr2 = alloc->realloc(alloc->ctx, ptr, new_size);
906n/a
907n/a if (ptr2 != NULL && ptr != NULL) {
908n/a TABLES_LOCK();
909n/a REMOVE_TRACE(ptr);
910n/a TABLES_UNLOCK();
911n/a }
912n/a return ptr2;
913n/a }
914n/a
915n/a /* Ignore reentrant call. PyGILState_Ensure() may call PyMem_RawMalloc()
916n/a indirectly which would call PyGILState_Ensure() if reentrant calls are
917n/a not disabled. */
918n/a set_reentrant(1);
919n/a
920n/a#ifdef WITH_THREAD
921n/a gil_state = PyGILState_Ensure();
922n/a ptr2 = tracemalloc_realloc(ctx, ptr, new_size);
923n/a PyGILState_Release(gil_state);
924n/a#else
925n/a ptr2 = tracemalloc_realloc(ctx, ptr, new_size);
926n/a#endif
927n/a
928n/a set_reentrant(0);
929n/a return ptr2;
930n/a}
931n/a#endif /* TRACE_RAW_MALLOC */
932n/a
933n/a
934n/astatic int
935n/atracemalloc_clear_filename(_Py_hashtable_t *ht, _Py_hashtable_entry_t *entry,
936n/a void *user_data)
937n/a{
938n/a PyObject *filename;
939n/a
940n/a _Py_HASHTABLE_ENTRY_READ_KEY(ht, entry, filename);
941n/a Py_DECREF(filename);
942n/a return 0;
943n/a}
944n/a
945n/a
946n/astatic int
947n/atraceback_free_traceback(_Py_hashtable_t *ht, _Py_hashtable_entry_t *entry,
948n/a void *user_data)
949n/a{
950n/a traceback_t *traceback;
951n/a
952n/a _Py_HASHTABLE_ENTRY_READ_KEY(ht, entry, traceback);
953n/a raw_free(traceback);
954n/a return 0;
955n/a}
956n/a
957n/a
958n/a/* reentrant flag must be set to call this function and GIL must be held */
959n/astatic void
960n/atracemalloc_clear_traces(void)
961n/a{
962n/a#ifdef WITH_THREAD
963n/a /* The GIL protects variables againt concurrent access */
964n/a assert(PyGILState_Check());
965n/a#endif
966n/a
967n/a TABLES_LOCK();
968n/a _Py_hashtable_clear(tracemalloc_traces);
969n/a tracemalloc_traced_memory = 0;
970n/a tracemalloc_peak_traced_memory = 0;
971n/a TABLES_UNLOCK();
972n/a
973n/a _Py_hashtable_foreach(tracemalloc_tracebacks, traceback_free_traceback, NULL);
974n/a _Py_hashtable_clear(tracemalloc_tracebacks);
975n/a
976n/a _Py_hashtable_foreach(tracemalloc_filenames, tracemalloc_clear_filename, NULL);
977n/a _Py_hashtable_clear(tracemalloc_filenames);
978n/a}
979n/a
980n/a
981n/astatic int
982n/atracemalloc_init(void)
983n/a{
984n/a if (tracemalloc_config.initialized == TRACEMALLOC_FINALIZED) {
985n/a PyErr_SetString(PyExc_RuntimeError,
986n/a "the tracemalloc module has been unloaded");
987n/a return -1;
988n/a }
989n/a
990n/a if (tracemalloc_config.initialized == TRACEMALLOC_INITIALIZED)
991n/a return 0;
992n/a
993n/a PyMem_GetAllocator(PYMEM_DOMAIN_RAW, &allocators.raw);
994n/a
995n/a#ifdef REENTRANT_THREADLOCAL
996n/a tracemalloc_reentrant_key = PyThread_create_key();
997n/a if (tracemalloc_reentrant_key == -1) {
998n/a#ifdef MS_WINDOWS
999n/a PyErr_SetFromWindowsErr(0);
1000n/a#else
1001n/a PyErr_SetFromErrno(PyExc_OSError);
1002n/a#endif
1003n/a return -1;
1004n/a }
1005n/a#endif
1006n/a
1007n/a#if defined(WITH_THREAD) && defined(TRACE_RAW_MALLOC)
1008n/a if (tables_lock == NULL) {
1009n/a tables_lock = PyThread_allocate_lock();
1010n/a if (tables_lock == NULL) {
1011n/a PyErr_SetString(PyExc_RuntimeError, "cannot allocate lock");
1012n/a return -1;
1013n/a }
1014n/a }
1015n/a#endif
1016n/a
1017n/a tracemalloc_filenames = hashtable_new(sizeof(PyObject *), 0,
1018n/a hashtable_hash_pyobject,
1019n/a hashtable_compare_unicode);
1020n/a
1021n/a tracemalloc_tracebacks = hashtable_new(sizeof(traceback_t *), 0,
1022n/a hashtable_hash_traceback,
1023n/a hashtable_compare_traceback);
1024n/a
1025n/a if (tracemalloc_config.use_domain) {
1026n/a tracemalloc_traces = hashtable_new(sizeof(pointer_t),
1027n/a sizeof(trace_t),
1028n/a hashtable_hash_pointer_t,
1029n/a hashtable_compare_pointer_t);
1030n/a }
1031n/a else {
1032n/a tracemalloc_traces = hashtable_new(sizeof(uintptr_t),
1033n/a sizeof(trace_t),
1034n/a _Py_hashtable_hash_ptr,
1035n/a _Py_hashtable_compare_direct);
1036n/a }
1037n/a
1038n/a if (tracemalloc_filenames == NULL || tracemalloc_tracebacks == NULL
1039n/a || tracemalloc_traces == NULL) {
1040n/a PyErr_NoMemory();
1041n/a return -1;
1042n/a }
1043n/a
1044n/a unknown_filename = PyUnicode_FromString("<unknown>");
1045n/a if (unknown_filename == NULL)
1046n/a return -1;
1047n/a PyUnicode_InternInPlace(&unknown_filename);
1048n/a
1049n/a tracemalloc_empty_traceback.nframe = 1;
1050n/a /* borrowed reference */
1051n/a tracemalloc_empty_traceback.frames[0].filename = unknown_filename;
1052n/a tracemalloc_empty_traceback.frames[0].lineno = 0;
1053n/a tracemalloc_empty_traceback.hash = traceback_hash(&tracemalloc_empty_traceback);
1054n/a
1055n/a tracemalloc_config.initialized = TRACEMALLOC_INITIALIZED;
1056n/a return 0;
1057n/a}
1058n/a
1059n/a
1060n/astatic void
1061n/atracemalloc_deinit(void)
1062n/a{
1063n/a if (tracemalloc_config.initialized != TRACEMALLOC_INITIALIZED)
1064n/a return;
1065n/a tracemalloc_config.initialized = TRACEMALLOC_FINALIZED;
1066n/a
1067n/a tracemalloc_stop();
1068n/a
1069n/a /* destroy hash tables */
1070n/a _Py_hashtable_destroy(tracemalloc_tracebacks);
1071n/a _Py_hashtable_destroy(tracemalloc_filenames);
1072n/a _Py_hashtable_destroy(tracemalloc_traces);
1073n/a
1074n/a#if defined(WITH_THREAD) && defined(TRACE_RAW_MALLOC)
1075n/a if (tables_lock != NULL) {
1076n/a PyThread_free_lock(tables_lock);
1077n/a tables_lock = NULL;
1078n/a }
1079n/a#endif
1080n/a
1081n/a#ifdef REENTRANT_THREADLOCAL
1082n/a PyThread_delete_key(tracemalloc_reentrant_key);
1083n/a tracemalloc_reentrant_key = -1;
1084n/a#endif
1085n/a
1086n/a Py_XDECREF(unknown_filename);
1087n/a}
1088n/a
1089n/a
1090n/astatic int
1091n/atracemalloc_start(int max_nframe)
1092n/a{
1093n/a PyMemAllocatorEx alloc;
1094n/a size_t size;
1095n/a
1096n/a if (tracemalloc_init() < 0)
1097n/a return -1;
1098n/a
1099n/a if (tracemalloc_config.tracing) {
1100n/a /* hook already installed: do nothing */
1101n/a return 0;
1102n/a }
1103n/a
1104n/a assert(1 <= max_nframe && max_nframe <= MAX_NFRAME);
1105n/a tracemalloc_config.max_nframe = max_nframe;
1106n/a
1107n/a /* allocate a buffer to store a new traceback */
1108n/a size = TRACEBACK_SIZE(max_nframe);
1109n/a assert(tracemalloc_traceback == NULL);
1110n/a tracemalloc_traceback = raw_malloc(size);
1111n/a if (tracemalloc_traceback == NULL) {
1112n/a PyErr_NoMemory();
1113n/a return -1;
1114n/a }
1115n/a
1116n/a#ifdef TRACE_RAW_MALLOC
1117n/a alloc.malloc = tracemalloc_raw_malloc;
1118n/a alloc.calloc = tracemalloc_raw_calloc;
1119n/a alloc.realloc = tracemalloc_raw_realloc;
1120n/a alloc.free = tracemalloc_free;
1121n/a
1122n/a alloc.ctx = &allocators.raw;
1123n/a PyMem_GetAllocator(PYMEM_DOMAIN_RAW, &allocators.raw);
1124n/a PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &alloc);
1125n/a#endif
1126n/a
1127n/a alloc.malloc = tracemalloc_malloc_gil;
1128n/a alloc.calloc = tracemalloc_calloc_gil;
1129n/a alloc.realloc = tracemalloc_realloc_gil;
1130n/a alloc.free = tracemalloc_free;
1131n/a
1132n/a alloc.ctx = &allocators.mem;
1133n/a PyMem_GetAllocator(PYMEM_DOMAIN_MEM, &allocators.mem);
1134n/a PyMem_SetAllocator(PYMEM_DOMAIN_MEM, &alloc);
1135n/a
1136n/a alloc.ctx = &allocators.obj;
1137n/a PyMem_GetAllocator(PYMEM_DOMAIN_OBJ, &allocators.obj);
1138n/a PyMem_SetAllocator(PYMEM_DOMAIN_OBJ, &alloc);
1139n/a
1140n/a /* everything is ready: start tracing Python memory allocations */
1141n/a tracemalloc_config.tracing = 1;
1142n/a
1143n/a return 0;
1144n/a}
1145n/a
1146n/a
1147n/astatic void
1148n/atracemalloc_stop(void)
1149n/a{
1150n/a if (!tracemalloc_config.tracing)
1151n/a return;
1152n/a
1153n/a /* stop tracing Python memory allocations */
1154n/a tracemalloc_config.tracing = 0;
1155n/a
1156n/a /* unregister the hook on memory allocators */
1157n/a#ifdef TRACE_RAW_MALLOC
1158n/a PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &allocators.raw);
1159n/a#endif
1160n/a PyMem_SetAllocator(PYMEM_DOMAIN_MEM, &allocators.mem);
1161n/a PyMem_SetAllocator(PYMEM_DOMAIN_OBJ, &allocators.obj);
1162n/a
1163n/a tracemalloc_clear_traces();
1164n/a
1165n/a /* release memory */
1166n/a raw_free(tracemalloc_traceback);
1167n/a tracemalloc_traceback = NULL;
1168n/a}
1169n/a
1170n/a
1171n/a
1172n/a/*[clinic input]
1173n/a_tracemalloc.is_tracing
1174n/a
1175n/aReturn True if the tracemalloc module is tracing Python memory allocations.
1176n/a[clinic start generated code]*/
1177n/a
1178n/astatic PyObject *
1179n/a_tracemalloc_is_tracing_impl(PyObject *module)
1180n/a/*[clinic end generated code: output=2d763b42601cd3ef input=af104b0a00192f63]*/
1181n/a{
1182n/a return PyBool_FromLong(tracemalloc_config.tracing);
1183n/a}
1184n/a
1185n/a
1186n/a/*[clinic input]
1187n/a_tracemalloc.clear_traces
1188n/a
1189n/aClear traces of memory blocks allocated by Python.
1190n/a[clinic start generated code]*/
1191n/a
1192n/astatic PyObject *
1193n/a_tracemalloc_clear_traces_impl(PyObject *module)
1194n/a/*[clinic end generated code: output=a86080ee41b84197 input=0dab5b6c785183a5]*/
1195n/a{
1196n/a if (!tracemalloc_config.tracing)
1197n/a Py_RETURN_NONE;
1198n/a
1199n/a set_reentrant(1);
1200n/a tracemalloc_clear_traces();
1201n/a set_reentrant(0);
1202n/a
1203n/a Py_RETURN_NONE;
1204n/a}
1205n/a
1206n/a
1207n/astatic PyObject*
1208n/aframe_to_pyobject(frame_t *frame)
1209n/a{
1210n/a PyObject *frame_obj, *lineno_obj;
1211n/a
1212n/a frame_obj = PyTuple_New(2);
1213n/a if (frame_obj == NULL)
1214n/a return NULL;
1215n/a
1216n/a Py_INCREF(frame->filename);
1217n/a PyTuple_SET_ITEM(frame_obj, 0, frame->filename);
1218n/a
1219n/a lineno_obj = PyLong_FromUnsignedLong(frame->lineno);
1220n/a if (lineno_obj == NULL) {
1221n/a Py_DECREF(frame_obj);
1222n/a return NULL;
1223n/a }
1224n/a PyTuple_SET_ITEM(frame_obj, 1, lineno_obj);
1225n/a
1226n/a return frame_obj;
1227n/a}
1228n/a
1229n/a
1230n/astatic PyObject*
1231n/atraceback_to_pyobject(traceback_t *traceback, _Py_hashtable_t *intern_table)
1232n/a{
1233n/a int i;
1234n/a PyObject *frames, *frame;
1235n/a
1236n/a if (intern_table != NULL) {
1237n/a if (_Py_HASHTABLE_GET(intern_table, traceback, frames)) {
1238n/a Py_INCREF(frames);
1239n/a return frames;
1240n/a }
1241n/a }
1242n/a
1243n/a frames = PyTuple_New(traceback->nframe);
1244n/a if (frames == NULL)
1245n/a return NULL;
1246n/a
1247n/a for (i=0; i < traceback->nframe; i++) {
1248n/a frame = frame_to_pyobject(&traceback->frames[i]);
1249n/a if (frame == NULL) {
1250n/a Py_DECREF(frames);
1251n/a return NULL;
1252n/a }
1253n/a PyTuple_SET_ITEM(frames, i, frame);
1254n/a }
1255n/a
1256n/a if (intern_table != NULL) {
1257n/a if (_Py_HASHTABLE_SET(intern_table, traceback, frames) < 0) {
1258n/a Py_DECREF(frames);
1259n/a PyErr_NoMemory();
1260n/a return NULL;
1261n/a }
1262n/a /* intern_table keeps a new reference to frames */
1263n/a Py_INCREF(frames);
1264n/a }
1265n/a return frames;
1266n/a}
1267n/a
1268n/a
1269n/astatic PyObject*
1270n/atrace_to_pyobject(_PyTraceMalloc_domain_t domain, trace_t *trace,
1271n/a _Py_hashtable_t *intern_tracebacks)
1272n/a{
1273n/a PyObject *trace_obj = NULL;
1274n/a PyObject *obj;
1275n/a
1276n/a trace_obj = PyTuple_New(3);
1277n/a if (trace_obj == NULL)
1278n/a return NULL;
1279n/a
1280n/a obj = PyLong_FromSize_t(domain);
1281n/a if (obj == NULL) {
1282n/a Py_DECREF(trace_obj);
1283n/a return NULL;
1284n/a }
1285n/a PyTuple_SET_ITEM(trace_obj, 0, obj);
1286n/a
1287n/a obj = PyLong_FromSize_t(trace->size);
1288n/a if (obj == NULL) {
1289n/a Py_DECREF(trace_obj);
1290n/a return NULL;
1291n/a }
1292n/a PyTuple_SET_ITEM(trace_obj, 1, obj);
1293n/a
1294n/a obj = traceback_to_pyobject(trace->traceback, intern_tracebacks);
1295n/a if (obj == NULL) {
1296n/a Py_DECREF(trace_obj);
1297n/a return NULL;
1298n/a }
1299n/a PyTuple_SET_ITEM(trace_obj, 2, obj);
1300n/a
1301n/a return trace_obj;
1302n/a}
1303n/a
1304n/a
1305n/atypedef struct {
1306n/a _Py_hashtable_t *traces;
1307n/a _Py_hashtable_t *tracebacks;
1308n/a PyObject *list;
1309n/a} get_traces_t;
1310n/a
1311n/astatic int
1312n/atracemalloc_get_traces_fill(_Py_hashtable_t *traces, _Py_hashtable_entry_t *entry,
1313n/a void *user_data)
1314n/a{
1315n/a get_traces_t *get_traces = user_data;
1316n/a _PyTraceMalloc_domain_t domain;
1317n/a trace_t trace;
1318n/a PyObject *tracemalloc_obj;
1319n/a int res;
1320n/a
1321n/a if (tracemalloc_config.use_domain) {
1322n/a pointer_t key;
1323n/a _Py_HASHTABLE_ENTRY_READ_KEY(traces, entry, key);
1324n/a domain = key.domain;
1325n/a }
1326n/a else {
1327n/a domain = DEFAULT_DOMAIN;
1328n/a }
1329n/a _Py_HASHTABLE_ENTRY_READ_DATA(traces, entry, trace);
1330n/a
1331n/a tracemalloc_obj = trace_to_pyobject(domain, &trace, get_traces->tracebacks);
1332n/a if (tracemalloc_obj == NULL)
1333n/a return 1;
1334n/a
1335n/a res = PyList_Append(get_traces->list, tracemalloc_obj);
1336n/a Py_DECREF(tracemalloc_obj);
1337n/a if (res < 0)
1338n/a return 1;
1339n/a
1340n/a return 0;
1341n/a}
1342n/a
1343n/a
1344n/astatic int
1345n/atracemalloc_pyobject_decref_cb(_Py_hashtable_t *tracebacks,
1346n/a _Py_hashtable_entry_t *entry,
1347n/a void *user_data)
1348n/a{
1349n/a PyObject *obj;
1350n/a _Py_HASHTABLE_ENTRY_READ_DATA(tracebacks, entry, obj);
1351n/a Py_DECREF(obj);
1352n/a return 0;
1353n/a}
1354n/a
1355n/a
1356n/a
1357n/a/*[clinic input]
1358n/a_tracemalloc._get_traces
1359n/a
1360n/aGet traces of all memory blocks allocated by Python.
1361n/a
1362n/aReturn a list of (size: int, traceback: tuple) tuples.
1363n/atraceback is a tuple of (filename: str, lineno: int) tuples.
1364n/a
1365n/aReturn an empty list if the tracemalloc module is disabled.
1366n/a[clinic start generated code]*/
1367n/a
1368n/astatic PyObject *
1369n/a_tracemalloc__get_traces_impl(PyObject *module)
1370n/a/*[clinic end generated code: output=e9929876ced4b5cc input=6c7d2230b24255aa]*/
1371n/a{
1372n/a get_traces_t get_traces;
1373n/a int err;
1374n/a
1375n/a get_traces.traces = NULL;
1376n/a get_traces.tracebacks = NULL;
1377n/a get_traces.list = PyList_New(0);
1378n/a if (get_traces.list == NULL)
1379n/a goto error;
1380n/a
1381n/a if (!tracemalloc_config.tracing)
1382n/a return get_traces.list;
1383n/a
1384n/a /* the traceback hash table is used temporarily to intern traceback tuple
1385n/a of (filename, lineno) tuples */
1386n/a get_traces.tracebacks = hashtable_new(sizeof(traceback_t *),
1387n/a sizeof(PyObject *),
1388n/a _Py_hashtable_hash_ptr,
1389n/a _Py_hashtable_compare_direct);
1390n/a if (get_traces.tracebacks == NULL) {
1391n/a PyErr_NoMemory();
1392n/a goto error;
1393n/a }
1394n/a
1395n/a TABLES_LOCK();
1396n/a get_traces.traces = _Py_hashtable_copy(tracemalloc_traces);
1397n/a TABLES_UNLOCK();
1398n/a
1399n/a if (get_traces.traces == NULL) {
1400n/a PyErr_NoMemory();
1401n/a goto error;
1402n/a }
1403n/a
1404n/a set_reentrant(1);
1405n/a err = _Py_hashtable_foreach(get_traces.traces,
1406n/a tracemalloc_get_traces_fill, &get_traces);
1407n/a set_reentrant(0);
1408n/a if (err)
1409n/a goto error;
1410n/a
1411n/a goto finally;
1412n/a
1413n/aerror:
1414n/a Py_CLEAR(get_traces.list);
1415n/a
1416n/afinally:
1417n/a if (get_traces.tracebacks != NULL) {
1418n/a _Py_hashtable_foreach(get_traces.tracebacks,
1419n/a tracemalloc_pyobject_decref_cb, NULL);
1420n/a _Py_hashtable_destroy(get_traces.tracebacks);
1421n/a }
1422n/a if (get_traces.traces != NULL) {
1423n/a _Py_hashtable_destroy(get_traces.traces);
1424n/a }
1425n/a
1426n/a return get_traces.list;
1427n/a}
1428n/a
1429n/a
1430n/astatic traceback_t*
1431n/atracemalloc_get_traceback(_PyTraceMalloc_domain_t domain, uintptr_t ptr)
1432n/a{
1433n/a trace_t trace;
1434n/a int found;
1435n/a
1436n/a if (!tracemalloc_config.tracing)
1437n/a return NULL;
1438n/a
1439n/a TABLES_LOCK();
1440n/a if (tracemalloc_config.use_domain) {
1441n/a pointer_t key = {ptr, domain};
1442n/a found = _Py_HASHTABLE_GET(tracemalloc_traces, key, trace);
1443n/a }
1444n/a else {
1445n/a found = _Py_HASHTABLE_GET(tracemalloc_traces, ptr, trace);
1446n/a }
1447n/a TABLES_UNLOCK();
1448n/a
1449n/a if (!found)
1450n/a return NULL;
1451n/a
1452n/a return trace.traceback;
1453n/a}
1454n/a
1455n/a
1456n/a
1457n/a/*[clinic input]
1458n/a_tracemalloc._get_object_traceback
1459n/a
1460n/a obj: object
1461n/a /
1462n/a
1463n/aGet the traceback where the Python object obj was allocated.
1464n/a
1465n/aReturn a tuple of (filename: str, lineno: int) tuples.
1466n/aReturn None if the tracemalloc module is disabled or did not
1467n/atrace the allocation of the object.
1468n/a[clinic start generated code]*/
1469n/a
1470n/astatic PyObject *
1471n/a_tracemalloc__get_object_traceback(PyObject *module, PyObject *obj)
1472n/a/*[clinic end generated code: output=41ee0553a658b0aa input=29495f1b21c53212]*/
1473n/a{
1474n/a PyTypeObject *type;
1475n/a void *ptr;
1476n/a traceback_t *traceback;
1477n/a
1478n/a type = Py_TYPE(obj);
1479n/a if (PyType_IS_GC(type))
1480n/a ptr = (void *)((char *)obj - sizeof(PyGC_Head));
1481n/a else
1482n/a ptr = (void *)obj;
1483n/a
1484n/a traceback = tracemalloc_get_traceback(DEFAULT_DOMAIN, (uintptr_t)ptr);
1485n/a if (traceback == NULL)
1486n/a Py_RETURN_NONE;
1487n/a
1488n/a return traceback_to_pyobject(traceback, NULL);
1489n/a}
1490n/a
1491n/a
1492n/a#define PUTS(fd, str) _Py_write_noraise(fd, str, (int)strlen(str))
1493n/a
1494n/astatic void
1495n/a_PyMem_DumpFrame(int fd, frame_t * frame)
1496n/a{
1497n/a PUTS(fd, " File \"");
1498n/a _Py_DumpASCII(fd, frame->filename);
1499n/a PUTS(fd, "\", line ");
1500n/a _Py_DumpDecimal(fd, frame->lineno);
1501n/a PUTS(fd, "\n");
1502n/a}
1503n/a
1504n/a/* Dump the traceback where a memory block was allocated into file descriptor
1505n/a fd. The function may block on TABLES_LOCK() but it is unlikely. */
1506n/avoid
1507n/a_PyMem_DumpTraceback(int fd, const void *ptr)
1508n/a{
1509n/a traceback_t *traceback;
1510n/a int i;
1511n/a
1512n/a traceback = tracemalloc_get_traceback(DEFAULT_DOMAIN, (uintptr_t)ptr);
1513n/a if (traceback == NULL)
1514n/a return;
1515n/a
1516n/a PUTS(fd, "Memory block allocated at (most recent call first):\n");
1517n/a for (i=0; i < traceback->nframe; i++) {
1518n/a _PyMem_DumpFrame(fd, &traceback->frames[i]);
1519n/a }
1520n/a PUTS(fd, "\n");
1521n/a}
1522n/a
1523n/a#undef PUTS
1524n/a
1525n/a
1526n/a
1527n/a/*[clinic input]
1528n/a_tracemalloc.start
1529n/a
1530n/a nframe: Py_ssize_t = 1
1531n/a /
1532n/a
1533n/aStart tracing Python memory allocations.
1534n/a
1535n/aAlso set the maximum number of frames stored in the traceback of a
1536n/atrace to nframe.
1537n/a[clinic start generated code]*/
1538n/a
1539n/astatic PyObject *
1540n/a_tracemalloc_start_impl(PyObject *module, Py_ssize_t nframe)
1541n/a/*[clinic end generated code: output=0f558d2079511553 input=997841629cc441cb]*/
1542n/a{
1543n/a int nframe_int;
1544n/a
1545n/a if (nframe < 1 || nframe > MAX_NFRAME) {
1546n/a PyErr_Format(PyExc_ValueError,
1547n/a "the number of frames must be in range [1; %i]",
1548n/a (int)MAX_NFRAME);
1549n/a return NULL;
1550n/a }
1551n/a nframe_int = Py_SAFE_DOWNCAST(nframe, Py_ssize_t, int);
1552n/a
1553n/a if (tracemalloc_start(nframe_int) < 0)
1554n/a return NULL;
1555n/a
1556n/a Py_RETURN_NONE;
1557n/a}
1558n/a
1559n/a
1560n/a/*[clinic input]
1561n/a_tracemalloc.stop
1562n/a
1563n/aStop tracing Python memory allocations.
1564n/a
1565n/aAlso clear traces of memory blocks allocated by Python.
1566n/a[clinic start generated code]*/
1567n/a
1568n/astatic PyObject *
1569n/a_tracemalloc_stop_impl(PyObject *module)
1570n/a/*[clinic end generated code: output=c3c42ae03e3955cd input=7478f075e51dae18]*/
1571n/a{
1572n/a tracemalloc_stop();
1573n/a Py_RETURN_NONE;
1574n/a}
1575n/a
1576n/a
1577n/a/*[clinic input]
1578n/a_tracemalloc.get_traceback_limit
1579n/a
1580n/aGet the maximum number of frames stored in the traceback of a trace.
1581n/a
1582n/aBy default, a trace of an allocated memory block only stores
1583n/athe most recent frame: the limit is 1.
1584n/a[clinic start generated code]*/
1585n/a
1586n/astatic PyObject *
1587n/a_tracemalloc_get_traceback_limit_impl(PyObject *module)
1588n/a/*[clinic end generated code: output=d556d9306ba95567 input=da3cd977fc68ae3b]*/
1589n/a{
1590n/a return PyLong_FromLong(tracemalloc_config.max_nframe);
1591n/a}
1592n/a
1593n/a
1594n/a
1595n/a/*[clinic input]
1596n/a_tracemalloc.get_tracemalloc_memory
1597n/a
1598n/aGet the memory usage in bytes of the tracemalloc module.
1599n/a
1600n/aThis memory is used internally to trace memory allocations.
1601n/a[clinic start generated code]*/
1602n/a
1603n/astatic PyObject *
1604n/a_tracemalloc_get_tracemalloc_memory_impl(PyObject *module)
1605n/a/*[clinic end generated code: output=e3f14e280a55f5aa input=5d919c0f4d5132ad]*/
1606n/a{
1607n/a size_t size;
1608n/a
1609n/a size = _Py_hashtable_size(tracemalloc_tracebacks);
1610n/a size += _Py_hashtable_size(tracemalloc_filenames);
1611n/a
1612n/a TABLES_LOCK();
1613n/a size += _Py_hashtable_size(tracemalloc_traces);
1614n/a TABLES_UNLOCK();
1615n/a
1616n/a return PyLong_FromSize_t(size);
1617n/a}
1618n/a
1619n/a
1620n/a
1621n/a/*[clinic input]
1622n/a_tracemalloc.get_traced_memory
1623n/a
1624n/aGet the current size and peak size of memory blocks traced by tracemalloc.
1625n/a
1626n/aReturns a tuple: (current: int, peak: int).
1627n/a[clinic start generated code]*/
1628n/a
1629n/astatic PyObject *
1630n/a_tracemalloc_get_traced_memory_impl(PyObject *module)
1631n/a/*[clinic end generated code: output=5b167189adb9e782 input=61ddb5478400ff66]*/
1632n/a{
1633n/a Py_ssize_t size, peak_size;
1634n/a
1635n/a if (!tracemalloc_config.tracing)
1636n/a return Py_BuildValue("ii", 0, 0);
1637n/a
1638n/a TABLES_LOCK();
1639n/a size = tracemalloc_traced_memory;
1640n/a peak_size = tracemalloc_peak_traced_memory;
1641n/a TABLES_UNLOCK();
1642n/a
1643n/a return Py_BuildValue("nn", size, peak_size);
1644n/a}
1645n/a
1646n/a
1647n/astatic PyMethodDef module_methods[] = {
1648n/a _TRACEMALLOC_IS_TRACING_METHODDEF
1649n/a _TRACEMALLOC_CLEAR_TRACES_METHODDEF
1650n/a _TRACEMALLOC__GET_TRACES_METHODDEF
1651n/a _TRACEMALLOC__GET_OBJECT_TRACEBACK_METHODDEF
1652n/a _TRACEMALLOC_START_METHODDEF
1653n/a _TRACEMALLOC_STOP_METHODDEF
1654n/a _TRACEMALLOC_GET_TRACEBACK_LIMIT_METHODDEF
1655n/a _TRACEMALLOC_GET_TRACEMALLOC_MEMORY_METHODDEF
1656n/a _TRACEMALLOC_GET_TRACED_MEMORY_METHODDEF
1657n/a /* sentinel */
1658n/a {NULL, NULL}
1659n/a};
1660n/a
1661n/aPyDoc_STRVAR(module_doc,
1662n/a"Debug module to trace memory blocks allocated by Python.");
1663n/a
1664n/astatic struct PyModuleDef module_def = {
1665n/a PyModuleDef_HEAD_INIT,
1666n/a "_tracemalloc",
1667n/a module_doc,
1668n/a 0, /* non-negative size to be able to unload the module */
1669n/a module_methods,
1670n/a NULL,
1671n/a};
1672n/a
1673n/aPyMODINIT_FUNC
1674n/aPyInit__tracemalloc(void)
1675n/a{
1676n/a PyObject *m;
1677n/a m = PyModule_Create(&module_def);
1678n/a if (m == NULL)
1679n/a return NULL;
1680n/a
1681n/a if (tracemalloc_init() < 0)
1682n/a return NULL;
1683n/a
1684n/a return m;
1685n/a}
1686n/a
1687n/a
1688n/astatic int
1689n/aparse_sys_xoptions(PyObject *value)
1690n/a{
1691n/a PyObject *valuelong;
1692n/a long nframe;
1693n/a
1694n/a if (value == Py_True)
1695n/a return 1;
1696n/a
1697n/a assert(PyUnicode_Check(value));
1698n/a if (PyUnicode_GetLength(value) == 0)
1699n/a return -1;
1700n/a
1701n/a valuelong = PyLong_FromUnicodeObject(value, 10);
1702n/a if (valuelong == NULL)
1703n/a return -1;
1704n/a
1705n/a nframe = PyLong_AsLong(valuelong);
1706n/a Py_DECREF(valuelong);
1707n/a if (nframe == -1 && PyErr_Occurred())
1708n/a return -1;
1709n/a
1710n/a if (nframe < 1 || nframe > MAX_NFRAME)
1711n/a return -1;
1712n/a
1713n/a return Py_SAFE_DOWNCAST(nframe, long, int);
1714n/a}
1715n/a
1716n/a
1717n/aint
1718n/a_PyTraceMalloc_Init(void)
1719n/a{
1720n/a char *p;
1721n/a int nframe;
1722n/a
1723n/a#ifdef WITH_THREAD
1724n/a assert(PyGILState_Check());
1725n/a#endif
1726n/a
1727n/a if ((p = Py_GETENV("PYTHONTRACEMALLOC")) && *p != '\0') {
1728n/a char *endptr = p;
1729n/a long value;
1730n/a
1731n/a errno = 0;
1732n/a value = strtol(p, &endptr, 10);
1733n/a if (*endptr != '\0'
1734n/a || value < 1
1735n/a || value > MAX_NFRAME
1736n/a || errno == ERANGE)
1737n/a {
1738n/a Py_FatalError("PYTHONTRACEMALLOC: invalid number of frames");
1739n/a return -1;
1740n/a }
1741n/a
1742n/a nframe = (int)value;
1743n/a }
1744n/a else {
1745n/a PyObject *xoptions, *key, *value;
1746n/a
1747n/a xoptions = PySys_GetXOptions();
1748n/a if (xoptions == NULL)
1749n/a return -1;
1750n/a
1751n/a key = PyUnicode_FromString("tracemalloc");
1752n/a if (key == NULL)
1753n/a return -1;
1754n/a
1755n/a value = PyDict_GetItemWithError(xoptions, key);
1756n/a Py_DECREF(key);
1757n/a if (value == NULL) {
1758n/a if (PyErr_Occurred())
1759n/a return -1;
1760n/a
1761n/a /* -X tracemalloc is not used */
1762n/a return 0;
1763n/a }
1764n/a
1765n/a nframe = parse_sys_xoptions(value);
1766n/a Py_DECREF(value);
1767n/a if (nframe < 0) {
1768n/a Py_FatalError("-X tracemalloc=NFRAME: invalid number of frames");
1769n/a }
1770n/a }
1771n/a
1772n/a return tracemalloc_start(nframe);
1773n/a}
1774n/a
1775n/a
1776n/avoid
1777n/a_PyTraceMalloc_Fini(void)
1778n/a{
1779n/a#ifdef WITH_THREAD
1780n/a assert(PyGILState_Check());
1781n/a#endif
1782n/a tracemalloc_deinit();
1783n/a}
1784n/a
1785n/aint
1786n/a_PyTraceMalloc_Track(_PyTraceMalloc_domain_t domain, uintptr_t ptr,
1787n/a size_t size)
1788n/a{
1789n/a int res;
1790n/a#ifdef WITH_THREAD
1791n/a PyGILState_STATE gil_state;
1792n/a#endif
1793n/a
1794n/a if (!tracemalloc_config.tracing) {
1795n/a /* tracemalloc is not tracing: do nothing */
1796n/a return -2;
1797n/a }
1798n/a
1799n/a#ifdef WITH_THREAD
1800n/a gil_state = PyGILState_Ensure();
1801n/a#endif
1802n/a
1803n/a TABLES_LOCK();
1804n/a res = tracemalloc_add_trace(domain, ptr, size);
1805n/a TABLES_UNLOCK();
1806n/a
1807n/a#ifdef WITH_THREAD
1808n/a PyGILState_Release(gil_state);
1809n/a#endif
1810n/a return res;
1811n/a}
1812n/a
1813n/a
1814n/aint
1815n/a_PyTraceMalloc_Untrack(_PyTraceMalloc_domain_t domain, uintptr_t ptr)
1816n/a{
1817n/a if (!tracemalloc_config.tracing) {
1818n/a /* tracemalloc is not tracing: do nothing */
1819n/a return -2;
1820n/a }
1821n/a
1822n/a TABLES_LOCK();
1823n/a tracemalloc_remove_trace(domain, ptr);
1824n/a TABLES_UNLOCK();
1825n/a
1826n/a return 0;
1827n/a}
1828n/a
1829n/a
1830n/aPyObject*
1831n/a_PyTraceMalloc_GetTraceback(_PyTraceMalloc_domain_t domain, uintptr_t ptr)
1832n/a{
1833n/a traceback_t *traceback;
1834n/a
1835n/a traceback = tracemalloc_get_traceback(domain, ptr);
1836n/a if (traceback == NULL)
1837n/a Py_RETURN_NONE;
1838n/a
1839n/a return traceback_to_pyobject(traceback, NULL);
1840n/a}