blob: ea7e0127366ab0a04313b72dff38dacade636c52 [file] [log] [blame]
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001#include "Python.h"
Victor Stinnere560f902020-04-14 18:30:41 +02002#include "pycore_gc.h" // PyGC_Head
3#include "pycore_pymem.h" // _Py_tracemalloc_config
Victor Stinnered488662019-05-20 00:14:57 +02004#include "pycore_traceback.h"
Victor Stinnered3b0bc2013-11-23 12:27:24 +01005#include "hashtable.h"
Victor Stinner70364772020-04-29 03:28:46 +02006#include "frameobject.h" // PyFrame_GetBack()
Victor Stinnered3b0bc2013-11-23 12:27:24 +01007
Serhiy Storchakab451f912017-02-04 12:18:38 +02008#include "clinic/_tracemalloc.c.h"
9/*[clinic input]
10module _tracemalloc
11[clinic start generated code]*/
12/*[clinic end generated code: output=da39a3ee5e6b4b0d input=708a98302fc46e5f]*/
13
Victor Stinnered3b0bc2013-11-23 12:27:24 +010014/* Trace memory blocks allocated by PyMem_RawMalloc() */
15#define TRACE_RAW_MALLOC
16
17/* Forward declaration */
18static void tracemalloc_stop(void);
Victor Stinnered3b0bc2013-11-23 12:27:24 +010019static void* raw_malloc(size_t size);
20static void raw_free(void *ptr);
21
22#ifdef Py_DEBUG
23# define TRACE_DEBUG
24#endif
25
Victor Stinnered3b0bc2013-11-23 12:27:24 +010026/* Protected by the GIL */
27static struct {
Victor Stinnerd8f0d922014-06-02 21:57:10 +020028 PyMemAllocatorEx mem;
29 PyMemAllocatorEx raw;
30 PyMemAllocatorEx obj;
Victor Stinnered3b0bc2013-11-23 12:27:24 +010031} allocators;
32
Victor Stinnered3b0bc2013-11-23 12:27:24 +010033
Antoine Pitroua6a4dc82017-09-07 18:56:24 +020034#if defined(TRACE_RAW_MALLOC)
Victor Stinnered3b0bc2013-11-23 12:27:24 +010035/* This lock is needed because tracemalloc_free() is called without
36 the GIL held from PyMem_RawFree(). It cannot acquire the lock because it
Joannah Nanjekye2bc43cd2019-09-05 13:06:49 -030037 would introduce a deadlock in _PyThreadState_DeleteCurrent(). */
Victor Stinnered3b0bc2013-11-23 12:27:24 +010038static PyThread_type_lock tables_lock;
39# define TABLES_LOCK() PyThread_acquire_lock(tables_lock, 1)
40# define TABLES_UNLOCK() PyThread_release_lock(tables_lock)
41#else
42 /* variables are protected by the GIL */
43# define TABLES_LOCK()
44# define TABLES_UNLOCK()
45#endif
46
Victor Stinnere492ae52016-03-22 12:58:23 +010047
48#define DEFAULT_DOMAIN 0
49
Victor Stinnere492ae52016-03-22 12:58:23 +010050/* Pack the frame_t structure to reduce the memory footprint. */
51typedef struct
52#ifdef __GNUC__
53__attribute__((packed))
54#endif
55{
Benjamin Petersonca470632016-09-06 13:47:26 -070056 uintptr_t ptr;
Victor Stinner5ea4c062017-06-20 17:46:36 +020057 unsigned int domain;
Victor Stinnere492ae52016-03-22 12:58:23 +010058} pointer_t;
59
Victor Stinnered3b0bc2013-11-23 12:27:24 +010060/* Pack the frame_t structure to reduce the memory footprint on 64-bit
Victor Stinnere492ae52016-03-22 12:58:23 +010061 architectures: 12 bytes instead of 16. */
Victor Stinnered3b0bc2013-11-23 12:27:24 +010062typedef struct
63#ifdef __GNUC__
64__attribute__((packed))
Victor Stinnerdd382ef2014-02-01 03:43:58 +010065#elif defined(_MSC_VER)
Segev Finer39243772017-07-25 11:47:43 +030066#pragma pack(push, 4)
Victor Stinnered3b0bc2013-11-23 12:27:24 +010067#endif
68{
Victor Stinner7105e9f2016-03-15 14:28:04 +010069 /* filename cannot be NULL: "<unknown>" is used if the Python frame
70 filename is NULL */
Victor Stinnered3b0bc2013-11-23 12:27:24 +010071 PyObject *filename;
Victor Stinner95283342016-03-15 21:57:02 +010072 unsigned int lineno;
Victor Stinnered3b0bc2013-11-23 12:27:24 +010073} frame_t;
Segev Finer39243772017-07-25 11:47:43 +030074#ifdef _MSC_VER
75#pragma pack(pop)
76#endif
Victor Stinnered3b0bc2013-11-23 12:27:24 +010077
Victor Stinnere492ae52016-03-22 12:58:23 +010078
Victor Stinnered3b0bc2013-11-23 12:27:24 +010079typedef struct {
80 Py_uhash_t hash;
Julien Danjou8d59eb12019-10-15 14:00:16 +020081 /* Number of frames stored */
82 uint16_t nframe;
83 /* Total number of frames the traceback had */
84 uint16_t total_nframe;
Victor Stinnered3b0bc2013-11-23 12:27:24 +010085 frame_t frames[1];
86} traceback_t;
87
88#define TRACEBACK_SIZE(NFRAME) \
89 (sizeof(traceback_t) + sizeof(frame_t) * (NFRAME - 1))
Victor Stinnerf28ce602013-11-27 22:27:13 +010090
Julien Danjou8d59eb12019-10-15 14:00:16 +020091/* The maximum number of frames is either:
92 - The maximum number of frames we can store in `traceback_t.nframe`
93 - The maximum memory size_t we can allocate */
94static const unsigned long MAX_NFRAME = Py_MIN(UINT16_MAX, ((SIZE_MAX - sizeof(traceback_t)) / sizeof(frame_t) + 1));
Victor Stinnered3b0bc2013-11-23 12:27:24 +010095
Victor Stinnere492ae52016-03-22 12:58:23 +010096
Victor Stinnered3b0bc2013-11-23 12:27:24 +010097static PyObject *unknown_filename = NULL;
98static traceback_t tracemalloc_empty_traceback;
99
Victor Stinner7a5be142013-11-26 01:06:02 +0100100/* Trace of a memory block */
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100101typedef struct {
Victor Stinner7a5be142013-11-26 01:06:02 +0100102 /* Size of the memory block in bytes */
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100103 size_t size;
Victor Stinner7a5be142013-11-26 01:06:02 +0100104
105 /* Traceback where the memory block was allocated */
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100106 traceback_t *traceback;
107} trace_t;
108
Victor Stinnere492ae52016-03-22 12:58:23 +0100109
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100110/* Size in bytes of currently traced memory.
111 Protected by TABLES_LOCK(). */
112static size_t tracemalloc_traced_memory = 0;
113
Victor Stinner3c0481d2013-11-27 21:39:49 +0100114/* Peak size in bytes of traced memory.
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100115 Protected by TABLES_LOCK(). */
Victor Stinner3c0481d2013-11-27 21:39:49 +0100116static size_t tracemalloc_peak_traced_memory = 0;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100117
Serhiy Storchaka56a6d852014-12-01 18:28:43 +0200118/* Hash table used as a set to intern filenames:
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100119 PyObject* => PyObject*.
120 Protected by the GIL */
121static _Py_hashtable_t *tracemalloc_filenames = NULL;
122
Victor Stinnerf28ce602013-11-27 22:27:13 +0100123/* Buffer to store a new traceback in traceback_new().
124 Protected by the GIL. */
125static traceback_t *tracemalloc_traceback = NULL;
126
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100127/* Hash table used as a set to intern tracebacks:
128 traceback_t* => traceback_t*
129 Protected by the GIL */
130static _Py_hashtable_t *tracemalloc_tracebacks = NULL;
131
132/* pointer (void*) => trace (trace_t).
133 Protected by TABLES_LOCK(). */
134static _Py_hashtable_t *tracemalloc_traces = NULL;
135
Victor Stinnere492ae52016-03-22 12:58:23 +0100136
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100137#ifdef TRACE_DEBUG
138static void
139tracemalloc_error(const char *format, ...)
140{
141 va_list ap;
142 fprintf(stderr, "tracemalloc: ");
143 va_start(ap, format);
144 vfprintf(stderr, format, ap);
145 va_end(ap);
146 fprintf(stderr, "\n");
147 fflush(stderr);
148}
149#endif
150
Victor Stinnere492ae52016-03-22 12:58:23 +0100151
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200152#if defined(TRACE_RAW_MALLOC)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100153#define REENTRANT_THREADLOCAL
154
Masayuki Yamamoto731e1892017-10-06 19:41:34 +0900155static Py_tss_t tracemalloc_reentrant_key = Py_tss_NEEDS_INIT;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100156
157/* Any non-NULL pointer can be used */
158#define REENTRANT Py_True
159
160static int
161get_reentrant(void)
162{
Victor Stinner4a066472016-03-22 17:45:09 +0100163 void *ptr;
164
Masayuki Yamamoto731e1892017-10-06 19:41:34 +0900165 assert(PyThread_tss_is_created(&tracemalloc_reentrant_key));
166 ptr = PyThread_tss_get(&tracemalloc_reentrant_key);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100167 if (ptr != NULL) {
168 assert(ptr == REENTRANT);
169 return 1;
170 }
171 else
172 return 0;
173}
174
175static void
176set_reentrant(int reentrant)
177{
Victor Stinner2ead3d22013-11-26 01:08:53 +0100178 assert(reentrant == 0 || reentrant == 1);
Masayuki Yamamoto731e1892017-10-06 19:41:34 +0900179 assert(PyThread_tss_is_created(&tracemalloc_reentrant_key));
Victor Stinner4a066472016-03-22 17:45:09 +0100180
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100181 if (reentrant) {
Victor Stinner0cfc0582016-03-22 17:40:07 +0100182 assert(!get_reentrant());
Masayuki Yamamoto731e1892017-10-06 19:41:34 +0900183 PyThread_tss_set(&tracemalloc_reentrant_key, REENTRANT);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100184 }
185 else {
Victor Stinner0cfc0582016-03-22 17:40:07 +0100186 assert(get_reentrant());
Masayuki Yamamoto731e1892017-10-06 19:41:34 +0900187 PyThread_tss_set(&tracemalloc_reentrant_key, NULL);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100188 }
189}
190
191#else
192
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200193/* TRACE_RAW_MALLOC not defined: variable protected by the GIL */
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100194static int tracemalloc_reentrant = 0;
195
196static int
197get_reentrant(void)
198{
199 return tracemalloc_reentrant;
200}
201
202static void
203set_reentrant(int reentrant)
204{
Victor Stinnerd5871e62016-03-23 00:17:04 +0100205 assert(reentrant != tracemalloc_reentrant);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100206 tracemalloc_reentrant = reentrant;
207}
208#endif
209
Victor Stinnere492ae52016-03-22 12:58:23 +0100210
Victor Stinner285cf0a2016-03-21 22:00:58 +0100211static Py_uhash_t
Victor Stinner5dacbd42016-03-23 09:52:13 +0100212hashtable_hash_pyobject(_Py_hashtable_t *ht, const void *pkey)
Victor Stinner51b846c2016-03-18 21:52:22 +0100213{
Victor Stinner285cf0a2016-03-21 22:00:58 +0100214 PyObject *obj;
215
Victor Stinner5dacbd42016-03-23 09:52:13 +0100216 _Py_HASHTABLE_READ_KEY(ht, pkey, obj);
Victor Stinner285cf0a2016-03-21 22:00:58 +0100217 return PyObject_Hash(obj);
218}
219
Victor Stinnere492ae52016-03-22 12:58:23 +0100220
Victor Stinner285cf0a2016-03-21 22:00:58 +0100221static int
Victor Stinner5dacbd42016-03-23 09:52:13 +0100222hashtable_compare_unicode(_Py_hashtable_t *ht, const void *pkey,
Victor Stinner285cf0a2016-03-21 22:00:58 +0100223 const _Py_hashtable_entry_t *entry)
224{
Victor Stinnere492ae52016-03-22 12:58:23 +0100225 PyObject *key1, *key2;
Victor Stinner285cf0a2016-03-21 22:00:58 +0100226
Victor Stinner5dacbd42016-03-23 09:52:13 +0100227 _Py_HASHTABLE_READ_KEY(ht, pkey, key1);
228 _Py_HASHTABLE_ENTRY_READ_KEY(ht, entry, key2);
Victor Stinner285cf0a2016-03-21 22:00:58 +0100229
Victor Stinnere492ae52016-03-22 12:58:23 +0100230 if (key1 != NULL && key2 != NULL)
231 return (PyUnicode_Compare(key1, key2) == 0);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100232 else
Victor Stinnere492ae52016-03-22 12:58:23 +0100233 return key1 == key2;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100234}
235
Victor Stinnere492ae52016-03-22 12:58:23 +0100236
237static Py_uhash_t
Victor Stinner5dacbd42016-03-23 09:52:13 +0100238hashtable_hash_pointer_t(_Py_hashtable_t *ht, const void *pkey)
Victor Stinnere492ae52016-03-22 12:58:23 +0100239{
240 pointer_t ptr;
241 Py_uhash_t hash;
242
Victor Stinner5dacbd42016-03-23 09:52:13 +0100243 _Py_HASHTABLE_READ_KEY(ht, pkey, ptr);
Victor Stinnere492ae52016-03-22 12:58:23 +0100244
245 hash = (Py_uhash_t)_Py_HashPointer((void*)ptr.ptr);
246 hash ^= ptr.domain;
247 return hash;
248}
249
250
doko@ubuntu.combc731502016-05-18 01:06:01 +0200251static int
Victor Stinner5dacbd42016-03-23 09:52:13 +0100252hashtable_compare_pointer_t(_Py_hashtable_t *ht, const void *pkey,
Victor Stinnere492ae52016-03-22 12:58:23 +0100253 const _Py_hashtable_entry_t *entry)
254{
255 pointer_t ptr1, ptr2;
256
Victor Stinner5dacbd42016-03-23 09:52:13 +0100257 _Py_HASHTABLE_READ_KEY(ht, pkey, ptr1);
258 _Py_HASHTABLE_ENTRY_READ_KEY(ht, entry, ptr2);
Victor Stinnere492ae52016-03-22 12:58:23 +0100259
260 /* compare pointer before domain, because pointer is more likely to be
261 different */
262 return (ptr1.ptr == ptr2.ptr && ptr1.domain == ptr2.domain);
263
264}
265
266
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100267static _Py_hashtable_t *
Victor Stinner285cf0a2016-03-21 22:00:58 +0100268hashtable_new(size_t key_size, size_t data_size,
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100269 _Py_hashtable_hash_func hash_func,
270 _Py_hashtable_compare_func compare_func)
271{
Victor Stinnerc9553872016-03-22 12:13:01 +0100272 _Py_hashtable_allocator_t hashtable_alloc = {malloc, free};
Victor Stinner285cf0a2016-03-21 22:00:58 +0100273 return _Py_hashtable_new_full(key_size, data_size, 0,
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100274 hash_func, compare_func,
Victor Stinnerc9553872016-03-22 12:13:01 +0100275 &hashtable_alloc);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100276}
277
Victor Stinnere492ae52016-03-22 12:58:23 +0100278
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100279static void*
280raw_malloc(size_t size)
281{
282 return allocators.raw.malloc(allocators.raw.ctx, size);
283}
284
285static void
286raw_free(void *ptr)
287{
288 allocators.raw.free(allocators.raw.ctx, ptr);
289}
290
Victor Stinnere492ae52016-03-22 12:58:23 +0100291
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100292static Py_uhash_t
Victor Stinner5dacbd42016-03-23 09:52:13 +0100293hashtable_hash_traceback(_Py_hashtable_t *ht, const void *pkey)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100294{
Victor Stinnerb32a7ed2016-03-21 23:05:08 +0100295 traceback_t *traceback;
Victor Stinner285cf0a2016-03-21 22:00:58 +0100296
Victor Stinner5dacbd42016-03-23 09:52:13 +0100297 _Py_HASHTABLE_READ_KEY(ht, pkey, traceback);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100298 return traceback->hash;
299}
300
Victor Stinnere492ae52016-03-22 12:58:23 +0100301
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100302static int
Victor Stinner5dacbd42016-03-23 09:52:13 +0100303hashtable_compare_traceback(_Py_hashtable_t *ht, const void *pkey,
304 const _Py_hashtable_entry_t *entry)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100305{
Victor Stinner285cf0a2016-03-21 22:00:58 +0100306 traceback_t *traceback1, *traceback2;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100307 const frame_t *frame1, *frame2;
308 int i;
309
Victor Stinner5dacbd42016-03-23 09:52:13 +0100310 _Py_HASHTABLE_READ_KEY(ht, pkey, traceback1);
311 _Py_HASHTABLE_ENTRY_READ_KEY(ht, entry, traceback2);
Victor Stinner285cf0a2016-03-21 22:00:58 +0100312
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100313 if (traceback1->nframe != traceback2->nframe)
314 return 0;
315
Julien Danjou8d59eb12019-10-15 14:00:16 +0200316 if (traceback1->total_nframe != traceback2->total_nframe)
317 return 0;
318
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100319 for (i=0; i < traceback1->nframe; i++) {
320 frame1 = &traceback1->frames[i];
321 frame2 = &traceback2->frames[i];
322
323 if (frame1->lineno != frame2->lineno)
324 return 0;
325
326 if (frame1->filename != frame2->filename) {
327 assert(PyUnicode_Compare(frame1->filename, frame2->filename) != 0);
328 return 0;
329 }
330 }
331 return 1;
332}
333
Victor Stinnere492ae52016-03-22 12:58:23 +0100334
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100335static void
336tracemalloc_get_frame(PyFrameObject *pyframe, frame_t *frame)
337{
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100338 frame->filename = unknown_filename;
Victor Stinner8852ad42020-04-29 01:28:13 +0200339 int lineno = PyFrame_GetLineNumber(pyframe);
340 if (lineno < 0) {
Victor Stinner95283342016-03-15 21:57:02 +0100341 lineno = 0;
Victor Stinner8852ad42020-04-29 01:28:13 +0200342 }
Victor Stinner95283342016-03-15 21:57:02 +0100343 frame->lineno = (unsigned int)lineno;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100344
Victor Stinner8852ad42020-04-29 01:28:13 +0200345 PyCodeObject *code = PyFrame_GetCode(pyframe);
346 PyObject *filename = code->co_filename;
347 Py_DECREF(code);
348
349 if (filename == NULL) {
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100350#ifdef TRACE_DEBUG
351 tracemalloc_error("failed to get the filename of the code object");
352#endif
353 return;
354 }
355
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100356 assert(filename != NULL);
357 if (filename == NULL)
358 return;
359
360 if (!PyUnicode_Check(filename)) {
361#ifdef TRACE_DEBUG
Martin Panter6245cb32016-04-15 02:14:19 +0000362 tracemalloc_error("filename is not a unicode string");
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100363#endif
364 return;
365 }
366 if (!PyUnicode_IS_READY(filename)) {
367 /* Don't make a Unicode string ready to avoid reentrant calls
368 to tracemalloc_malloc() or tracemalloc_realloc() */
369#ifdef TRACE_DEBUG
370 tracemalloc_error("filename is not a ready unicode string");
371#endif
372 return;
373 }
374
375 /* intern the filename */
Victor Stinner8852ad42020-04-29 01:28:13 +0200376 _Py_hashtable_entry_t *entry;
Victor Stinner285cf0a2016-03-21 22:00:58 +0100377 entry = _Py_HASHTABLE_GET_ENTRY(tracemalloc_filenames, filename);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100378 if (entry != NULL) {
Victor Stinner5dacbd42016-03-23 09:52:13 +0100379 _Py_HASHTABLE_ENTRY_READ_KEY(tracemalloc_filenames, entry, filename);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100380 }
381 else {
382 /* tracemalloc_filenames is responsible to keep a reference
383 to the filename */
384 Py_INCREF(filename);
Victor Stinner285cf0a2016-03-21 22:00:58 +0100385 if (_Py_HASHTABLE_SET_NODATA(tracemalloc_filenames, filename) < 0) {
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100386 Py_DECREF(filename);
387#ifdef TRACE_DEBUG
388 tracemalloc_error("failed to intern the filename");
389#endif
390 return;
391 }
392 }
393
394 /* the tracemalloc_filenames table keeps a reference to the filename */
395 frame->filename = filename;
396}
397
Victor Stinnere492ae52016-03-22 12:58:23 +0100398
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100399static Py_uhash_t
400traceback_hash(traceback_t *traceback)
401{
402 /* code based on tuplehash() of Objects/tupleobject.c */
Victor Stinner4d8c29c2013-12-16 23:05:13 +0100403 Py_uhash_t x, y; /* Unsigned for defined overflow behavior. */
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100404 int len = traceback->nframe;
405 Py_uhash_t mult = _PyHASH_MULTIPLIER;
406 frame_t *frame;
407
408 x = 0x345678UL;
409 frame = traceback->frames;
410 while (--len >= 0) {
Victor Stinner4d8c29c2013-12-16 23:05:13 +0100411 y = (Py_uhash_t)PyObject_Hash(frame->filename);
412 y ^= (Py_uhash_t)frame->lineno;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100413 frame++;
414
415 x = (x ^ y) * mult;
416 /* the cast might truncate len; that doesn't change hash stability */
Victor Stinner4d8c29c2013-12-16 23:05:13 +0100417 mult += (Py_uhash_t)(82520UL + len + len);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100418 }
Julien Danjou8d59eb12019-10-15 14:00:16 +0200419 x ^= traceback->total_nframe;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100420 x += 97531UL;
421 return x;
422}
423
Victor Stinnere492ae52016-03-22 12:58:23 +0100424
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100425static void
426traceback_get_frames(traceback_t *traceback)
427{
Victor Stinner4386b902020-04-29 03:01:43 +0200428 PyThreadState *tstate = PyGILState_GetThisThreadState();
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100429 if (tstate == NULL) {
430#ifdef TRACE_DEBUG
431 tracemalloc_error("failed to get the current thread state");
432#endif
433 return;
434 }
435
Victor Stinner4386b902020-04-29 03:01:43 +0200436 PyFrameObject *pyframe = PyThreadState_GetFrame(tstate);
Victor Stinner70364772020-04-29 03:28:46 +0200437 for (; pyframe != NULL;) {
Julien Danjou8d59eb12019-10-15 14:00:16 +0200438 if (traceback->nframe < _Py_tracemalloc_config.max_nframe) {
439 tracemalloc_get_frame(pyframe, &traceback->frames[traceback->nframe]);
440 assert(traceback->frames[traceback->nframe].filename != NULL);
441 traceback->nframe++;
442 }
Victor Stinner70364772020-04-29 03:28:46 +0200443 if (traceback->total_nframe < UINT16_MAX) {
Julien Danjou8d59eb12019-10-15 14:00:16 +0200444 traceback->total_nframe++;
Victor Stinner70364772020-04-29 03:28:46 +0200445 }
446
447 PyFrameObject *back = PyFrame_GetBack(pyframe);
448 Py_DECREF(pyframe);
449 pyframe = back;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100450 }
451}
452
Victor Stinnere492ae52016-03-22 12:58:23 +0100453
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100454static traceback_t *
455traceback_new(void)
456{
Victor Stinnerf28ce602013-11-27 22:27:13 +0100457 traceback_t *traceback;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100458 _Py_hashtable_entry_t *entry;
459
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100460 assert(PyGILState_Check());
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100461
462 /* get frames */
Victor Stinnerf28ce602013-11-27 22:27:13 +0100463 traceback = tracemalloc_traceback;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100464 traceback->nframe = 0;
Julien Danjou8d59eb12019-10-15 14:00:16 +0200465 traceback->total_nframe = 0;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100466 traceback_get_frames(traceback);
467 if (traceback->nframe == 0)
468 return &tracemalloc_empty_traceback;
469 traceback->hash = traceback_hash(traceback);
470
471 /* intern the traceback */
Victor Stinner285cf0a2016-03-21 22:00:58 +0100472 entry = _Py_HASHTABLE_GET_ENTRY(tracemalloc_tracebacks, traceback);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100473 if (entry != NULL) {
Victor Stinner5dacbd42016-03-23 09:52:13 +0100474 _Py_HASHTABLE_ENTRY_READ_KEY(tracemalloc_tracebacks, entry, traceback);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100475 }
476 else {
477 traceback_t *copy;
478 size_t traceback_size;
479
480 traceback_size = TRACEBACK_SIZE(traceback->nframe);
481
482 copy = raw_malloc(traceback_size);
483 if (copy == NULL) {
484#ifdef TRACE_DEBUG
485 tracemalloc_error("failed to intern the traceback: malloc failed");
486#endif
487 return NULL;
488 }
489 memcpy(copy, traceback, traceback_size);
490
Victor Stinner285cf0a2016-03-21 22:00:58 +0100491 if (_Py_HASHTABLE_SET_NODATA(tracemalloc_tracebacks, copy) < 0) {
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100492 raw_free(copy);
493#ifdef TRACE_DEBUG
494 tracemalloc_error("failed to intern the traceback: putdata failed");
495#endif
496 return NULL;
497 }
498 traceback = copy;
499 }
500 return traceback;
501}
502
Victor Stinnere492ae52016-03-22 12:58:23 +0100503
Victor Stinner5e14a382016-03-23 22:03:55 +0100504static int
505tracemalloc_use_domain_cb(_Py_hashtable_t *old_traces,
506 _Py_hashtable_entry_t *entry, void *user_data)
507{
Benjamin Petersonca470632016-09-06 13:47:26 -0700508 uintptr_t ptr;
Victor Stinner5e14a382016-03-23 22:03:55 +0100509 pointer_t key;
510 _Py_hashtable_t *new_traces = (_Py_hashtable_t *)user_data;
511 const void *pdata = _Py_HASHTABLE_ENTRY_PDATA(old_traces, entry);
512
513 _Py_HASHTABLE_ENTRY_READ_KEY(old_traces, entry, ptr);
514 key.ptr = ptr;
515 key.domain = DEFAULT_DOMAIN;
516
517 return _Py_hashtable_set(new_traces,
518 sizeof(key), &key,
519 old_traces->data_size, pdata);
520}
521
522
Benjamin Petersonca470632016-09-06 13:47:26 -0700523/* Convert tracemalloc_traces from compact key (uintptr_t) to pointer_t key.
Victor Stinner5e14a382016-03-23 22:03:55 +0100524 * Return 0 on success, -1 on error. */
525static int
526tracemalloc_use_domain(void)
527{
528 _Py_hashtable_t *new_traces = NULL;
529
Victor Stinner9e00e802018-10-25 13:31:16 +0200530 assert(!_Py_tracemalloc_config.use_domain);
Victor Stinner5e14a382016-03-23 22:03:55 +0100531
532 new_traces = hashtable_new(sizeof(pointer_t),
533 sizeof(trace_t),
534 hashtable_hash_pointer_t,
535 hashtable_compare_pointer_t);
536 if (new_traces == NULL) {
537 return -1;
538 }
539
540 if (_Py_hashtable_foreach(tracemalloc_traces, tracemalloc_use_domain_cb,
541 new_traces) < 0)
542 {
543 _Py_hashtable_destroy(new_traces);
544 return -1;
545 }
546
547 _Py_hashtable_destroy(tracemalloc_traces);
548 tracemalloc_traces = new_traces;
549
Victor Stinner9e00e802018-10-25 13:31:16 +0200550 _Py_tracemalloc_config.use_domain = 1;
Victor Stinner5e14a382016-03-23 22:03:55 +0100551
552 return 0;
553}
554
555
Victor Stinnere492ae52016-03-22 12:58:23 +0100556static void
Victor Stinner5ea4c062017-06-20 17:46:36 +0200557tracemalloc_remove_trace(unsigned int domain, uintptr_t ptr)
Victor Stinnere492ae52016-03-22 12:58:23 +0100558{
559 trace_t trace;
560 int removed;
561
Victor Stinner9e00e802018-10-25 13:31:16 +0200562 assert(_Py_tracemalloc_config.tracing);
Victor Stinner10b73e12016-03-22 13:39:05 +0100563
Victor Stinner9e00e802018-10-25 13:31:16 +0200564 if (_Py_tracemalloc_config.use_domain) {
Victor Stinnere492ae52016-03-22 12:58:23 +0100565 pointer_t key = {ptr, domain};
566 removed = _Py_HASHTABLE_POP(tracemalloc_traces, key, trace);
567 }
568 else {
569 removed = _Py_HASHTABLE_POP(tracemalloc_traces, ptr, trace);
570 }
571 if (!removed) {
572 return;
573 }
574
575 assert(tracemalloc_traced_memory >= trace.size);
576 tracemalloc_traced_memory -= trace.size;
577}
578
579#define REMOVE_TRACE(ptr) \
Benjamin Petersonca470632016-09-06 13:47:26 -0700580 tracemalloc_remove_trace(DEFAULT_DOMAIN, (uintptr_t)(ptr))
Victor Stinnere492ae52016-03-22 12:58:23 +0100581
582
Victor Stinner52968672013-11-24 11:37:15 +0100583static int
Victor Stinner5ea4c062017-06-20 17:46:36 +0200584tracemalloc_add_trace(unsigned int domain, uintptr_t ptr,
Victor Stinner10b73e12016-03-22 13:39:05 +0100585 size_t size)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100586{
Victor Stinnerca79ccd2016-03-23 09:38:54 +0100587 pointer_t key = {ptr, domain};
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100588 traceback_t *traceback;
589 trace_t trace;
Victor Stinnerca79ccd2016-03-23 09:38:54 +0100590 _Py_hashtable_entry_t* entry;
Victor Stinner52968672013-11-24 11:37:15 +0100591 int res;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100592
Victor Stinner9e00e802018-10-25 13:31:16 +0200593 assert(_Py_tracemalloc_config.tracing);
Victor Stinner10b73e12016-03-22 13:39:05 +0100594
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100595 traceback = traceback_new();
Victor Stinnere492ae52016-03-22 12:58:23 +0100596 if (traceback == NULL) {
Victor Stinner52968672013-11-24 11:37:15 +0100597 return -1;
Victor Stinnere492ae52016-03-22 12:58:23 +0100598 }
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100599
Victor Stinner9e00e802018-10-25 13:31:16 +0200600 if (!_Py_tracemalloc_config.use_domain && domain != DEFAULT_DOMAIN) {
Victor Stinner5e14a382016-03-23 22:03:55 +0100601 /* first trace using a non-zero domain whereas traces use compact
Benjamin Petersonca470632016-09-06 13:47:26 -0700602 (uintptr_t) keys: switch to pointer_t keys. */
Victor Stinner5e14a382016-03-23 22:03:55 +0100603 if (tracemalloc_use_domain() < 0) {
604 return -1;
605 }
606 }
607
Victor Stinner9e00e802018-10-25 13:31:16 +0200608 if (_Py_tracemalloc_config.use_domain) {
Victor Stinnerca79ccd2016-03-23 09:38:54 +0100609 entry = _Py_HASHTABLE_GET_ENTRY(tracemalloc_traces, key);
Victor Stinnere492ae52016-03-22 12:58:23 +0100610 }
611 else {
Victor Stinnerca79ccd2016-03-23 09:38:54 +0100612 entry = _Py_HASHTABLE_GET_ENTRY(tracemalloc_traces, ptr);
Victor Stinnerd606ba72013-11-24 11:28:20 +0100613 }
Victor Stinner52968672013-11-24 11:37:15 +0100614
Victor Stinnerca79ccd2016-03-23 09:38:54 +0100615 if (entry != NULL) {
616 /* the memory block is already tracked */
617 _Py_HASHTABLE_ENTRY_READ_DATA(tracemalloc_traces, entry, trace);
618 assert(tracemalloc_traced_memory >= trace.size);
619 tracemalloc_traced_memory -= trace.size;
620
621 trace.size = size;
622 trace.traceback = traceback;
623 _Py_HASHTABLE_ENTRY_WRITE_DATA(tracemalloc_traces, entry, trace);
624 }
625 else {
626 trace.size = size;
627 trace.traceback = traceback;
628
Victor Stinner9e00e802018-10-25 13:31:16 +0200629 if (_Py_tracemalloc_config.use_domain) {
Victor Stinnerca79ccd2016-03-23 09:38:54 +0100630 res = _Py_HASHTABLE_SET(tracemalloc_traces, key, trace);
631 }
632 else {
633 res = _Py_HASHTABLE_SET(tracemalloc_traces, ptr, trace);
634 }
635 if (res != 0) {
636 return res;
637 }
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100638 }
Victor Stinnere492ae52016-03-22 12:58:23 +0100639
Benjamin Peterson2f8bfef2016-09-07 09:26:18 -0700640 assert(tracemalloc_traced_memory <= SIZE_MAX - size);
Victor Stinnere492ae52016-03-22 12:58:23 +0100641 tracemalloc_traced_memory += size;
642 if (tracemalloc_traced_memory > tracemalloc_peak_traced_memory)
643 tracemalloc_peak_traced_memory = tracemalloc_traced_memory;
644 return 0;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100645}
646
Victor Stinnere492ae52016-03-22 12:58:23 +0100647#define ADD_TRACE(ptr, size) \
Benjamin Petersonca470632016-09-06 13:47:26 -0700648 tracemalloc_add_trace(DEFAULT_DOMAIN, (uintptr_t)(ptr), size)
Victor Stinnere492ae52016-03-22 12:58:23 +0100649
650
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100651static void*
Victor Stinnerdb067af2014-05-02 22:31:14 +0200652tracemalloc_alloc(int use_calloc, void *ctx, size_t nelem, size_t elsize)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100653{
Victor Stinnerd8f0d922014-06-02 21:57:10 +0200654 PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100655 void *ptr;
656
Benjamin Peterson2f8bfef2016-09-07 09:26:18 -0700657 assert(elsize == 0 || nelem <= SIZE_MAX / elsize);
Victor Stinnerdb067af2014-05-02 22:31:14 +0200658
659 if (use_calloc)
660 ptr = alloc->calloc(alloc->ctx, nelem, elsize);
661 else
662 ptr = alloc->malloc(alloc->ctx, nelem * elsize);
Victor Stinner15116802013-12-04 01:29:35 +0100663 if (ptr == NULL)
664 return NULL;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100665
Victor Stinner88c29872013-12-04 01:47:46 +0100666 TABLES_LOCK();
Victor Stinnere492ae52016-03-22 12:58:23 +0100667 if (ADD_TRACE(ptr, nelem * elsize) < 0) {
Victor Stinner15116802013-12-04 01:29:35 +0100668 /* Failed to allocate a trace for the new memory block */
Victor Stinner88c29872013-12-04 01:47:46 +0100669 TABLES_UNLOCK();
Victor Stinner15116802013-12-04 01:29:35 +0100670 alloc->free(alloc->ctx, ptr);
671 return NULL;
Victor Stinner52968672013-11-24 11:37:15 +0100672 }
Victor Stinner88c29872013-12-04 01:47:46 +0100673 TABLES_UNLOCK();
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100674 return ptr;
675}
676
Victor Stinnere492ae52016-03-22 12:58:23 +0100677
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100678static void*
Victor Stinner15116802013-12-04 01:29:35 +0100679tracemalloc_realloc(void *ctx, void *ptr, size_t new_size)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100680{
Victor Stinnerd8f0d922014-06-02 21:57:10 +0200681 PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100682 void *ptr2;
683
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100684 ptr2 = alloc->realloc(alloc->ctx, ptr, new_size);
Victor Stinner15116802013-12-04 01:29:35 +0100685 if (ptr2 == NULL)
686 return NULL;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100687
Victor Stinner15116802013-12-04 01:29:35 +0100688 if (ptr != NULL) {
689 /* an existing memory block has been resized */
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100690
Victor Stinner88c29872013-12-04 01:47:46 +0100691 TABLES_LOCK();
Victor Stinner42bcf372016-03-23 09:08:08 +0100692
693 /* tracemalloc_add_trace() updates the trace if there is already
694 a trace at address (domain, ptr2) */
695 if (ptr2 != ptr) {
696 REMOVE_TRACE(ptr);
697 }
Victor Stinner08facd22013-11-24 12:27:59 +0100698
Victor Stinnere492ae52016-03-22 12:58:23 +0100699 if (ADD_TRACE(ptr2, new_size) < 0) {
Victor Stinner15116802013-12-04 01:29:35 +0100700 /* Memory allocation failed. The error cannot be reported to
Raymond Hettinger15f44ab2016-08-30 10:47:49 -0700701 the caller, because realloc() may already have shrunk the
Victor Stinner15116802013-12-04 01:29:35 +0100702 memory block and so removed bytes.
703
Serhiy Storchaka6a7b3a72016-04-17 08:32:47 +0300704 This case is very unlikely: a hash entry has just been
Victor Stinner88c29872013-12-04 01:47:46 +0100705 released, so the hash table should have at least one free entry.
706
707 The GIL and the table lock ensures that only one thread is
708 allocating memory. */
Serhiy Storchakaeebaa9b2020-03-09 20:49:52 +0200709 Py_FatalError("tracemalloc_realloc() failed to allocate a trace");
Victor Stinner52968672013-11-24 11:37:15 +0100710 }
Victor Stinner88c29872013-12-04 01:47:46 +0100711 TABLES_UNLOCK();
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100712 }
Victor Stinner15116802013-12-04 01:29:35 +0100713 else {
714 /* new allocation */
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100715
Victor Stinner88c29872013-12-04 01:47:46 +0100716 TABLES_LOCK();
Victor Stinnere492ae52016-03-22 12:58:23 +0100717 if (ADD_TRACE(ptr2, new_size) < 0) {
Victor Stinner15116802013-12-04 01:29:35 +0100718 /* Failed to allocate a trace for the new memory block */
Victor Stinner88c29872013-12-04 01:47:46 +0100719 TABLES_UNLOCK();
Victor Stinner15116802013-12-04 01:29:35 +0100720 alloc->free(alloc->ctx, ptr2);
721 return NULL;
722 }
Victor Stinner88c29872013-12-04 01:47:46 +0100723 TABLES_UNLOCK();
Victor Stinner15116802013-12-04 01:29:35 +0100724 }
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100725 return ptr2;
726}
727
Victor Stinnere492ae52016-03-22 12:58:23 +0100728
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100729static void
730tracemalloc_free(void *ctx, void *ptr)
731{
Victor Stinnerd8f0d922014-06-02 21:57:10 +0200732 PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100733
734 if (ptr == NULL)
735 return;
736
737 /* GIL cannot be locked in PyMem_RawFree() because it would introduce
Joannah Nanjekye2bc43cd2019-09-05 13:06:49 -0300738 a deadlock in _PyThreadState_DeleteCurrent(). */
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100739
740 alloc->free(alloc->ctx, ptr);
Victor Stinner88c29872013-12-04 01:47:46 +0100741
742 TABLES_LOCK();
Victor Stinnere492ae52016-03-22 12:58:23 +0100743 REMOVE_TRACE(ptr);
Victor Stinner88c29872013-12-04 01:47:46 +0100744 TABLES_UNLOCK();
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100745}
746
Victor Stinnere492ae52016-03-22 12:58:23 +0100747
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100748static void*
Victor Stinnerdb067af2014-05-02 22:31:14 +0200749tracemalloc_alloc_gil(int use_calloc, void *ctx, size_t nelem, size_t elsize)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100750{
Victor Stinner15116802013-12-04 01:29:35 +0100751 void *ptr;
752
753 if (get_reentrant()) {
Victor Stinnerd8f0d922014-06-02 21:57:10 +0200754 PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx;
Victor Stinnerdb067af2014-05-02 22:31:14 +0200755 if (use_calloc)
756 return alloc->calloc(alloc->ctx, nelem, elsize);
757 else
758 return alloc->malloc(alloc->ctx, nelem * elsize);
Victor Stinner15116802013-12-04 01:29:35 +0100759 }
760
761 /* Ignore reentrant call. PyObjet_Malloc() calls PyMem_Malloc() for
762 allocations larger than 512 bytes, don't trace the same memory
763 allocation twice. */
764 set_reentrant(1);
765
Victor Stinnerdb067af2014-05-02 22:31:14 +0200766 ptr = tracemalloc_alloc(use_calloc, ctx, nelem, elsize);
Victor Stinner15116802013-12-04 01:29:35 +0100767
768 set_reentrant(0);
769 return ptr;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100770}
771
Victor Stinnere492ae52016-03-22 12:58:23 +0100772
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100773static void*
Victor Stinnerdb067af2014-05-02 22:31:14 +0200774tracemalloc_malloc_gil(void *ctx, size_t size)
775{
776 return tracemalloc_alloc_gil(0, ctx, 1, size);
777}
778
Victor Stinnere492ae52016-03-22 12:58:23 +0100779
Victor Stinnerdb067af2014-05-02 22:31:14 +0200780static void*
781tracemalloc_calloc_gil(void *ctx, size_t nelem, size_t elsize)
782{
783 return tracemalloc_alloc_gil(1, ctx, nelem, elsize);
784}
785
Victor Stinnere492ae52016-03-22 12:58:23 +0100786
Victor Stinnerdb067af2014-05-02 22:31:14 +0200787static void*
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100788tracemalloc_realloc_gil(void *ctx, void *ptr, size_t new_size)
789{
Victor Stinner15116802013-12-04 01:29:35 +0100790 void *ptr2;
791
792 if (get_reentrant()) {
793 /* Reentrant call to PyMem_Realloc() and PyMem_RawRealloc().
794 Example: PyMem_RawRealloc() is called internally by pymalloc
795 (_PyObject_Malloc() and _PyObject_Realloc()) to allocate a new
796 arena (new_arena()). */
Victor Stinnerd8f0d922014-06-02 21:57:10 +0200797 PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx;
Victor Stinner15116802013-12-04 01:29:35 +0100798
799 ptr2 = alloc->realloc(alloc->ctx, ptr, new_size);
Victor Stinner88c29872013-12-04 01:47:46 +0100800 if (ptr2 != NULL && ptr != NULL) {
801 TABLES_LOCK();
Victor Stinnere492ae52016-03-22 12:58:23 +0100802 REMOVE_TRACE(ptr);
Victor Stinner88c29872013-12-04 01:47:46 +0100803 TABLES_UNLOCK();
804 }
Victor Stinner15116802013-12-04 01:29:35 +0100805 return ptr2;
806 }
807
808 /* Ignore reentrant call. PyObjet_Realloc() calls PyMem_Realloc() for
809 allocations larger than 512 bytes. Don't trace the same memory
810 allocation twice. */
811 set_reentrant(1);
812
813 ptr2 = tracemalloc_realloc(ctx, ptr, new_size);
814
815 set_reentrant(0);
816 return ptr2;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100817}
818
Victor Stinnere492ae52016-03-22 12:58:23 +0100819
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100820#ifdef TRACE_RAW_MALLOC
821static void*
Victor Stinnerdb067af2014-05-02 22:31:14 +0200822tracemalloc_raw_alloc(int use_calloc, void *ctx, size_t nelem, size_t elsize)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100823{
Victor Stinner15116802013-12-04 01:29:35 +0100824 PyGILState_STATE gil_state;
Victor Stinner15116802013-12-04 01:29:35 +0100825 void *ptr;
826
827 if (get_reentrant()) {
Victor Stinnerd8f0d922014-06-02 21:57:10 +0200828 PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx;
Victor Stinnerdb067af2014-05-02 22:31:14 +0200829 if (use_calloc)
830 return alloc->calloc(alloc->ctx, nelem, elsize);
831 else
832 return alloc->malloc(alloc->ctx, nelem * elsize);
Victor Stinner15116802013-12-04 01:29:35 +0100833 }
834
835 /* Ignore reentrant call. PyGILState_Ensure() may call PyMem_RawMalloc()
836 indirectly which would call PyGILState_Ensure() if reentrant are not
837 disabled. */
838 set_reentrant(1);
839
Victor Stinner15116802013-12-04 01:29:35 +0100840 gil_state = PyGILState_Ensure();
Victor Stinnerdb067af2014-05-02 22:31:14 +0200841 ptr = tracemalloc_alloc(use_calloc, ctx, nelem, elsize);
Victor Stinner15116802013-12-04 01:29:35 +0100842 PyGILState_Release(gil_state);
Victor Stinner15116802013-12-04 01:29:35 +0100843
844 set_reentrant(0);
845 return ptr;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100846}
847
Victor Stinnere492ae52016-03-22 12:58:23 +0100848
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100849static void*
Victor Stinnerdb067af2014-05-02 22:31:14 +0200850tracemalloc_raw_malloc(void *ctx, size_t size)
851{
852 return tracemalloc_raw_alloc(0, ctx, 1, size);
853}
854
Victor Stinnere492ae52016-03-22 12:58:23 +0100855
Victor Stinnerdb067af2014-05-02 22:31:14 +0200856static void*
857tracemalloc_raw_calloc(void *ctx, size_t nelem, size_t elsize)
858{
859 return tracemalloc_raw_alloc(1, ctx, nelem, elsize);
860}
861
Victor Stinnere492ae52016-03-22 12:58:23 +0100862
Victor Stinnerdb067af2014-05-02 22:31:14 +0200863static void*
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100864tracemalloc_raw_realloc(void *ctx, void *ptr, size_t new_size)
865{
Victor Stinner15116802013-12-04 01:29:35 +0100866 PyGILState_STATE gil_state;
Victor Stinner15116802013-12-04 01:29:35 +0100867 void *ptr2;
868
869 if (get_reentrant()) {
870 /* Reentrant call to PyMem_RawRealloc(). */
Victor Stinnerd8f0d922014-06-02 21:57:10 +0200871 PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx;
Victor Stinner15116802013-12-04 01:29:35 +0100872
873 ptr2 = alloc->realloc(alloc->ctx, ptr, new_size);
Victor Stinner15116802013-12-04 01:29:35 +0100874
Victor Stinner88c29872013-12-04 01:47:46 +0100875 if (ptr2 != NULL && ptr != NULL) {
876 TABLES_LOCK();
Victor Stinnere492ae52016-03-22 12:58:23 +0100877 REMOVE_TRACE(ptr);
Victor Stinner88c29872013-12-04 01:47:46 +0100878 TABLES_UNLOCK();
879 }
Victor Stinner15116802013-12-04 01:29:35 +0100880 return ptr2;
881 }
882
883 /* Ignore reentrant call. PyGILState_Ensure() may call PyMem_RawMalloc()
884 indirectly which would call PyGILState_Ensure() if reentrant calls are
885 not disabled. */
886 set_reentrant(1);
887
Victor Stinner15116802013-12-04 01:29:35 +0100888 gil_state = PyGILState_Ensure();
889 ptr2 = tracemalloc_realloc(ctx, ptr, new_size);
890 PyGILState_Release(gil_state);
Victor Stinner15116802013-12-04 01:29:35 +0100891
892 set_reentrant(0);
893 return ptr2;
894}
895#endif /* TRACE_RAW_MALLOC */
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100896
Victor Stinnere492ae52016-03-22 12:58:23 +0100897
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100898static int
Victor Stinner285cf0a2016-03-21 22:00:58 +0100899tracemalloc_clear_filename(_Py_hashtable_t *ht, _Py_hashtable_entry_t *entry,
900 void *user_data)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100901{
Victor Stinner285cf0a2016-03-21 22:00:58 +0100902 PyObject *filename;
903
Victor Stinner5dacbd42016-03-23 09:52:13 +0100904 _Py_HASHTABLE_ENTRY_READ_KEY(ht, entry, filename);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100905 Py_DECREF(filename);
906 return 0;
907}
908
Victor Stinnere492ae52016-03-22 12:58:23 +0100909
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100910static int
Victor Stinner285cf0a2016-03-21 22:00:58 +0100911traceback_free_traceback(_Py_hashtable_t *ht, _Py_hashtable_entry_t *entry,
912 void *user_data)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100913{
Victor Stinner285cf0a2016-03-21 22:00:58 +0100914 traceback_t *traceback;
915
Victor Stinner5dacbd42016-03-23 09:52:13 +0100916 _Py_HASHTABLE_ENTRY_READ_KEY(ht, entry, traceback);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100917 raw_free(traceback);
918 return 0;
919}
920
Victor Stinnere492ae52016-03-22 12:58:23 +0100921
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100922/* reentrant flag must be set to call this function and GIL must be held */
923static void
924tracemalloc_clear_traces(void)
925{
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100926 /* The GIL protects variables againt concurrent access */
927 assert(PyGILState_Check());
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100928
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100929 TABLES_LOCK();
930 _Py_hashtable_clear(tracemalloc_traces);
931 tracemalloc_traced_memory = 0;
Victor Stinner3c0481d2013-11-27 21:39:49 +0100932 tracemalloc_peak_traced_memory = 0;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100933 TABLES_UNLOCK();
934
935 _Py_hashtable_foreach(tracemalloc_tracebacks, traceback_free_traceback, NULL);
936 _Py_hashtable_clear(tracemalloc_tracebacks);
937
938 _Py_hashtable_foreach(tracemalloc_filenames, tracemalloc_clear_filename, NULL);
939 _Py_hashtable_clear(tracemalloc_filenames);
940}
941
Victor Stinnere492ae52016-03-22 12:58:23 +0100942
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100943static int
944tracemalloc_init(void)
945{
Victor Stinner9e00e802018-10-25 13:31:16 +0200946 if (_Py_tracemalloc_config.initialized == TRACEMALLOC_FINALIZED) {
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100947 PyErr_SetString(PyExc_RuntimeError,
948 "the tracemalloc module has been unloaded");
949 return -1;
950 }
951
Victor Stinner9e00e802018-10-25 13:31:16 +0200952 if (_Py_tracemalloc_config.initialized == TRACEMALLOC_INITIALIZED)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100953 return 0;
954
955 PyMem_GetAllocator(PYMEM_DOMAIN_RAW, &allocators.raw);
956
957#ifdef REENTRANT_THREADLOCAL
Masayuki Yamamoto731e1892017-10-06 19:41:34 +0900958 if (PyThread_tss_create(&tracemalloc_reentrant_key) != 0) {
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100959#ifdef MS_WINDOWS
960 PyErr_SetFromWindowsErr(0);
961#else
962 PyErr_SetFromErrno(PyExc_OSError);
963#endif
964 return -1;
965 }
966#endif
967
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200968#if defined(TRACE_RAW_MALLOC)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100969 if (tables_lock == NULL) {
970 tables_lock = PyThread_allocate_lock();
971 if (tables_lock == NULL) {
972 PyErr_SetString(PyExc_RuntimeError, "cannot allocate lock");
973 return -1;
974 }
975 }
976#endif
977
Victor Stinner285cf0a2016-03-21 22:00:58 +0100978 tracemalloc_filenames = hashtable_new(sizeof(PyObject *), 0,
979 hashtable_hash_pyobject,
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100980 hashtable_compare_unicode);
981
Victor Stinner285cf0a2016-03-21 22:00:58 +0100982 tracemalloc_tracebacks = hashtable_new(sizeof(traceback_t *), 0,
983 hashtable_hash_traceback,
984 hashtable_compare_traceback);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100985
Victor Stinner9e00e802018-10-25 13:31:16 +0200986 if (_Py_tracemalloc_config.use_domain) {
Victor Stinnere492ae52016-03-22 12:58:23 +0100987 tracemalloc_traces = hashtable_new(sizeof(pointer_t),
988 sizeof(trace_t),
989 hashtable_hash_pointer_t,
990 hashtable_compare_pointer_t);
991 }
992 else {
Benjamin Petersonca470632016-09-06 13:47:26 -0700993 tracemalloc_traces = hashtable_new(sizeof(uintptr_t),
Victor Stinnere492ae52016-03-22 12:58:23 +0100994 sizeof(trace_t),
995 _Py_hashtable_hash_ptr,
996 _Py_hashtable_compare_direct);
997 }
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100998
999 if (tracemalloc_filenames == NULL || tracemalloc_tracebacks == NULL
Victor Stinner285cf0a2016-03-21 22:00:58 +01001000 || tracemalloc_traces == NULL) {
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001001 PyErr_NoMemory();
1002 return -1;
1003 }
1004
1005 unknown_filename = PyUnicode_FromString("<unknown>");
1006 if (unknown_filename == NULL)
1007 return -1;
1008 PyUnicode_InternInPlace(&unknown_filename);
1009
1010 tracemalloc_empty_traceback.nframe = 1;
Julien Danjou8d59eb12019-10-15 14:00:16 +02001011 tracemalloc_empty_traceback.total_nframe = 1;
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001012 /* borrowed reference */
1013 tracemalloc_empty_traceback.frames[0].filename = unknown_filename;
1014 tracemalloc_empty_traceback.frames[0].lineno = 0;
1015 tracemalloc_empty_traceback.hash = traceback_hash(&tracemalloc_empty_traceback);
1016
Victor Stinner9e00e802018-10-25 13:31:16 +02001017 _Py_tracemalloc_config.initialized = TRACEMALLOC_INITIALIZED;
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001018 return 0;
1019}
1020
Victor Stinnere492ae52016-03-22 12:58:23 +01001021
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001022static void
1023tracemalloc_deinit(void)
1024{
Victor Stinner9e00e802018-10-25 13:31:16 +02001025 if (_Py_tracemalloc_config.initialized != TRACEMALLOC_INITIALIZED)
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001026 return;
Victor Stinner9e00e802018-10-25 13:31:16 +02001027 _Py_tracemalloc_config.initialized = TRACEMALLOC_FINALIZED;
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001028
1029 tracemalloc_stop();
1030
1031 /* destroy hash tables */
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001032 _Py_hashtable_destroy(tracemalloc_tracebacks);
1033 _Py_hashtable_destroy(tracemalloc_filenames);
Victor Stinner285cf0a2016-03-21 22:00:58 +01001034 _Py_hashtable_destroy(tracemalloc_traces);
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001035
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02001036#if defined(TRACE_RAW_MALLOC)
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001037 if (tables_lock != NULL) {
1038 PyThread_free_lock(tables_lock);
1039 tables_lock = NULL;
1040 }
1041#endif
1042
1043#ifdef REENTRANT_THREADLOCAL
Masayuki Yamamoto731e1892017-10-06 19:41:34 +09001044 PyThread_tss_delete(&tracemalloc_reentrant_key);
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001045#endif
1046
1047 Py_XDECREF(unknown_filename);
1048}
1049
Victor Stinnere492ae52016-03-22 12:58:23 +01001050
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001051static int
Victor Stinnerf28ce602013-11-27 22:27:13 +01001052tracemalloc_start(int max_nframe)
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001053{
Victor Stinnerd8f0d922014-06-02 21:57:10 +02001054 PyMemAllocatorEx alloc;
Victor Stinnerf28ce602013-11-27 22:27:13 +01001055 size_t size;
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001056
Julien Danjou8d59eb12019-10-15 14:00:16 +02001057 if (max_nframe < 1 || (unsigned long) max_nframe > MAX_NFRAME) {
Victor Stinnera7368ac2017-11-15 18:11:45 -08001058 PyErr_Format(PyExc_ValueError,
Julien Danjou8d59eb12019-10-15 14:00:16 +02001059 "the number of frames must be in range [1; %lu]",
1060 MAX_NFRAME);
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001061 return -1;
Victor Stinnera7368ac2017-11-15 18:11:45 -08001062 }
1063
1064 if (tracemalloc_init() < 0) {
1065 return -1;
1066 }
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001067
Victor Stinner9e00e802018-10-25 13:31:16 +02001068 if (_Py_tracemalloc_config.tracing) {
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001069 /* hook already installed: do nothing */
1070 return 0;
1071 }
1072
Victor Stinner9e00e802018-10-25 13:31:16 +02001073 _Py_tracemalloc_config.max_nframe = max_nframe;
Victor Stinnerf28ce602013-11-27 22:27:13 +01001074
1075 /* allocate a buffer to store a new traceback */
1076 size = TRACEBACK_SIZE(max_nframe);
1077 assert(tracemalloc_traceback == NULL);
1078 tracemalloc_traceback = raw_malloc(size);
1079 if (tracemalloc_traceback == NULL) {
1080 PyErr_NoMemory();
1081 return -1;
1082 }
1083
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001084#ifdef TRACE_RAW_MALLOC
1085 alloc.malloc = tracemalloc_raw_malloc;
Victor Stinnerdb067af2014-05-02 22:31:14 +02001086 alloc.calloc = tracemalloc_raw_calloc;
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001087 alloc.realloc = tracemalloc_raw_realloc;
1088 alloc.free = tracemalloc_free;
1089
1090 alloc.ctx = &allocators.raw;
1091 PyMem_GetAllocator(PYMEM_DOMAIN_RAW, &allocators.raw);
1092 PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &alloc);
1093#endif
1094
1095 alloc.malloc = tracemalloc_malloc_gil;
Victor Stinnerdb067af2014-05-02 22:31:14 +02001096 alloc.calloc = tracemalloc_calloc_gil;
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001097 alloc.realloc = tracemalloc_realloc_gil;
1098 alloc.free = tracemalloc_free;
1099
1100 alloc.ctx = &allocators.mem;
1101 PyMem_GetAllocator(PYMEM_DOMAIN_MEM, &allocators.mem);
1102 PyMem_SetAllocator(PYMEM_DOMAIN_MEM, &alloc);
1103
1104 alloc.ctx = &allocators.obj;
1105 PyMem_GetAllocator(PYMEM_DOMAIN_OBJ, &allocators.obj);
1106 PyMem_SetAllocator(PYMEM_DOMAIN_OBJ, &alloc);
1107
1108 /* everything is ready: start tracing Python memory allocations */
Victor Stinner9e00e802018-10-25 13:31:16 +02001109 _Py_tracemalloc_config.tracing = 1;
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001110
1111 return 0;
1112}
1113
Victor Stinnere492ae52016-03-22 12:58:23 +01001114
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001115static void
1116tracemalloc_stop(void)
1117{
Victor Stinner9e00e802018-10-25 13:31:16 +02001118 if (!_Py_tracemalloc_config.tracing)
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001119 return;
1120
1121 /* stop tracing Python memory allocations */
Victor Stinner9e00e802018-10-25 13:31:16 +02001122 _Py_tracemalloc_config.tracing = 0;
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001123
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001124 /* unregister the hook on memory allocators */
1125#ifdef TRACE_RAW_MALLOC
1126 PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &allocators.raw);
1127#endif
1128 PyMem_SetAllocator(PYMEM_DOMAIN_MEM, &allocators.mem);
1129 PyMem_SetAllocator(PYMEM_DOMAIN_OBJ, &allocators.obj);
1130
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001131 tracemalloc_clear_traces();
Victor Stinner285cf0a2016-03-21 22:00:58 +01001132
1133 /* release memory */
Victor Stinnerf28ce602013-11-27 22:27:13 +01001134 raw_free(tracemalloc_traceback);
1135 tracemalloc_traceback = NULL;
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001136}
1137
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001138
Victor Stinnere492ae52016-03-22 12:58:23 +01001139
Serhiy Storchakab451f912017-02-04 12:18:38 +02001140/*[clinic input]
1141_tracemalloc.is_tracing
1142
1143Return True if the tracemalloc module is tracing Python memory allocations.
1144[clinic start generated code]*/
1145
1146static PyObject *
1147_tracemalloc_is_tracing_impl(PyObject *module)
Serhiy Storchaka97353842017-02-05 22:58:46 +02001148/*[clinic end generated code: output=2d763b42601cd3ef input=af104b0a00192f63]*/
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001149{
Victor Stinner9e00e802018-10-25 13:31:16 +02001150 return PyBool_FromLong(_Py_tracemalloc_config.tracing);
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001151}
1152
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001153
Serhiy Storchakab451f912017-02-04 12:18:38 +02001154/*[clinic input]
1155_tracemalloc.clear_traces
Victor Stinnere492ae52016-03-22 12:58:23 +01001156
Serhiy Storchakab451f912017-02-04 12:18:38 +02001157Clear traces of memory blocks allocated by Python.
1158[clinic start generated code]*/
1159
1160static PyObject *
1161_tracemalloc_clear_traces_impl(PyObject *module)
1162/*[clinic end generated code: output=a86080ee41b84197 input=0dab5b6c785183a5]*/
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001163{
Victor Stinner9e00e802018-10-25 13:31:16 +02001164 if (!_Py_tracemalloc_config.tracing)
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001165 Py_RETURN_NONE;
1166
1167 set_reentrant(1);
1168 tracemalloc_clear_traces();
1169 set_reentrant(0);
1170
1171 Py_RETURN_NONE;
1172}
1173
Victor Stinnere492ae52016-03-22 12:58:23 +01001174
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001175static PyObject*
1176frame_to_pyobject(frame_t *frame)
1177{
1178 PyObject *frame_obj, *lineno_obj;
1179
1180 frame_obj = PyTuple_New(2);
1181 if (frame_obj == NULL)
1182 return NULL;
1183
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001184 Py_INCREF(frame->filename);
1185 PyTuple_SET_ITEM(frame_obj, 0, frame->filename);
1186
Victor Stinner95283342016-03-15 21:57:02 +01001187 lineno_obj = PyLong_FromUnsignedLong(frame->lineno);
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001188 if (lineno_obj == NULL) {
1189 Py_DECREF(frame_obj);
1190 return NULL;
1191 }
1192 PyTuple_SET_ITEM(frame_obj, 1, lineno_obj);
1193
1194 return frame_obj;
1195}
1196
Victor Stinnere492ae52016-03-22 12:58:23 +01001197
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001198static PyObject*
1199traceback_to_pyobject(traceback_t *traceback, _Py_hashtable_t *intern_table)
1200{
1201 int i;
1202 PyObject *frames, *frame;
1203
1204 if (intern_table != NULL) {
1205 if (_Py_HASHTABLE_GET(intern_table, traceback, frames)) {
1206 Py_INCREF(frames);
1207 return frames;
1208 }
1209 }
1210
1211 frames = PyTuple_New(traceback->nframe);
1212 if (frames == NULL)
1213 return NULL;
1214
1215 for (i=0; i < traceback->nframe; i++) {
1216 frame = frame_to_pyobject(&traceback->frames[i]);
1217 if (frame == NULL) {
1218 Py_DECREF(frames);
1219 return NULL;
1220 }
1221 PyTuple_SET_ITEM(frames, i, frame);
1222 }
1223
1224 if (intern_table != NULL) {
1225 if (_Py_HASHTABLE_SET(intern_table, traceback, frames) < 0) {
1226 Py_DECREF(frames);
1227 PyErr_NoMemory();
1228 return NULL;
1229 }
1230 /* intern_table keeps a new reference to frames */
1231 Py_INCREF(frames);
1232 }
1233 return frames;
1234}
1235
Victor Stinnere492ae52016-03-22 12:58:23 +01001236
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001237static PyObject*
Victor Stinner5ea4c062017-06-20 17:46:36 +02001238trace_to_pyobject(unsigned int domain, trace_t *trace,
Victor Stinnere492ae52016-03-22 12:58:23 +01001239 _Py_hashtable_t *intern_tracebacks)
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001240{
1241 PyObject *trace_obj = NULL;
Victor Stinnere492ae52016-03-22 12:58:23 +01001242 PyObject *obj;
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001243
Julien Danjou8d59eb12019-10-15 14:00:16 +02001244 trace_obj = PyTuple_New(4);
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001245 if (trace_obj == NULL)
1246 return NULL;
1247
Victor Stinnere492ae52016-03-22 12:58:23 +01001248 obj = PyLong_FromSize_t(domain);
1249 if (obj == NULL) {
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001250 Py_DECREF(trace_obj);
1251 return NULL;
1252 }
Victor Stinnere492ae52016-03-22 12:58:23 +01001253 PyTuple_SET_ITEM(trace_obj, 0, obj);
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001254
Victor Stinnere492ae52016-03-22 12:58:23 +01001255 obj = PyLong_FromSize_t(trace->size);
1256 if (obj == NULL) {
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001257 Py_DECREF(trace_obj);
1258 return NULL;
1259 }
Victor Stinnere492ae52016-03-22 12:58:23 +01001260 PyTuple_SET_ITEM(trace_obj, 1, obj);
1261
1262 obj = traceback_to_pyobject(trace->traceback, intern_tracebacks);
1263 if (obj == NULL) {
1264 Py_DECREF(trace_obj);
1265 return NULL;
1266 }
1267 PyTuple_SET_ITEM(trace_obj, 2, obj);
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001268
Julien Danjou8d59eb12019-10-15 14:00:16 +02001269 obj = PyLong_FromUnsignedLong(trace->traceback->total_nframe);
1270 if (obj == NULL) {
1271 Py_DECREF(trace_obj);
1272 return NULL;
1273 }
1274 PyTuple_SET_ITEM(trace_obj, 3, obj);
1275
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001276 return trace_obj;
1277}
1278
Victor Stinnere492ae52016-03-22 12:58:23 +01001279
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001280typedef struct {
1281 _Py_hashtable_t *traces;
1282 _Py_hashtable_t *tracebacks;
1283 PyObject *list;
1284} get_traces_t;
1285
1286static int
Victor Stinner285cf0a2016-03-21 22:00:58 +01001287tracemalloc_get_traces_fill(_Py_hashtable_t *traces, _Py_hashtable_entry_t *entry,
1288 void *user_data)
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001289{
1290 get_traces_t *get_traces = user_data;
Victor Stinner5ea4c062017-06-20 17:46:36 +02001291 unsigned int domain;
Victor Stinner5dacbd42016-03-23 09:52:13 +01001292 trace_t trace;
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001293 PyObject *tracemalloc_obj;
1294 int res;
1295
Victor Stinner9e00e802018-10-25 13:31:16 +02001296 if (_Py_tracemalloc_config.use_domain) {
Victor Stinnere492ae52016-03-22 12:58:23 +01001297 pointer_t key;
Victor Stinner5dacbd42016-03-23 09:52:13 +01001298 _Py_HASHTABLE_ENTRY_READ_KEY(traces, entry, key);
Victor Stinnere492ae52016-03-22 12:58:23 +01001299 domain = key.domain;
1300 }
1301 else {
1302 domain = DEFAULT_DOMAIN;
1303 }
Victor Stinner5dacbd42016-03-23 09:52:13 +01001304 _Py_HASHTABLE_ENTRY_READ_DATA(traces, entry, trace);
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001305
Victor Stinner5dacbd42016-03-23 09:52:13 +01001306 tracemalloc_obj = trace_to_pyobject(domain, &trace, get_traces->tracebacks);
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001307 if (tracemalloc_obj == NULL)
1308 return 1;
1309
1310 res = PyList_Append(get_traces->list, tracemalloc_obj);
1311 Py_DECREF(tracemalloc_obj);
1312 if (res < 0)
1313 return 1;
1314
1315 return 0;
1316}
1317
Victor Stinnere492ae52016-03-22 12:58:23 +01001318
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001319static int
Victor Stinner285cf0a2016-03-21 22:00:58 +01001320tracemalloc_pyobject_decref_cb(_Py_hashtable_t *tracebacks,
1321 _Py_hashtable_entry_t *entry,
1322 void *user_data)
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001323{
Victor Stinnerc9553872016-03-22 12:13:01 +01001324 PyObject *obj;
Victor Stinnere8c6b2f2016-03-23 09:25:01 +01001325 _Py_HASHTABLE_ENTRY_READ_DATA(tracebacks, entry, obj);
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001326 Py_DECREF(obj);
1327 return 0;
1328}
1329
Victor Stinnere492ae52016-03-22 12:58:23 +01001330
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001331
Serhiy Storchakab451f912017-02-04 12:18:38 +02001332/*[clinic input]
1333_tracemalloc._get_traces
1334
1335Get traces of all memory blocks allocated by Python.
1336
1337Return a list of (size: int, traceback: tuple) tuples.
1338traceback is a tuple of (filename: str, lineno: int) tuples.
1339
1340Return an empty list if the tracemalloc module is disabled.
1341[clinic start generated code]*/
1342
1343static PyObject *
1344_tracemalloc__get_traces_impl(PyObject *module)
1345/*[clinic end generated code: output=e9929876ced4b5cc input=6c7d2230b24255aa]*/
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001346{
1347 get_traces_t get_traces;
1348 int err;
1349
1350 get_traces.traces = NULL;
1351 get_traces.tracebacks = NULL;
1352 get_traces.list = PyList_New(0);
1353 if (get_traces.list == NULL)
1354 goto error;
1355
Victor Stinner9e00e802018-10-25 13:31:16 +02001356 if (!_Py_tracemalloc_config.tracing)
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001357 return get_traces.list;
1358
Victor Stinnerde2f1322013-11-26 00:26:23 +01001359 /* the traceback hash table is used temporarily to intern traceback tuple
1360 of (filename, lineno) tuples */
Victor Stinnerc9553872016-03-22 12:13:01 +01001361 get_traces.tracebacks = hashtable_new(sizeof(traceback_t *),
1362 sizeof(PyObject *),
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001363 _Py_hashtable_hash_ptr,
1364 _Py_hashtable_compare_direct);
1365 if (get_traces.tracebacks == NULL) {
1366 PyErr_NoMemory();
1367 goto error;
1368 }
1369
1370 TABLES_LOCK();
1371 get_traces.traces = _Py_hashtable_copy(tracemalloc_traces);
1372 TABLES_UNLOCK();
1373
1374 if (get_traces.traces == NULL) {
1375 PyErr_NoMemory();
1376 goto error;
1377 }
1378
1379 set_reentrant(1);
1380 err = _Py_hashtable_foreach(get_traces.traces,
1381 tracemalloc_get_traces_fill, &get_traces);
1382 set_reentrant(0);
1383 if (err)
1384 goto error;
1385
1386 goto finally;
1387
1388error:
1389 Py_CLEAR(get_traces.list);
1390
1391finally:
1392 if (get_traces.tracebacks != NULL) {
1393 _Py_hashtable_foreach(get_traces.tracebacks,
Victor Stinner285cf0a2016-03-21 22:00:58 +01001394 tracemalloc_pyobject_decref_cb, NULL);
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001395 _Py_hashtable_destroy(get_traces.tracebacks);
1396 }
Victor Stinnerc9553872016-03-22 12:13:01 +01001397 if (get_traces.traces != NULL) {
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001398 _Py_hashtable_destroy(get_traces.traces);
Victor Stinnerc9553872016-03-22 12:13:01 +01001399 }
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001400
1401 return get_traces.list;
1402}
1403
Victor Stinnere492ae52016-03-22 12:58:23 +01001404
Victor Stinner0611c262016-03-15 22:22:13 +01001405static traceback_t*
Victor Stinner5ea4c062017-06-20 17:46:36 +02001406tracemalloc_get_traceback(unsigned int domain, uintptr_t ptr)
Victor Stinner0611c262016-03-15 22:22:13 +01001407{
1408 trace_t trace;
1409 int found;
1410
Victor Stinner9e00e802018-10-25 13:31:16 +02001411 if (!_Py_tracemalloc_config.tracing)
Victor Stinner0611c262016-03-15 22:22:13 +01001412 return NULL;
1413
1414 TABLES_LOCK();
Victor Stinner9e00e802018-10-25 13:31:16 +02001415 if (_Py_tracemalloc_config.use_domain) {
Victor Stinner10b73e12016-03-22 13:39:05 +01001416 pointer_t key = {ptr, domain};
Victor Stinnere492ae52016-03-22 12:58:23 +01001417 found = _Py_HASHTABLE_GET(tracemalloc_traces, key, trace);
1418 }
1419 else {
1420 found = _Py_HASHTABLE_GET(tracemalloc_traces, ptr, trace);
1421 }
Victor Stinner0611c262016-03-15 22:22:13 +01001422 TABLES_UNLOCK();
1423
1424 if (!found)
1425 return NULL;
1426
1427 return trace.traceback;
1428}
1429
Victor Stinnere492ae52016-03-22 12:58:23 +01001430
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001431
Serhiy Storchakab451f912017-02-04 12:18:38 +02001432/*[clinic input]
1433_tracemalloc._get_object_traceback
1434
1435 obj: object
1436 /
1437
1438Get the traceback where the Python object obj was allocated.
1439
1440Return a tuple of (filename: str, lineno: int) tuples.
1441Return None if the tracemalloc module is disabled or did not
1442trace the allocation of the object.
1443[clinic start generated code]*/
1444
1445static PyObject *
1446_tracemalloc__get_object_traceback(PyObject *module, PyObject *obj)
1447/*[clinic end generated code: output=41ee0553a658b0aa input=29495f1b21c53212]*/
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001448{
1449 PyTypeObject *type;
1450 void *ptr;
Victor Stinner0611c262016-03-15 22:22:13 +01001451 traceback_t *traceback;
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001452
1453 type = Py_TYPE(obj);
Victor Stinner626bff82018-10-25 17:31:10 +02001454 if (PyType_IS_GC(type)) {
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001455 ptr = (void *)((char *)obj - sizeof(PyGC_Head));
Victor Stinner626bff82018-10-25 17:31:10 +02001456 }
1457 else {
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001458 ptr = (void *)obj;
Victor Stinner626bff82018-10-25 17:31:10 +02001459 }
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001460
Benjamin Petersonca470632016-09-06 13:47:26 -07001461 traceback = tracemalloc_get_traceback(DEFAULT_DOMAIN, (uintptr_t)ptr);
Victor Stinner0611c262016-03-15 22:22:13 +01001462 if (traceback == NULL)
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001463 Py_RETURN_NONE;
1464
Victor Stinner0611c262016-03-15 22:22:13 +01001465 return traceback_to_pyobject(traceback, NULL);
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001466}
1467
Victor Stinnere492ae52016-03-22 12:58:23 +01001468
Victor Stinner0611c262016-03-15 22:22:13 +01001469#define PUTS(fd, str) _Py_write_noraise(fd, str, (int)strlen(str))
1470
1471static void
1472_PyMem_DumpFrame(int fd, frame_t * frame)
1473{
1474 PUTS(fd, " File \"");
1475 _Py_DumpASCII(fd, frame->filename);
1476 PUTS(fd, "\", line ");
1477 _Py_DumpDecimal(fd, frame->lineno);
1478 PUTS(fd, "\n");
1479}
1480
1481/* Dump the traceback where a memory block was allocated into file descriptor
1482 fd. The function may block on TABLES_LOCK() but it is unlikely. */
1483void
1484_PyMem_DumpTraceback(int fd, const void *ptr)
1485{
1486 traceback_t *traceback;
1487 int i;
1488
Victor Stinnerf966e532018-11-13 15:14:58 +01001489 if (!_Py_tracemalloc_config.tracing) {
1490 PUTS(fd, "Enable tracemalloc to get the memory block "
1491 "allocation traceback\n\n");
1492 return;
1493 }
1494
Benjamin Petersonca470632016-09-06 13:47:26 -07001495 traceback = tracemalloc_get_traceback(DEFAULT_DOMAIN, (uintptr_t)ptr);
Victor Stinner0611c262016-03-15 22:22:13 +01001496 if (traceback == NULL)
1497 return;
1498
1499 PUTS(fd, "Memory block allocated at (most recent call first):\n");
1500 for (i=0; i < traceback->nframe; i++) {
1501 _PyMem_DumpFrame(fd, &traceback->frames[i]);
1502 }
1503 PUTS(fd, "\n");
1504}
1505
1506#undef PUTS
1507
Victor Stinnere492ae52016-03-22 12:58:23 +01001508
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001509
Serhiy Storchakab451f912017-02-04 12:18:38 +02001510/*[clinic input]
1511_tracemalloc.start
1512
Victor Stinnera7368ac2017-11-15 18:11:45 -08001513 nframe: int = 1
Serhiy Storchakab451f912017-02-04 12:18:38 +02001514 /
1515
1516Start tracing Python memory allocations.
1517
1518Also set the maximum number of frames stored in the traceback of a
1519trace to nframe.
1520[clinic start generated code]*/
1521
1522static PyObject *
Victor Stinnera7368ac2017-11-15 18:11:45 -08001523_tracemalloc_start_impl(PyObject *module, int nframe)
1524/*[clinic end generated code: output=caae05c23c159d3c input=40d849b5b29d1933]*/
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001525{
Victor Stinnera7368ac2017-11-15 18:11:45 -08001526 if (tracemalloc_start(nframe) < 0) {
Victor Stinner3728d6c2013-11-23 12:37:20 +01001527 return NULL;
1528 }
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001529 Py_RETURN_NONE;
1530}
1531
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001532
Serhiy Storchakab451f912017-02-04 12:18:38 +02001533/*[clinic input]
1534_tracemalloc.stop
Victor Stinnere492ae52016-03-22 12:58:23 +01001535
Serhiy Storchakab451f912017-02-04 12:18:38 +02001536Stop tracing Python memory allocations.
1537
1538Also clear traces of memory blocks allocated by Python.
1539[clinic start generated code]*/
1540
1541static PyObject *
1542_tracemalloc_stop_impl(PyObject *module)
1543/*[clinic end generated code: output=c3c42ae03e3955cd input=7478f075e51dae18]*/
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001544{
1545 tracemalloc_stop();
1546 Py_RETURN_NONE;
1547}
1548
Victor Stinnere492ae52016-03-22 12:58:23 +01001549
Serhiy Storchakab451f912017-02-04 12:18:38 +02001550/*[clinic input]
1551_tracemalloc.get_traceback_limit
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001552
Serhiy Storchakab451f912017-02-04 12:18:38 +02001553Get the maximum number of frames stored in the traceback of a trace.
1554
1555By default, a trace of an allocated memory block only stores
1556the most recent frame: the limit is 1.
1557[clinic start generated code]*/
1558
1559static PyObject *
1560_tracemalloc_get_traceback_limit_impl(PyObject *module)
1561/*[clinic end generated code: output=d556d9306ba95567 input=da3cd977fc68ae3b]*/
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001562{
Victor Stinner9e00e802018-10-25 13:31:16 +02001563 return PyLong_FromLong(_Py_tracemalloc_config.max_nframe);
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001564}
1565
Victor Stinnere492ae52016-03-22 12:58:23 +01001566
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001567
Serhiy Storchakab451f912017-02-04 12:18:38 +02001568/*[clinic input]
1569_tracemalloc.get_tracemalloc_memory
1570
1571Get the memory usage in bytes of the tracemalloc module.
1572
1573This memory is used internally to trace memory allocations.
1574[clinic start generated code]*/
1575
1576static PyObject *
1577_tracemalloc_get_tracemalloc_memory_impl(PyObject *module)
1578/*[clinic end generated code: output=e3f14e280a55f5aa input=5d919c0f4d5132ad]*/
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001579{
1580 size_t size;
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001581
1582 size = _Py_hashtable_size(tracemalloc_tracebacks);
1583 size += _Py_hashtable_size(tracemalloc_filenames);
1584
1585 TABLES_LOCK();
1586 size += _Py_hashtable_size(tracemalloc_traces);
1587 TABLES_UNLOCK();
1588
Serhiy Storchakab451f912017-02-04 12:18:38 +02001589 return PyLong_FromSize_t(size);
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001590}
1591
Victor Stinnere492ae52016-03-22 12:58:23 +01001592
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001593
Serhiy Storchakab451f912017-02-04 12:18:38 +02001594/*[clinic input]
1595_tracemalloc.get_traced_memory
1596
1597Get the current size and peak size of memory blocks traced by tracemalloc.
1598
1599Returns a tuple: (current: int, peak: int).
1600[clinic start generated code]*/
1601
1602static PyObject *
1603_tracemalloc_get_traced_memory_impl(PyObject *module)
1604/*[clinic end generated code: output=5b167189adb9e782 input=61ddb5478400ff66]*/
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001605{
Victor Stinner3c0481d2013-11-27 21:39:49 +01001606 Py_ssize_t size, peak_size;
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001607
Victor Stinner9e00e802018-10-25 13:31:16 +02001608 if (!_Py_tracemalloc_config.tracing)
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001609 return Py_BuildValue("ii", 0, 0);
1610
1611 TABLES_LOCK();
1612 size = tracemalloc_traced_memory;
Victor Stinner3c0481d2013-11-27 21:39:49 +01001613 peak_size = tracemalloc_peak_traced_memory;
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001614 TABLES_UNLOCK();
1615
Serhiy Storchakab451f912017-02-04 12:18:38 +02001616 return Py_BuildValue("nn", size, peak_size);
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001617}
1618
Victor Stinnere492ae52016-03-22 12:58:23 +01001619
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001620static PyMethodDef module_methods[] = {
Serhiy Storchakab451f912017-02-04 12:18:38 +02001621 _TRACEMALLOC_IS_TRACING_METHODDEF
1622 _TRACEMALLOC_CLEAR_TRACES_METHODDEF
1623 _TRACEMALLOC__GET_TRACES_METHODDEF
1624 _TRACEMALLOC__GET_OBJECT_TRACEBACK_METHODDEF
1625 _TRACEMALLOC_START_METHODDEF
1626 _TRACEMALLOC_STOP_METHODDEF
1627 _TRACEMALLOC_GET_TRACEBACK_LIMIT_METHODDEF
1628 _TRACEMALLOC_GET_TRACEMALLOC_MEMORY_METHODDEF
1629 _TRACEMALLOC_GET_TRACED_MEMORY_METHODDEF
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001630 /* sentinel */
1631 {NULL, NULL}
1632};
1633
1634PyDoc_STRVAR(module_doc,
1635"Debug module to trace memory blocks allocated by Python.");
1636
1637static struct PyModuleDef module_def = {
1638 PyModuleDef_HEAD_INIT,
1639 "_tracemalloc",
1640 module_doc,
1641 0, /* non-negative size to be able to unload the module */
1642 module_methods,
1643 NULL,
1644};
1645
1646PyMODINIT_FUNC
1647PyInit__tracemalloc(void)
1648{
1649 PyObject *m;
1650 m = PyModule_Create(&module_def);
1651 if (m == NULL)
1652 return NULL;
1653
Brandt Bucherd51a3632019-11-20 02:00:31 -08001654 if (tracemalloc_init() < 0) {
1655 Py_DECREF(m);
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001656 return NULL;
Brandt Bucherd51a3632019-11-20 02:00:31 -08001657 }
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001658
1659 return m;
1660}
1661
Victor Stinnere492ae52016-03-22 12:58:23 +01001662
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001663int
Victor Stinnera7368ac2017-11-15 18:11:45 -08001664_PyTraceMalloc_Init(int nframe)
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001665{
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001666 assert(PyGILState_Check());
Victor Stinnera7368ac2017-11-15 18:11:45 -08001667 if (nframe == 0) {
1668 return 0;
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001669 }
Victor Stinnerf28ce602013-11-27 22:27:13 +01001670 return tracemalloc_start(nframe);
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001671}
1672
Victor Stinnere492ae52016-03-22 12:58:23 +01001673
Victor Stinnerbe0708f2013-12-01 10:03:26 +01001674void
1675_PyTraceMalloc_Fini(void)
1676{
Victor Stinnerbe0708f2013-12-01 10:03:26 +01001677 assert(PyGILState_Check());
Victor Stinnerbe0708f2013-12-01 10:03:26 +01001678 tracemalloc_deinit();
1679}
Victor Stinner10b73e12016-03-22 13:39:05 +01001680
1681int
Victor Stinner5ea4c062017-06-20 17:46:36 +02001682PyTraceMalloc_Track(unsigned int domain, uintptr_t ptr,
1683 size_t size)
Victor Stinner10b73e12016-03-22 13:39:05 +01001684{
1685 int res;
Victor Stinner10b73e12016-03-22 13:39:05 +01001686 PyGILState_STATE gil_state;
Victor Stinner10b73e12016-03-22 13:39:05 +01001687
Victor Stinner9e00e802018-10-25 13:31:16 +02001688 if (!_Py_tracemalloc_config.tracing) {
Victor Stinner10b73e12016-03-22 13:39:05 +01001689 /* tracemalloc is not tracing: do nothing */
1690 return -2;
1691 }
1692
Victor Stinner10b73e12016-03-22 13:39:05 +01001693 gil_state = PyGILState_Ensure();
Victor Stinner10b73e12016-03-22 13:39:05 +01001694
1695 TABLES_LOCK();
1696 res = tracemalloc_add_trace(domain, ptr, size);
1697 TABLES_UNLOCK();
1698
Victor Stinner10b73e12016-03-22 13:39:05 +01001699 PyGILState_Release(gil_state);
Victor Stinner10b73e12016-03-22 13:39:05 +01001700 return res;
1701}
1702
1703
1704int
Victor Stinner5ea4c062017-06-20 17:46:36 +02001705PyTraceMalloc_Untrack(unsigned int domain, uintptr_t ptr)
Victor Stinner10b73e12016-03-22 13:39:05 +01001706{
Victor Stinner9e00e802018-10-25 13:31:16 +02001707 if (!_Py_tracemalloc_config.tracing) {
Victor Stinner10b73e12016-03-22 13:39:05 +01001708 /* tracemalloc is not tracing: do nothing */
1709 return -2;
1710 }
1711
1712 TABLES_LOCK();
1713 tracemalloc_remove_trace(domain, ptr);
1714 TABLES_UNLOCK();
1715
1716 return 0;
1717}
1718
1719
Victor Stinner9e00e802018-10-25 13:31:16 +02001720/* If the object memory block is already traced, update its trace
1721 with the current Python traceback.
1722
1723 Do nothing if tracemalloc is not tracing memory allocations
1724 or if the object memory block is not already traced. */
1725int
1726_PyTraceMalloc_NewReference(PyObject *op)
1727{
1728 assert(PyGILState_Check());
1729
1730 if (!_Py_tracemalloc_config.tracing) {
1731 /* tracemalloc is not tracing: do nothing */
1732 return -1;
1733 }
1734
1735 uintptr_t ptr;
1736 PyTypeObject *type = Py_TYPE(op);
1737 if (PyType_IS_GC(type)) {
1738 ptr = (uintptr_t)((char *)op - sizeof(PyGC_Head));
1739 }
1740 else {
1741 ptr = (uintptr_t)op;
1742 }
1743
1744 _Py_hashtable_entry_t* entry;
1745 int res = -1;
1746
1747 TABLES_LOCK();
1748 if (_Py_tracemalloc_config.use_domain) {
1749 pointer_t key = {ptr, DEFAULT_DOMAIN};
1750 entry = _Py_HASHTABLE_GET_ENTRY(tracemalloc_traces, key);
1751 }
1752 else {
1753 entry = _Py_HASHTABLE_GET_ENTRY(tracemalloc_traces, ptr);
1754 }
1755
1756 if (entry != NULL) {
1757 /* update the traceback of the memory block */
1758 traceback_t *traceback = traceback_new();
1759 if (traceback != NULL) {
1760 trace_t trace;
1761 _Py_HASHTABLE_ENTRY_READ_DATA(tracemalloc_traces, entry, trace);
1762 trace.traceback = traceback;
1763 _Py_HASHTABLE_ENTRY_WRITE_DATA(tracemalloc_traces, entry, trace);
1764 res = 0;
1765 }
1766 }
1767 /* else: cannot track the object, its memory block size is unknown */
1768 TABLES_UNLOCK();
1769
1770 return res;
1771}
1772
1773
Victor Stinner10b73e12016-03-22 13:39:05 +01001774PyObject*
Victor Stinner5ea4c062017-06-20 17:46:36 +02001775_PyTraceMalloc_GetTraceback(unsigned int domain, uintptr_t ptr)
Victor Stinner10b73e12016-03-22 13:39:05 +01001776{
1777 traceback_t *traceback;
1778
1779 traceback = tracemalloc_get_traceback(domain, ptr);
1780 if (traceback == NULL)
1781 Py_RETURN_NONE;
1782
1783 return traceback_to_pyobject(traceback, NULL);
1784}