17db96d56Sopenharmony_ci#include "Python.h"
27db96d56Sopenharmony_ci#include "pycore_fileutils.h"     // _Py_write_noraise()
37db96d56Sopenharmony_ci#include "pycore_gc.h"            // PyGC_Head
47db96d56Sopenharmony_ci#include "pycore_hashtable.h"     // _Py_hashtable_t
57db96d56Sopenharmony_ci#include "pycore_pymem.h"         // _Py_tracemalloc_config
67db96d56Sopenharmony_ci#include "pycore_runtime.h"       // _Py_ID()
77db96d56Sopenharmony_ci#include "pycore_traceback.h"
87db96d56Sopenharmony_ci#include <pycore_frame.h>
97db96d56Sopenharmony_ci
107db96d56Sopenharmony_ci#include <stdlib.h>               // malloc()
117db96d56Sopenharmony_ci
127db96d56Sopenharmony_ci#include "clinic/_tracemalloc.c.h"
137db96d56Sopenharmony_ci
147db96d56Sopenharmony_ci/*[clinic input]
157db96d56Sopenharmony_cimodule _tracemalloc
167db96d56Sopenharmony_ci[clinic start generated code]*/
177db96d56Sopenharmony_ci/*[clinic end generated code: output=da39a3ee5e6b4b0d input=708a98302fc46e5f]*/
187db96d56Sopenharmony_ci
197db96d56Sopenharmony_ci_Py_DECLARE_STR(anon_unknown, "<unknown>");
207db96d56Sopenharmony_ci
217db96d56Sopenharmony_ci/* Trace memory blocks allocated by PyMem_RawMalloc() */
227db96d56Sopenharmony_ci#define TRACE_RAW_MALLOC
237db96d56Sopenharmony_ci
247db96d56Sopenharmony_ci/* Forward declaration */
257db96d56Sopenharmony_cistatic void tracemalloc_stop(void);
267db96d56Sopenharmony_cistatic void* raw_malloc(size_t size);
277db96d56Sopenharmony_cistatic void raw_free(void *ptr);
287db96d56Sopenharmony_ci
297db96d56Sopenharmony_ci#ifdef Py_DEBUG
307db96d56Sopenharmony_ci#  define TRACE_DEBUG
317db96d56Sopenharmony_ci#endif
327db96d56Sopenharmony_ci
337db96d56Sopenharmony_ci#define TO_PTR(key) ((const void *)(uintptr_t)(key))
347db96d56Sopenharmony_ci#define FROM_PTR(key) ((uintptr_t)(key))
357db96d56Sopenharmony_ci
367db96d56Sopenharmony_ci/* Protected by the GIL */
377db96d56Sopenharmony_cistatic struct {
387db96d56Sopenharmony_ci    PyMemAllocatorEx mem;
397db96d56Sopenharmony_ci    PyMemAllocatorEx raw;
407db96d56Sopenharmony_ci    PyMemAllocatorEx obj;
417db96d56Sopenharmony_ci} allocators;
427db96d56Sopenharmony_ci
437db96d56Sopenharmony_ci
447db96d56Sopenharmony_ci#if defined(TRACE_RAW_MALLOC)
457db96d56Sopenharmony_ci/* This lock is needed because tracemalloc_free() is called without
467db96d56Sopenharmony_ci   the GIL held from PyMem_RawFree(). It cannot acquire the lock because it
477db96d56Sopenharmony_ci   would introduce a deadlock in _PyThreadState_DeleteCurrent(). */
487db96d56Sopenharmony_cistatic PyThread_type_lock tables_lock;
497db96d56Sopenharmony_ci#  define TABLES_LOCK() PyThread_acquire_lock(tables_lock, 1)
507db96d56Sopenharmony_ci#  define TABLES_UNLOCK() PyThread_release_lock(tables_lock)
517db96d56Sopenharmony_ci#else
527db96d56Sopenharmony_ci   /* variables are protected by the GIL */
537db96d56Sopenharmony_ci#  define TABLES_LOCK()
547db96d56Sopenharmony_ci#  define TABLES_UNLOCK()
557db96d56Sopenharmony_ci#endif
567db96d56Sopenharmony_ci
577db96d56Sopenharmony_ci
587db96d56Sopenharmony_ci#define DEFAULT_DOMAIN 0
597db96d56Sopenharmony_ci
607db96d56Sopenharmony_ci/* Pack the frame_t structure to reduce the memory footprint on 64-bit
617db96d56Sopenharmony_ci   architectures: 12 bytes instead of 16. */
627db96d56Sopenharmony_citypedef struct
637db96d56Sopenharmony_ci#ifdef __GNUC__
647db96d56Sopenharmony_ci__attribute__((packed))
657db96d56Sopenharmony_ci#elif defined(_MSC_VER)
667db96d56Sopenharmony_ci#pragma pack(push, 4)
677db96d56Sopenharmony_ci#endif
687db96d56Sopenharmony_ci{
697db96d56Sopenharmony_ci    /* filename cannot be NULL: "<unknown>" is used if the Python frame
707db96d56Sopenharmony_ci       filename is NULL */
717db96d56Sopenharmony_ci    PyObject *filename;
727db96d56Sopenharmony_ci    unsigned int lineno;
737db96d56Sopenharmony_ci} frame_t;
747db96d56Sopenharmony_ci#ifdef _MSC_VER
757db96d56Sopenharmony_ci#pragma pack(pop)
767db96d56Sopenharmony_ci#endif
777db96d56Sopenharmony_ci
787db96d56Sopenharmony_ci
797db96d56Sopenharmony_citypedef struct {
807db96d56Sopenharmony_ci    Py_uhash_t hash;
817db96d56Sopenharmony_ci    /* Number of frames stored */
827db96d56Sopenharmony_ci    uint16_t nframe;
837db96d56Sopenharmony_ci    /* Total number of frames the traceback had */
847db96d56Sopenharmony_ci    uint16_t total_nframe;
857db96d56Sopenharmony_ci    frame_t frames[1];
867db96d56Sopenharmony_ci} traceback_t;
877db96d56Sopenharmony_ci
887db96d56Sopenharmony_ci#define TRACEBACK_SIZE(NFRAME) \
897db96d56Sopenharmony_ci        (sizeof(traceback_t) + sizeof(frame_t) * (NFRAME - 1))
907db96d56Sopenharmony_ci
917db96d56Sopenharmony_ci/* The maximum number of frames is either:
927db96d56Sopenharmony_ci - The maximum number of frames we can store in `traceback_t.nframe`
937db96d56Sopenharmony_ci - The maximum memory size_t we can allocate */
947db96d56Sopenharmony_cistatic const unsigned long MAX_NFRAME = Py_MIN(UINT16_MAX, ((SIZE_MAX - sizeof(traceback_t)) / sizeof(frame_t) + 1));
957db96d56Sopenharmony_ci
967db96d56Sopenharmony_ci
977db96d56Sopenharmony_cistatic traceback_t tracemalloc_empty_traceback;
987db96d56Sopenharmony_ci
997db96d56Sopenharmony_ci/* Trace of a memory block */
1007db96d56Sopenharmony_citypedef struct {
1017db96d56Sopenharmony_ci    /* Size of the memory block in bytes */
1027db96d56Sopenharmony_ci    size_t size;
1037db96d56Sopenharmony_ci
1047db96d56Sopenharmony_ci    /* Traceback where the memory block was allocated */
1057db96d56Sopenharmony_ci    traceback_t *traceback;
1067db96d56Sopenharmony_ci} trace_t;
1077db96d56Sopenharmony_ci
1087db96d56Sopenharmony_ci
1097db96d56Sopenharmony_ci/* Size in bytes of currently traced memory.
1107db96d56Sopenharmony_ci   Protected by TABLES_LOCK(). */
1117db96d56Sopenharmony_cistatic size_t tracemalloc_traced_memory = 0;
1127db96d56Sopenharmony_ci
1137db96d56Sopenharmony_ci/* Peak size in bytes of traced memory.
1147db96d56Sopenharmony_ci   Protected by TABLES_LOCK(). */
1157db96d56Sopenharmony_cistatic size_t tracemalloc_peak_traced_memory = 0;
1167db96d56Sopenharmony_ci
1177db96d56Sopenharmony_ci/* Hash table used as a set to intern filenames:
1187db96d56Sopenharmony_ci   PyObject* => PyObject*.
1197db96d56Sopenharmony_ci   Protected by the GIL */
1207db96d56Sopenharmony_cistatic _Py_hashtable_t *tracemalloc_filenames = NULL;
1217db96d56Sopenharmony_ci
1227db96d56Sopenharmony_ci/* Buffer to store a new traceback in traceback_new().
1237db96d56Sopenharmony_ci   Protected by the GIL. */
1247db96d56Sopenharmony_cistatic traceback_t *tracemalloc_traceback = NULL;
1257db96d56Sopenharmony_ci
1267db96d56Sopenharmony_ci/* Hash table used as a set to intern tracebacks:
1277db96d56Sopenharmony_ci   traceback_t* => traceback_t*
1287db96d56Sopenharmony_ci   Protected by the GIL */
1297db96d56Sopenharmony_cistatic _Py_hashtable_t *tracemalloc_tracebacks = NULL;
1307db96d56Sopenharmony_ci
1317db96d56Sopenharmony_ci/* pointer (void*) => trace (trace_t*).
1327db96d56Sopenharmony_ci   Protected by TABLES_LOCK(). */
1337db96d56Sopenharmony_cistatic _Py_hashtable_t *tracemalloc_traces = NULL;
1347db96d56Sopenharmony_ci
1357db96d56Sopenharmony_ci/* domain (unsigned int) => traces (_Py_hashtable_t).
1367db96d56Sopenharmony_ci   Protected by TABLES_LOCK(). */
1377db96d56Sopenharmony_cistatic _Py_hashtable_t *tracemalloc_domains = NULL;
1387db96d56Sopenharmony_ci
1397db96d56Sopenharmony_ci
1407db96d56Sopenharmony_ci#ifdef TRACE_DEBUG
1417db96d56Sopenharmony_cistatic void
1427db96d56Sopenharmony_citracemalloc_error(const char *format, ...)
1437db96d56Sopenharmony_ci{
1447db96d56Sopenharmony_ci    va_list ap;
1457db96d56Sopenharmony_ci    fprintf(stderr, "tracemalloc: ");
1467db96d56Sopenharmony_ci    va_start(ap, format);
1477db96d56Sopenharmony_ci    vfprintf(stderr, format, ap);
1487db96d56Sopenharmony_ci    va_end(ap);
1497db96d56Sopenharmony_ci    fprintf(stderr, "\n");
1507db96d56Sopenharmony_ci    fflush(stderr);
1517db96d56Sopenharmony_ci}
1527db96d56Sopenharmony_ci#endif
1537db96d56Sopenharmony_ci
1547db96d56Sopenharmony_ci
1557db96d56Sopenharmony_ci#if defined(TRACE_RAW_MALLOC)
1567db96d56Sopenharmony_ci#define REENTRANT_THREADLOCAL
1577db96d56Sopenharmony_ci
1587db96d56Sopenharmony_cistatic Py_tss_t tracemalloc_reentrant_key = Py_tss_NEEDS_INIT;
1597db96d56Sopenharmony_ci
1607db96d56Sopenharmony_ci/* Any non-NULL pointer can be used */
1617db96d56Sopenharmony_ci#define REENTRANT Py_True
1627db96d56Sopenharmony_ci
1637db96d56Sopenharmony_cistatic int
1647db96d56Sopenharmony_ciget_reentrant(void)
1657db96d56Sopenharmony_ci{
1667db96d56Sopenharmony_ci    void *ptr;
1677db96d56Sopenharmony_ci
1687db96d56Sopenharmony_ci    assert(PyThread_tss_is_created(&tracemalloc_reentrant_key));
1697db96d56Sopenharmony_ci    ptr = PyThread_tss_get(&tracemalloc_reentrant_key);
1707db96d56Sopenharmony_ci    if (ptr != NULL) {
1717db96d56Sopenharmony_ci        assert(ptr == REENTRANT);
1727db96d56Sopenharmony_ci        return 1;
1737db96d56Sopenharmony_ci    }
1747db96d56Sopenharmony_ci    else
1757db96d56Sopenharmony_ci        return 0;
1767db96d56Sopenharmony_ci}
1777db96d56Sopenharmony_ci
1787db96d56Sopenharmony_cistatic void
1797db96d56Sopenharmony_ciset_reentrant(int reentrant)
1807db96d56Sopenharmony_ci{
1817db96d56Sopenharmony_ci    assert(reentrant == 0 || reentrant == 1);
1827db96d56Sopenharmony_ci    assert(PyThread_tss_is_created(&tracemalloc_reentrant_key));
1837db96d56Sopenharmony_ci
1847db96d56Sopenharmony_ci    if (reentrant) {
1857db96d56Sopenharmony_ci        assert(!get_reentrant());
1867db96d56Sopenharmony_ci        PyThread_tss_set(&tracemalloc_reentrant_key, REENTRANT);
1877db96d56Sopenharmony_ci    }
1887db96d56Sopenharmony_ci    else {
1897db96d56Sopenharmony_ci        assert(get_reentrant());
1907db96d56Sopenharmony_ci        PyThread_tss_set(&tracemalloc_reentrant_key, NULL);
1917db96d56Sopenharmony_ci    }
1927db96d56Sopenharmony_ci}
1937db96d56Sopenharmony_ci
1947db96d56Sopenharmony_ci#else
1957db96d56Sopenharmony_ci
1967db96d56Sopenharmony_ci/* TRACE_RAW_MALLOC not defined: variable protected by the GIL */
1977db96d56Sopenharmony_cistatic int tracemalloc_reentrant = 0;
1987db96d56Sopenharmony_ci
1997db96d56Sopenharmony_cistatic int
2007db96d56Sopenharmony_ciget_reentrant(void)
2017db96d56Sopenharmony_ci{
2027db96d56Sopenharmony_ci    return tracemalloc_reentrant;
2037db96d56Sopenharmony_ci}
2047db96d56Sopenharmony_ci
2057db96d56Sopenharmony_cistatic void
2067db96d56Sopenharmony_ciset_reentrant(int reentrant)
2077db96d56Sopenharmony_ci{
2087db96d56Sopenharmony_ci    assert(reentrant != tracemalloc_reentrant);
2097db96d56Sopenharmony_ci    tracemalloc_reentrant = reentrant;
2107db96d56Sopenharmony_ci}
2117db96d56Sopenharmony_ci#endif
2127db96d56Sopenharmony_ci
2137db96d56Sopenharmony_ci
2147db96d56Sopenharmony_cistatic Py_uhash_t
2157db96d56Sopenharmony_cihashtable_hash_pyobject(const void *key)
2167db96d56Sopenharmony_ci{
2177db96d56Sopenharmony_ci    PyObject *obj = (PyObject *)key;
2187db96d56Sopenharmony_ci    return PyObject_Hash(obj);
2197db96d56Sopenharmony_ci}
2207db96d56Sopenharmony_ci
2217db96d56Sopenharmony_ci
2227db96d56Sopenharmony_cistatic int
2237db96d56Sopenharmony_cihashtable_compare_unicode(const void *key1, const void *key2)
2247db96d56Sopenharmony_ci{
2257db96d56Sopenharmony_ci    PyObject *obj1 = (PyObject *)key1;
2267db96d56Sopenharmony_ci    PyObject *obj2 = (PyObject *)key2;
2277db96d56Sopenharmony_ci    if (obj1 != NULL && obj2 != NULL) {
2287db96d56Sopenharmony_ci        return (PyUnicode_Compare(obj1, obj2) == 0);
2297db96d56Sopenharmony_ci    }
2307db96d56Sopenharmony_ci    else {
2317db96d56Sopenharmony_ci        return obj1 == obj2;
2327db96d56Sopenharmony_ci    }
2337db96d56Sopenharmony_ci}
2347db96d56Sopenharmony_ci
2357db96d56Sopenharmony_ci
2367db96d56Sopenharmony_cistatic Py_uhash_t
2377db96d56Sopenharmony_cihashtable_hash_uint(const void *key_raw)
2387db96d56Sopenharmony_ci{
2397db96d56Sopenharmony_ci    unsigned int key = (unsigned int)FROM_PTR(key_raw);
2407db96d56Sopenharmony_ci    return (Py_uhash_t)key;
2417db96d56Sopenharmony_ci}
2427db96d56Sopenharmony_ci
2437db96d56Sopenharmony_ci
2447db96d56Sopenharmony_cistatic _Py_hashtable_t *
2457db96d56Sopenharmony_cihashtable_new(_Py_hashtable_hash_func hash_func,
2467db96d56Sopenharmony_ci              _Py_hashtable_compare_func compare_func,
2477db96d56Sopenharmony_ci              _Py_hashtable_destroy_func key_destroy_func,
2487db96d56Sopenharmony_ci              _Py_hashtable_destroy_func value_destroy_func)
2497db96d56Sopenharmony_ci{
2507db96d56Sopenharmony_ci    _Py_hashtable_allocator_t hashtable_alloc = {malloc, free};
2517db96d56Sopenharmony_ci    return _Py_hashtable_new_full(hash_func, compare_func,
2527db96d56Sopenharmony_ci                                  key_destroy_func, value_destroy_func,
2537db96d56Sopenharmony_ci                                  &hashtable_alloc);
2547db96d56Sopenharmony_ci}
2557db96d56Sopenharmony_ci
2567db96d56Sopenharmony_ci
2577db96d56Sopenharmony_cistatic void*
2587db96d56Sopenharmony_ciraw_malloc(size_t size)
2597db96d56Sopenharmony_ci{
2607db96d56Sopenharmony_ci    return allocators.raw.malloc(allocators.raw.ctx, size);
2617db96d56Sopenharmony_ci}
2627db96d56Sopenharmony_ci
2637db96d56Sopenharmony_cistatic void
2647db96d56Sopenharmony_ciraw_free(void *ptr)
2657db96d56Sopenharmony_ci{
2667db96d56Sopenharmony_ci    allocators.raw.free(allocators.raw.ctx, ptr);
2677db96d56Sopenharmony_ci}
2687db96d56Sopenharmony_ci
2697db96d56Sopenharmony_ci
2707db96d56Sopenharmony_cistatic Py_uhash_t
2717db96d56Sopenharmony_cihashtable_hash_traceback(const void *key)
2727db96d56Sopenharmony_ci{
2737db96d56Sopenharmony_ci    const traceback_t *traceback = (const traceback_t *)key;
2747db96d56Sopenharmony_ci    return traceback->hash;
2757db96d56Sopenharmony_ci}
2767db96d56Sopenharmony_ci
2777db96d56Sopenharmony_ci
2787db96d56Sopenharmony_cistatic int
2797db96d56Sopenharmony_cihashtable_compare_traceback(const void *key1, const void *key2)
2807db96d56Sopenharmony_ci{
2817db96d56Sopenharmony_ci    const traceback_t *traceback1 = (const traceback_t *)key1;
2827db96d56Sopenharmony_ci    const traceback_t *traceback2 = (const traceback_t *)key2;
2837db96d56Sopenharmony_ci
2847db96d56Sopenharmony_ci    if (traceback1->nframe != traceback2->nframe) {
2857db96d56Sopenharmony_ci        return 0;
2867db96d56Sopenharmony_ci    }
2877db96d56Sopenharmony_ci    if (traceback1->total_nframe != traceback2->total_nframe) {
2887db96d56Sopenharmony_ci        return 0;
2897db96d56Sopenharmony_ci    }
2907db96d56Sopenharmony_ci
2917db96d56Sopenharmony_ci    for (int i=0; i < traceback1->nframe; i++) {
2927db96d56Sopenharmony_ci        const frame_t *frame1 = &traceback1->frames[i];
2937db96d56Sopenharmony_ci        const frame_t *frame2 = &traceback2->frames[i];
2947db96d56Sopenharmony_ci
2957db96d56Sopenharmony_ci        if (frame1->lineno != frame2->lineno) {
2967db96d56Sopenharmony_ci            return 0;
2977db96d56Sopenharmony_ci        }
2987db96d56Sopenharmony_ci        if (frame1->filename != frame2->filename) {
2997db96d56Sopenharmony_ci            assert(PyUnicode_Compare(frame1->filename, frame2->filename) != 0);
3007db96d56Sopenharmony_ci            return 0;
3017db96d56Sopenharmony_ci        }
3027db96d56Sopenharmony_ci    }
3037db96d56Sopenharmony_ci    return 1;
3047db96d56Sopenharmony_ci}
3057db96d56Sopenharmony_ci
3067db96d56Sopenharmony_ci
3077db96d56Sopenharmony_cistatic void
3087db96d56Sopenharmony_citracemalloc_get_frame(_PyInterpreterFrame *pyframe, frame_t *frame)
3097db96d56Sopenharmony_ci{
3107db96d56Sopenharmony_ci    frame->filename = &_Py_STR(anon_unknown);
3117db96d56Sopenharmony_ci    int lineno = _PyInterpreterFrame_GetLine(pyframe);
3127db96d56Sopenharmony_ci    if (lineno < 0) {
3137db96d56Sopenharmony_ci        lineno = 0;
3147db96d56Sopenharmony_ci    }
3157db96d56Sopenharmony_ci    frame->lineno = (unsigned int)lineno;
3167db96d56Sopenharmony_ci
3177db96d56Sopenharmony_ci    PyObject *filename = pyframe->f_code->co_filename;
3187db96d56Sopenharmony_ci
3197db96d56Sopenharmony_ci    if (filename == NULL) {
3207db96d56Sopenharmony_ci#ifdef TRACE_DEBUG
3217db96d56Sopenharmony_ci        tracemalloc_error("failed to get the filename of the code object");
3227db96d56Sopenharmony_ci#endif
3237db96d56Sopenharmony_ci        return;
3247db96d56Sopenharmony_ci    }
3257db96d56Sopenharmony_ci
3267db96d56Sopenharmony_ci    if (!PyUnicode_Check(filename)) {
3277db96d56Sopenharmony_ci#ifdef TRACE_DEBUG
3287db96d56Sopenharmony_ci        tracemalloc_error("filename is not a unicode string");
3297db96d56Sopenharmony_ci#endif
3307db96d56Sopenharmony_ci        return;
3317db96d56Sopenharmony_ci    }
3327db96d56Sopenharmony_ci    if (!PyUnicode_IS_READY(filename)) {
3337db96d56Sopenharmony_ci        /* Don't make a Unicode string ready to avoid reentrant calls
3347db96d56Sopenharmony_ci           to tracemalloc_malloc() or tracemalloc_realloc() */
3357db96d56Sopenharmony_ci#ifdef TRACE_DEBUG
3367db96d56Sopenharmony_ci        tracemalloc_error("filename is not a ready unicode string");
3377db96d56Sopenharmony_ci#endif
3387db96d56Sopenharmony_ci        return;
3397db96d56Sopenharmony_ci    }
3407db96d56Sopenharmony_ci
3417db96d56Sopenharmony_ci    /* intern the filename */
3427db96d56Sopenharmony_ci    _Py_hashtable_entry_t *entry;
3437db96d56Sopenharmony_ci    entry = _Py_hashtable_get_entry(tracemalloc_filenames, filename);
3447db96d56Sopenharmony_ci    if (entry != NULL) {
3457db96d56Sopenharmony_ci        filename = (PyObject *)entry->key;
3467db96d56Sopenharmony_ci    }
3477db96d56Sopenharmony_ci    else {
3487db96d56Sopenharmony_ci        /* tracemalloc_filenames is responsible to keep a reference
3497db96d56Sopenharmony_ci           to the filename */
3507db96d56Sopenharmony_ci        Py_INCREF(filename);
3517db96d56Sopenharmony_ci        if (_Py_hashtable_set(tracemalloc_filenames, filename, NULL) < 0) {
3527db96d56Sopenharmony_ci            Py_DECREF(filename);
3537db96d56Sopenharmony_ci#ifdef TRACE_DEBUG
3547db96d56Sopenharmony_ci            tracemalloc_error("failed to intern the filename");
3557db96d56Sopenharmony_ci#endif
3567db96d56Sopenharmony_ci            return;
3577db96d56Sopenharmony_ci        }
3587db96d56Sopenharmony_ci    }
3597db96d56Sopenharmony_ci
3607db96d56Sopenharmony_ci    /* the tracemalloc_filenames table keeps a reference to the filename */
3617db96d56Sopenharmony_ci    frame->filename = filename;
3627db96d56Sopenharmony_ci}
3637db96d56Sopenharmony_ci
3647db96d56Sopenharmony_ci
3657db96d56Sopenharmony_cistatic Py_uhash_t
3667db96d56Sopenharmony_citraceback_hash(traceback_t *traceback)
3677db96d56Sopenharmony_ci{
3687db96d56Sopenharmony_ci    /* code based on tuplehash() of Objects/tupleobject.c */
3697db96d56Sopenharmony_ci    Py_uhash_t x, y;  /* Unsigned for defined overflow behavior. */
3707db96d56Sopenharmony_ci    int len = traceback->nframe;
3717db96d56Sopenharmony_ci    Py_uhash_t mult = _PyHASH_MULTIPLIER;
3727db96d56Sopenharmony_ci    frame_t *frame;
3737db96d56Sopenharmony_ci
3747db96d56Sopenharmony_ci    x = 0x345678UL;
3757db96d56Sopenharmony_ci    frame = traceback->frames;
3767db96d56Sopenharmony_ci    while (--len >= 0) {
3777db96d56Sopenharmony_ci        y = (Py_uhash_t)PyObject_Hash(frame->filename);
3787db96d56Sopenharmony_ci        y ^= (Py_uhash_t)frame->lineno;
3797db96d56Sopenharmony_ci        frame++;
3807db96d56Sopenharmony_ci
3817db96d56Sopenharmony_ci        x = (x ^ y) * mult;
3827db96d56Sopenharmony_ci        /* the cast might truncate len; that doesn't change hash stability */
3837db96d56Sopenharmony_ci        mult += (Py_uhash_t)(82520UL + len + len);
3847db96d56Sopenharmony_ci    }
3857db96d56Sopenharmony_ci    x ^= traceback->total_nframe;
3867db96d56Sopenharmony_ci    x += 97531UL;
3877db96d56Sopenharmony_ci    return x;
3887db96d56Sopenharmony_ci}
3897db96d56Sopenharmony_ci
3907db96d56Sopenharmony_ci
3917db96d56Sopenharmony_cistatic void
3927db96d56Sopenharmony_citraceback_get_frames(traceback_t *traceback)
3937db96d56Sopenharmony_ci{
3947db96d56Sopenharmony_ci    PyThreadState *tstate = PyGILState_GetThisThreadState();
3957db96d56Sopenharmony_ci    if (tstate == NULL) {
3967db96d56Sopenharmony_ci#ifdef TRACE_DEBUG
3977db96d56Sopenharmony_ci        tracemalloc_error("failed to get the current thread state");
3987db96d56Sopenharmony_ci#endif
3997db96d56Sopenharmony_ci        return;
4007db96d56Sopenharmony_ci    }
4017db96d56Sopenharmony_ci
4027db96d56Sopenharmony_ci    _PyInterpreterFrame *pyframe = tstate->cframe->current_frame;
4037db96d56Sopenharmony_ci    for (;;) {
4047db96d56Sopenharmony_ci        while (pyframe && _PyFrame_IsIncomplete(pyframe)) {
4057db96d56Sopenharmony_ci            pyframe = pyframe->previous;
4067db96d56Sopenharmony_ci        }
4077db96d56Sopenharmony_ci        if (pyframe == NULL) {
4087db96d56Sopenharmony_ci            break;
4097db96d56Sopenharmony_ci        }
4107db96d56Sopenharmony_ci        if (traceback->nframe < _Py_tracemalloc_config.max_nframe) {
4117db96d56Sopenharmony_ci            tracemalloc_get_frame(pyframe, &traceback->frames[traceback->nframe]);
4127db96d56Sopenharmony_ci            assert(traceback->frames[traceback->nframe].filename != NULL);
4137db96d56Sopenharmony_ci            traceback->nframe++;
4147db96d56Sopenharmony_ci        }
4157db96d56Sopenharmony_ci        if (traceback->total_nframe < UINT16_MAX) {
4167db96d56Sopenharmony_ci            traceback->total_nframe++;
4177db96d56Sopenharmony_ci        }
4187db96d56Sopenharmony_ci
4197db96d56Sopenharmony_ci        pyframe = pyframe->previous;
4207db96d56Sopenharmony_ci    }
4217db96d56Sopenharmony_ci}
4227db96d56Sopenharmony_ci
4237db96d56Sopenharmony_ci
4247db96d56Sopenharmony_cistatic traceback_t *
4257db96d56Sopenharmony_citraceback_new(void)
4267db96d56Sopenharmony_ci{
4277db96d56Sopenharmony_ci    traceback_t *traceback;
4287db96d56Sopenharmony_ci    _Py_hashtable_entry_t *entry;
4297db96d56Sopenharmony_ci
4307db96d56Sopenharmony_ci    assert(PyGILState_Check());
4317db96d56Sopenharmony_ci
4327db96d56Sopenharmony_ci    /* get frames */
4337db96d56Sopenharmony_ci    traceback = tracemalloc_traceback;
4347db96d56Sopenharmony_ci    traceback->nframe = 0;
4357db96d56Sopenharmony_ci    traceback->total_nframe = 0;
4367db96d56Sopenharmony_ci    traceback_get_frames(traceback);
4377db96d56Sopenharmony_ci    if (traceback->nframe == 0)
4387db96d56Sopenharmony_ci        return &tracemalloc_empty_traceback;
4397db96d56Sopenharmony_ci    traceback->hash = traceback_hash(traceback);
4407db96d56Sopenharmony_ci
4417db96d56Sopenharmony_ci    /* intern the traceback */
4427db96d56Sopenharmony_ci    entry = _Py_hashtable_get_entry(tracemalloc_tracebacks, traceback);
4437db96d56Sopenharmony_ci    if (entry != NULL) {
4447db96d56Sopenharmony_ci        traceback = (traceback_t *)entry->key;
4457db96d56Sopenharmony_ci    }
4467db96d56Sopenharmony_ci    else {
4477db96d56Sopenharmony_ci        traceback_t *copy;
4487db96d56Sopenharmony_ci        size_t traceback_size;
4497db96d56Sopenharmony_ci
4507db96d56Sopenharmony_ci        traceback_size = TRACEBACK_SIZE(traceback->nframe);
4517db96d56Sopenharmony_ci
4527db96d56Sopenharmony_ci        copy = raw_malloc(traceback_size);
4537db96d56Sopenharmony_ci        if (copy == NULL) {
4547db96d56Sopenharmony_ci#ifdef TRACE_DEBUG
4557db96d56Sopenharmony_ci            tracemalloc_error("failed to intern the traceback: malloc failed");
4567db96d56Sopenharmony_ci#endif
4577db96d56Sopenharmony_ci            return NULL;
4587db96d56Sopenharmony_ci        }
4597db96d56Sopenharmony_ci        memcpy(copy, traceback, traceback_size);
4607db96d56Sopenharmony_ci
4617db96d56Sopenharmony_ci        if (_Py_hashtable_set(tracemalloc_tracebacks, copy, NULL) < 0) {
4627db96d56Sopenharmony_ci            raw_free(copy);
4637db96d56Sopenharmony_ci#ifdef TRACE_DEBUG
4647db96d56Sopenharmony_ci            tracemalloc_error("failed to intern the traceback: putdata failed");
4657db96d56Sopenharmony_ci#endif
4667db96d56Sopenharmony_ci            return NULL;
4677db96d56Sopenharmony_ci        }
4687db96d56Sopenharmony_ci        traceback = copy;
4697db96d56Sopenharmony_ci    }
4707db96d56Sopenharmony_ci    return traceback;
4717db96d56Sopenharmony_ci}
4727db96d56Sopenharmony_ci
4737db96d56Sopenharmony_ci
4747db96d56Sopenharmony_cistatic _Py_hashtable_t*
4757db96d56Sopenharmony_citracemalloc_create_traces_table(void)
4767db96d56Sopenharmony_ci{
4777db96d56Sopenharmony_ci    return hashtable_new(_Py_hashtable_hash_ptr,
4787db96d56Sopenharmony_ci                         _Py_hashtable_compare_direct,
4797db96d56Sopenharmony_ci                         NULL, raw_free);
4807db96d56Sopenharmony_ci}
4817db96d56Sopenharmony_ci
4827db96d56Sopenharmony_ci
4837db96d56Sopenharmony_cistatic _Py_hashtable_t*
4847db96d56Sopenharmony_citracemalloc_create_domains_table(void)
4857db96d56Sopenharmony_ci{
4867db96d56Sopenharmony_ci    return hashtable_new(hashtable_hash_uint,
4877db96d56Sopenharmony_ci                         _Py_hashtable_compare_direct,
4887db96d56Sopenharmony_ci                         NULL,
4897db96d56Sopenharmony_ci                         (_Py_hashtable_destroy_func)_Py_hashtable_destroy);
4907db96d56Sopenharmony_ci}
4917db96d56Sopenharmony_ci
4927db96d56Sopenharmony_ci
4937db96d56Sopenharmony_cistatic _Py_hashtable_t*
4947db96d56Sopenharmony_citracemalloc_get_traces_table(unsigned int domain)
4957db96d56Sopenharmony_ci{
4967db96d56Sopenharmony_ci    if (domain == DEFAULT_DOMAIN) {
4977db96d56Sopenharmony_ci        return tracemalloc_traces;
4987db96d56Sopenharmony_ci    }
4997db96d56Sopenharmony_ci    else {
5007db96d56Sopenharmony_ci        return _Py_hashtable_get(tracemalloc_domains, TO_PTR(domain));
5017db96d56Sopenharmony_ci    }
5027db96d56Sopenharmony_ci}
5037db96d56Sopenharmony_ci
5047db96d56Sopenharmony_ci
5057db96d56Sopenharmony_cistatic void
5067db96d56Sopenharmony_citracemalloc_remove_trace(unsigned int domain, uintptr_t ptr)
5077db96d56Sopenharmony_ci{
5087db96d56Sopenharmony_ci    assert(_Py_tracemalloc_config.tracing);
5097db96d56Sopenharmony_ci
5107db96d56Sopenharmony_ci    _Py_hashtable_t *traces = tracemalloc_get_traces_table(domain);
5117db96d56Sopenharmony_ci    if (!traces) {
5127db96d56Sopenharmony_ci        return;
5137db96d56Sopenharmony_ci    }
5147db96d56Sopenharmony_ci
5157db96d56Sopenharmony_ci    trace_t *trace = _Py_hashtable_steal(traces, TO_PTR(ptr));
5167db96d56Sopenharmony_ci    if (!trace) {
5177db96d56Sopenharmony_ci        return;
5187db96d56Sopenharmony_ci    }
5197db96d56Sopenharmony_ci    assert(tracemalloc_traced_memory >= trace->size);
5207db96d56Sopenharmony_ci    tracemalloc_traced_memory -= trace->size;
5217db96d56Sopenharmony_ci    raw_free(trace);
5227db96d56Sopenharmony_ci}
5237db96d56Sopenharmony_ci
5247db96d56Sopenharmony_ci#define REMOVE_TRACE(ptr) \
5257db96d56Sopenharmony_ci            tracemalloc_remove_trace(DEFAULT_DOMAIN, (uintptr_t)(ptr))
5267db96d56Sopenharmony_ci
5277db96d56Sopenharmony_ci
5287db96d56Sopenharmony_cistatic int
5297db96d56Sopenharmony_citracemalloc_add_trace(unsigned int domain, uintptr_t ptr,
5307db96d56Sopenharmony_ci                      size_t size)
5317db96d56Sopenharmony_ci{
5327db96d56Sopenharmony_ci    assert(_Py_tracemalloc_config.tracing);
5337db96d56Sopenharmony_ci
5347db96d56Sopenharmony_ci    traceback_t *traceback = traceback_new();
5357db96d56Sopenharmony_ci    if (traceback == NULL) {
5367db96d56Sopenharmony_ci        return -1;
5377db96d56Sopenharmony_ci    }
5387db96d56Sopenharmony_ci
5397db96d56Sopenharmony_ci    _Py_hashtable_t *traces = tracemalloc_get_traces_table(domain);
5407db96d56Sopenharmony_ci    if (traces == NULL) {
5417db96d56Sopenharmony_ci        traces = tracemalloc_create_traces_table();
5427db96d56Sopenharmony_ci        if (traces == NULL) {
5437db96d56Sopenharmony_ci            return -1;
5447db96d56Sopenharmony_ci        }
5457db96d56Sopenharmony_ci
5467db96d56Sopenharmony_ci        if (_Py_hashtable_set(tracemalloc_domains, TO_PTR(domain), traces) < 0) {
5477db96d56Sopenharmony_ci            _Py_hashtable_destroy(traces);
5487db96d56Sopenharmony_ci            return -1;
5497db96d56Sopenharmony_ci        }
5507db96d56Sopenharmony_ci    }
5517db96d56Sopenharmony_ci
5527db96d56Sopenharmony_ci    trace_t *trace = _Py_hashtable_get(traces, TO_PTR(ptr));
5537db96d56Sopenharmony_ci    if (trace != NULL) {
5547db96d56Sopenharmony_ci        /* the memory block is already tracked */
5557db96d56Sopenharmony_ci        assert(tracemalloc_traced_memory >= trace->size);
5567db96d56Sopenharmony_ci        tracemalloc_traced_memory -= trace->size;
5577db96d56Sopenharmony_ci
5587db96d56Sopenharmony_ci        trace->size = size;
5597db96d56Sopenharmony_ci        trace->traceback = traceback;
5607db96d56Sopenharmony_ci    }
5617db96d56Sopenharmony_ci    else {
5627db96d56Sopenharmony_ci        trace = raw_malloc(sizeof(trace_t));
5637db96d56Sopenharmony_ci        if (trace == NULL) {
5647db96d56Sopenharmony_ci            return -1;
5657db96d56Sopenharmony_ci        }
5667db96d56Sopenharmony_ci        trace->size = size;
5677db96d56Sopenharmony_ci        trace->traceback = traceback;
5687db96d56Sopenharmony_ci
5697db96d56Sopenharmony_ci        int res = _Py_hashtable_set(traces, TO_PTR(ptr), trace);
5707db96d56Sopenharmony_ci        if (res != 0) {
5717db96d56Sopenharmony_ci            raw_free(trace);
5727db96d56Sopenharmony_ci            return res;
5737db96d56Sopenharmony_ci        }
5747db96d56Sopenharmony_ci    }
5757db96d56Sopenharmony_ci
5767db96d56Sopenharmony_ci    assert(tracemalloc_traced_memory <= SIZE_MAX - size);
5777db96d56Sopenharmony_ci    tracemalloc_traced_memory += size;
5787db96d56Sopenharmony_ci    if (tracemalloc_traced_memory > tracemalloc_peak_traced_memory) {
5797db96d56Sopenharmony_ci        tracemalloc_peak_traced_memory = tracemalloc_traced_memory;
5807db96d56Sopenharmony_ci    }
5817db96d56Sopenharmony_ci    return 0;
5827db96d56Sopenharmony_ci}
5837db96d56Sopenharmony_ci
5847db96d56Sopenharmony_ci#define ADD_TRACE(ptr, size) \
5857db96d56Sopenharmony_ci            tracemalloc_add_trace(DEFAULT_DOMAIN, (uintptr_t)(ptr), size)
5867db96d56Sopenharmony_ci
5877db96d56Sopenharmony_ci
5887db96d56Sopenharmony_cistatic void*
5897db96d56Sopenharmony_citracemalloc_alloc(int use_calloc, void *ctx, size_t nelem, size_t elsize)
5907db96d56Sopenharmony_ci{
5917db96d56Sopenharmony_ci    PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx;
5927db96d56Sopenharmony_ci    void *ptr;
5937db96d56Sopenharmony_ci
5947db96d56Sopenharmony_ci    assert(elsize == 0 || nelem <= SIZE_MAX / elsize);
5957db96d56Sopenharmony_ci
5967db96d56Sopenharmony_ci    if (use_calloc)
5977db96d56Sopenharmony_ci        ptr = alloc->calloc(alloc->ctx, nelem, elsize);
5987db96d56Sopenharmony_ci    else
5997db96d56Sopenharmony_ci        ptr = alloc->malloc(alloc->ctx, nelem * elsize);
6007db96d56Sopenharmony_ci    if (ptr == NULL)
6017db96d56Sopenharmony_ci        return NULL;
6027db96d56Sopenharmony_ci
6037db96d56Sopenharmony_ci    TABLES_LOCK();
6047db96d56Sopenharmony_ci    if (ADD_TRACE(ptr, nelem * elsize) < 0) {
6057db96d56Sopenharmony_ci        /* Failed to allocate a trace for the new memory block */
6067db96d56Sopenharmony_ci        TABLES_UNLOCK();
6077db96d56Sopenharmony_ci        alloc->free(alloc->ctx, ptr);
6087db96d56Sopenharmony_ci        return NULL;
6097db96d56Sopenharmony_ci    }
6107db96d56Sopenharmony_ci    TABLES_UNLOCK();
6117db96d56Sopenharmony_ci    return ptr;
6127db96d56Sopenharmony_ci}
6137db96d56Sopenharmony_ci
6147db96d56Sopenharmony_ci
6157db96d56Sopenharmony_cistatic void*
6167db96d56Sopenharmony_citracemalloc_realloc(void *ctx, void *ptr, size_t new_size)
6177db96d56Sopenharmony_ci{
6187db96d56Sopenharmony_ci    PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx;
6197db96d56Sopenharmony_ci    void *ptr2;
6207db96d56Sopenharmony_ci
6217db96d56Sopenharmony_ci    ptr2 = alloc->realloc(alloc->ctx, ptr, new_size);
6227db96d56Sopenharmony_ci    if (ptr2 == NULL)
6237db96d56Sopenharmony_ci        return NULL;
6247db96d56Sopenharmony_ci
6257db96d56Sopenharmony_ci    if (ptr != NULL) {
6267db96d56Sopenharmony_ci        /* an existing memory block has been resized */
6277db96d56Sopenharmony_ci
6287db96d56Sopenharmony_ci        TABLES_LOCK();
6297db96d56Sopenharmony_ci
6307db96d56Sopenharmony_ci        /* tracemalloc_add_trace() updates the trace if there is already
6317db96d56Sopenharmony_ci           a trace at address ptr2 */
6327db96d56Sopenharmony_ci        if (ptr2 != ptr) {
6337db96d56Sopenharmony_ci            REMOVE_TRACE(ptr);
6347db96d56Sopenharmony_ci        }
6357db96d56Sopenharmony_ci
6367db96d56Sopenharmony_ci        if (ADD_TRACE(ptr2, new_size) < 0) {
6377db96d56Sopenharmony_ci            /* Memory allocation failed. The error cannot be reported to
6387db96d56Sopenharmony_ci               the caller, because realloc() may already have shrunk the
6397db96d56Sopenharmony_ci               memory block and so removed bytes.
6407db96d56Sopenharmony_ci
6417db96d56Sopenharmony_ci               This case is very unlikely: a hash entry has just been
6427db96d56Sopenharmony_ci               released, so the hash table should have at least one free entry.
6437db96d56Sopenharmony_ci
6447db96d56Sopenharmony_ci               The GIL and the table lock ensures that only one thread is
6457db96d56Sopenharmony_ci               allocating memory. */
6467db96d56Sopenharmony_ci            Py_FatalError("tracemalloc_realloc() failed to allocate a trace");
6477db96d56Sopenharmony_ci        }
6487db96d56Sopenharmony_ci        TABLES_UNLOCK();
6497db96d56Sopenharmony_ci    }
6507db96d56Sopenharmony_ci    else {
6517db96d56Sopenharmony_ci        /* new allocation */
6527db96d56Sopenharmony_ci
6537db96d56Sopenharmony_ci        TABLES_LOCK();
6547db96d56Sopenharmony_ci        if (ADD_TRACE(ptr2, new_size) < 0) {
6557db96d56Sopenharmony_ci            /* Failed to allocate a trace for the new memory block */
6567db96d56Sopenharmony_ci            TABLES_UNLOCK();
6577db96d56Sopenharmony_ci            alloc->free(alloc->ctx, ptr2);
6587db96d56Sopenharmony_ci            return NULL;
6597db96d56Sopenharmony_ci        }
6607db96d56Sopenharmony_ci        TABLES_UNLOCK();
6617db96d56Sopenharmony_ci    }
6627db96d56Sopenharmony_ci    return ptr2;
6637db96d56Sopenharmony_ci}
6647db96d56Sopenharmony_ci
6657db96d56Sopenharmony_ci
6667db96d56Sopenharmony_cistatic void
6677db96d56Sopenharmony_citracemalloc_free(void *ctx, void *ptr)
6687db96d56Sopenharmony_ci{
6697db96d56Sopenharmony_ci    PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx;
6707db96d56Sopenharmony_ci
6717db96d56Sopenharmony_ci    if (ptr == NULL)
6727db96d56Sopenharmony_ci        return;
6737db96d56Sopenharmony_ci
6747db96d56Sopenharmony_ci     /* GIL cannot be locked in PyMem_RawFree() because it would introduce
6757db96d56Sopenharmony_ci        a deadlock in _PyThreadState_DeleteCurrent(). */
6767db96d56Sopenharmony_ci
6777db96d56Sopenharmony_ci    alloc->free(alloc->ctx, ptr);
6787db96d56Sopenharmony_ci
6797db96d56Sopenharmony_ci    TABLES_LOCK();
6807db96d56Sopenharmony_ci    REMOVE_TRACE(ptr);
6817db96d56Sopenharmony_ci    TABLES_UNLOCK();
6827db96d56Sopenharmony_ci}
6837db96d56Sopenharmony_ci
6847db96d56Sopenharmony_ci
6857db96d56Sopenharmony_cistatic void*
6867db96d56Sopenharmony_citracemalloc_alloc_gil(int use_calloc, void *ctx, size_t nelem, size_t elsize)
6877db96d56Sopenharmony_ci{
6887db96d56Sopenharmony_ci    void *ptr;
6897db96d56Sopenharmony_ci
6907db96d56Sopenharmony_ci    if (get_reentrant()) {
6917db96d56Sopenharmony_ci        PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx;
6927db96d56Sopenharmony_ci        if (use_calloc)
6937db96d56Sopenharmony_ci            return alloc->calloc(alloc->ctx, nelem, elsize);
6947db96d56Sopenharmony_ci        else
6957db96d56Sopenharmony_ci            return alloc->malloc(alloc->ctx, nelem * elsize);
6967db96d56Sopenharmony_ci    }
6977db96d56Sopenharmony_ci
6987db96d56Sopenharmony_ci    /* Ignore reentrant call. PyObjet_Malloc() calls PyMem_Malloc() for
6997db96d56Sopenharmony_ci       allocations larger than 512 bytes, don't trace the same memory
7007db96d56Sopenharmony_ci       allocation twice. */
7017db96d56Sopenharmony_ci    set_reentrant(1);
7027db96d56Sopenharmony_ci
7037db96d56Sopenharmony_ci    ptr = tracemalloc_alloc(use_calloc, ctx, nelem, elsize);
7047db96d56Sopenharmony_ci
7057db96d56Sopenharmony_ci    set_reentrant(0);
7067db96d56Sopenharmony_ci    return ptr;
7077db96d56Sopenharmony_ci}
7087db96d56Sopenharmony_ci
7097db96d56Sopenharmony_ci
7107db96d56Sopenharmony_cistatic void*
7117db96d56Sopenharmony_citracemalloc_malloc_gil(void *ctx, size_t size)
7127db96d56Sopenharmony_ci{
7137db96d56Sopenharmony_ci    return tracemalloc_alloc_gil(0, ctx, 1, size);
7147db96d56Sopenharmony_ci}
7157db96d56Sopenharmony_ci
7167db96d56Sopenharmony_ci
7177db96d56Sopenharmony_cistatic void*
7187db96d56Sopenharmony_citracemalloc_calloc_gil(void *ctx, size_t nelem, size_t elsize)
7197db96d56Sopenharmony_ci{
7207db96d56Sopenharmony_ci    return tracemalloc_alloc_gil(1, ctx, nelem, elsize);
7217db96d56Sopenharmony_ci}
7227db96d56Sopenharmony_ci
7237db96d56Sopenharmony_ci
7247db96d56Sopenharmony_cistatic void*
7257db96d56Sopenharmony_citracemalloc_realloc_gil(void *ctx, void *ptr, size_t new_size)
7267db96d56Sopenharmony_ci{
7277db96d56Sopenharmony_ci    void *ptr2;
7287db96d56Sopenharmony_ci
7297db96d56Sopenharmony_ci    if (get_reentrant()) {
7307db96d56Sopenharmony_ci        /* Reentrant call to PyMem_Realloc() and PyMem_RawRealloc().
7317db96d56Sopenharmony_ci           Example: PyMem_RawRealloc() is called internally by pymalloc
7327db96d56Sopenharmony_ci           (_PyObject_Malloc() and  _PyObject_Realloc()) to allocate a new
7337db96d56Sopenharmony_ci           arena (new_arena()). */
7347db96d56Sopenharmony_ci        PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx;
7357db96d56Sopenharmony_ci
7367db96d56Sopenharmony_ci        ptr2 = alloc->realloc(alloc->ctx, ptr, new_size);
7377db96d56Sopenharmony_ci        if (ptr2 != NULL && ptr != NULL) {
7387db96d56Sopenharmony_ci            TABLES_LOCK();
7397db96d56Sopenharmony_ci            REMOVE_TRACE(ptr);
7407db96d56Sopenharmony_ci            TABLES_UNLOCK();
7417db96d56Sopenharmony_ci        }
7427db96d56Sopenharmony_ci        return ptr2;
7437db96d56Sopenharmony_ci    }
7447db96d56Sopenharmony_ci
7457db96d56Sopenharmony_ci    /* Ignore reentrant call. PyObjet_Realloc() calls PyMem_Realloc() for
7467db96d56Sopenharmony_ci       allocations larger than 512 bytes. Don't trace the same memory
7477db96d56Sopenharmony_ci       allocation twice. */
7487db96d56Sopenharmony_ci    set_reentrant(1);
7497db96d56Sopenharmony_ci
7507db96d56Sopenharmony_ci    ptr2 = tracemalloc_realloc(ctx, ptr, new_size);
7517db96d56Sopenharmony_ci
7527db96d56Sopenharmony_ci    set_reentrant(0);
7537db96d56Sopenharmony_ci    return ptr2;
7547db96d56Sopenharmony_ci}
7557db96d56Sopenharmony_ci
7567db96d56Sopenharmony_ci
7577db96d56Sopenharmony_ci#ifdef TRACE_RAW_MALLOC
7587db96d56Sopenharmony_cistatic void*
7597db96d56Sopenharmony_citracemalloc_raw_alloc(int use_calloc, void *ctx, size_t nelem, size_t elsize)
7607db96d56Sopenharmony_ci{
7617db96d56Sopenharmony_ci    PyGILState_STATE gil_state;
7627db96d56Sopenharmony_ci    void *ptr;
7637db96d56Sopenharmony_ci
7647db96d56Sopenharmony_ci    if (get_reentrant()) {
7657db96d56Sopenharmony_ci        PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx;
7667db96d56Sopenharmony_ci        if (use_calloc)
7677db96d56Sopenharmony_ci            return alloc->calloc(alloc->ctx, nelem, elsize);
7687db96d56Sopenharmony_ci        else
7697db96d56Sopenharmony_ci            return alloc->malloc(alloc->ctx, nelem * elsize);
7707db96d56Sopenharmony_ci    }
7717db96d56Sopenharmony_ci
7727db96d56Sopenharmony_ci    /* Ignore reentrant call. PyGILState_Ensure() may call PyMem_RawMalloc()
7737db96d56Sopenharmony_ci       indirectly which would call PyGILState_Ensure() if reentrant are not
7747db96d56Sopenharmony_ci       disabled. */
7757db96d56Sopenharmony_ci    set_reentrant(1);
7767db96d56Sopenharmony_ci
7777db96d56Sopenharmony_ci    gil_state = PyGILState_Ensure();
7787db96d56Sopenharmony_ci    ptr = tracemalloc_alloc(use_calloc, ctx, nelem, elsize);
7797db96d56Sopenharmony_ci    PyGILState_Release(gil_state);
7807db96d56Sopenharmony_ci
7817db96d56Sopenharmony_ci    set_reentrant(0);
7827db96d56Sopenharmony_ci    return ptr;
7837db96d56Sopenharmony_ci}
7847db96d56Sopenharmony_ci
7857db96d56Sopenharmony_ci
7867db96d56Sopenharmony_cistatic void*
7877db96d56Sopenharmony_citracemalloc_raw_malloc(void *ctx, size_t size)
7887db96d56Sopenharmony_ci{
7897db96d56Sopenharmony_ci    return tracemalloc_raw_alloc(0, ctx, 1, size);
7907db96d56Sopenharmony_ci}
7917db96d56Sopenharmony_ci
7927db96d56Sopenharmony_ci
7937db96d56Sopenharmony_cistatic void*
7947db96d56Sopenharmony_citracemalloc_raw_calloc(void *ctx, size_t nelem, size_t elsize)
7957db96d56Sopenharmony_ci{
7967db96d56Sopenharmony_ci    return tracemalloc_raw_alloc(1, ctx, nelem, elsize);
7977db96d56Sopenharmony_ci}
7987db96d56Sopenharmony_ci
7997db96d56Sopenharmony_ci
8007db96d56Sopenharmony_cistatic void*
8017db96d56Sopenharmony_citracemalloc_raw_realloc(void *ctx, void *ptr, size_t new_size)
8027db96d56Sopenharmony_ci{
8037db96d56Sopenharmony_ci    PyGILState_STATE gil_state;
8047db96d56Sopenharmony_ci    void *ptr2;
8057db96d56Sopenharmony_ci
8067db96d56Sopenharmony_ci    if (get_reentrant()) {
8077db96d56Sopenharmony_ci        /* Reentrant call to PyMem_RawRealloc(). */
8087db96d56Sopenharmony_ci        PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx;
8097db96d56Sopenharmony_ci
8107db96d56Sopenharmony_ci        ptr2 = alloc->realloc(alloc->ctx, ptr, new_size);
8117db96d56Sopenharmony_ci
8127db96d56Sopenharmony_ci        if (ptr2 != NULL && ptr != NULL) {
8137db96d56Sopenharmony_ci            TABLES_LOCK();
8147db96d56Sopenharmony_ci            REMOVE_TRACE(ptr);
8157db96d56Sopenharmony_ci            TABLES_UNLOCK();
8167db96d56Sopenharmony_ci        }
8177db96d56Sopenharmony_ci        return ptr2;
8187db96d56Sopenharmony_ci    }
8197db96d56Sopenharmony_ci
8207db96d56Sopenharmony_ci    /* Ignore reentrant call. PyGILState_Ensure() may call PyMem_RawMalloc()
8217db96d56Sopenharmony_ci       indirectly which would call PyGILState_Ensure() if reentrant calls are
8227db96d56Sopenharmony_ci       not disabled. */
8237db96d56Sopenharmony_ci    set_reentrant(1);
8247db96d56Sopenharmony_ci
8257db96d56Sopenharmony_ci    gil_state = PyGILState_Ensure();
8267db96d56Sopenharmony_ci    ptr2 = tracemalloc_realloc(ctx, ptr, new_size);
8277db96d56Sopenharmony_ci    PyGILState_Release(gil_state);
8287db96d56Sopenharmony_ci
8297db96d56Sopenharmony_ci    set_reentrant(0);
8307db96d56Sopenharmony_ci    return ptr2;
8317db96d56Sopenharmony_ci}
8327db96d56Sopenharmony_ci#endif   /* TRACE_RAW_MALLOC */
8337db96d56Sopenharmony_ci
8347db96d56Sopenharmony_ci
8357db96d56Sopenharmony_cistatic void
8367db96d56Sopenharmony_citracemalloc_clear_filename(void *value)
8377db96d56Sopenharmony_ci{
8387db96d56Sopenharmony_ci    PyObject *filename = (PyObject *)value;
8397db96d56Sopenharmony_ci    Py_DECREF(filename);
8407db96d56Sopenharmony_ci}
8417db96d56Sopenharmony_ci
8427db96d56Sopenharmony_ci
8437db96d56Sopenharmony_ci/* reentrant flag must be set to call this function and GIL must be held */
8447db96d56Sopenharmony_cistatic void
8457db96d56Sopenharmony_citracemalloc_clear_traces(void)
8467db96d56Sopenharmony_ci{
8477db96d56Sopenharmony_ci    /* The GIL protects variables against concurrent access */
8487db96d56Sopenharmony_ci    assert(PyGILState_Check());
8497db96d56Sopenharmony_ci
8507db96d56Sopenharmony_ci    TABLES_LOCK();
8517db96d56Sopenharmony_ci    _Py_hashtable_clear(tracemalloc_traces);
8527db96d56Sopenharmony_ci    _Py_hashtable_clear(tracemalloc_domains);
8537db96d56Sopenharmony_ci    tracemalloc_traced_memory = 0;
8547db96d56Sopenharmony_ci    tracemalloc_peak_traced_memory = 0;
8557db96d56Sopenharmony_ci    TABLES_UNLOCK();
8567db96d56Sopenharmony_ci
8577db96d56Sopenharmony_ci    _Py_hashtable_clear(tracemalloc_tracebacks);
8587db96d56Sopenharmony_ci
8597db96d56Sopenharmony_ci    _Py_hashtable_clear(tracemalloc_filenames);
8607db96d56Sopenharmony_ci}
8617db96d56Sopenharmony_ci
8627db96d56Sopenharmony_ci
8637db96d56Sopenharmony_cistatic int
8647db96d56Sopenharmony_citracemalloc_init(void)
8657db96d56Sopenharmony_ci{
8667db96d56Sopenharmony_ci    if (_Py_tracemalloc_config.initialized == TRACEMALLOC_FINALIZED) {
8677db96d56Sopenharmony_ci        PyErr_SetString(PyExc_RuntimeError,
8687db96d56Sopenharmony_ci                        "the tracemalloc module has been unloaded");
8697db96d56Sopenharmony_ci        return -1;
8707db96d56Sopenharmony_ci    }
8717db96d56Sopenharmony_ci
8727db96d56Sopenharmony_ci    if (_Py_tracemalloc_config.initialized == TRACEMALLOC_INITIALIZED)
8737db96d56Sopenharmony_ci        return 0;
8747db96d56Sopenharmony_ci
8757db96d56Sopenharmony_ci    PyMem_GetAllocator(PYMEM_DOMAIN_RAW, &allocators.raw);
8767db96d56Sopenharmony_ci
8777db96d56Sopenharmony_ci#ifdef REENTRANT_THREADLOCAL
8787db96d56Sopenharmony_ci    if (PyThread_tss_create(&tracemalloc_reentrant_key) != 0) {
8797db96d56Sopenharmony_ci#ifdef MS_WINDOWS
8807db96d56Sopenharmony_ci        PyErr_SetFromWindowsErr(0);
8817db96d56Sopenharmony_ci#else
8827db96d56Sopenharmony_ci        PyErr_SetFromErrno(PyExc_OSError);
8837db96d56Sopenharmony_ci#endif
8847db96d56Sopenharmony_ci        return -1;
8857db96d56Sopenharmony_ci    }
8867db96d56Sopenharmony_ci#endif
8877db96d56Sopenharmony_ci
8887db96d56Sopenharmony_ci#if defined(TRACE_RAW_MALLOC)
8897db96d56Sopenharmony_ci    if (tables_lock == NULL) {
8907db96d56Sopenharmony_ci        tables_lock = PyThread_allocate_lock();
8917db96d56Sopenharmony_ci        if (tables_lock == NULL) {
8927db96d56Sopenharmony_ci            PyErr_SetString(PyExc_RuntimeError, "cannot allocate lock");
8937db96d56Sopenharmony_ci            return -1;
8947db96d56Sopenharmony_ci        }
8957db96d56Sopenharmony_ci    }
8967db96d56Sopenharmony_ci#endif
8977db96d56Sopenharmony_ci
8987db96d56Sopenharmony_ci    tracemalloc_filenames = hashtable_new(hashtable_hash_pyobject,
8997db96d56Sopenharmony_ci                                          hashtable_compare_unicode,
9007db96d56Sopenharmony_ci                                          tracemalloc_clear_filename, NULL);
9017db96d56Sopenharmony_ci
9027db96d56Sopenharmony_ci    tracemalloc_tracebacks = hashtable_new(hashtable_hash_traceback,
9037db96d56Sopenharmony_ci                                           hashtable_compare_traceback,
9047db96d56Sopenharmony_ci                                           NULL, raw_free);
9057db96d56Sopenharmony_ci
9067db96d56Sopenharmony_ci    tracemalloc_traces = tracemalloc_create_traces_table();
9077db96d56Sopenharmony_ci    tracemalloc_domains = tracemalloc_create_domains_table();
9087db96d56Sopenharmony_ci
9097db96d56Sopenharmony_ci    if (tracemalloc_filenames == NULL || tracemalloc_tracebacks == NULL
9107db96d56Sopenharmony_ci       || tracemalloc_traces == NULL || tracemalloc_domains == NULL) {
9117db96d56Sopenharmony_ci        PyErr_NoMemory();
9127db96d56Sopenharmony_ci        return -1;
9137db96d56Sopenharmony_ci    }
9147db96d56Sopenharmony_ci
9157db96d56Sopenharmony_ci    tracemalloc_empty_traceback.nframe = 1;
9167db96d56Sopenharmony_ci    tracemalloc_empty_traceback.total_nframe = 1;
9177db96d56Sopenharmony_ci    /* borrowed reference */
9187db96d56Sopenharmony_ci    tracemalloc_empty_traceback.frames[0].filename = &_Py_STR(anon_unknown);
9197db96d56Sopenharmony_ci    tracemalloc_empty_traceback.frames[0].lineno = 0;
9207db96d56Sopenharmony_ci    tracemalloc_empty_traceback.hash = traceback_hash(&tracemalloc_empty_traceback);
9217db96d56Sopenharmony_ci
9227db96d56Sopenharmony_ci    _Py_tracemalloc_config.initialized = TRACEMALLOC_INITIALIZED;
9237db96d56Sopenharmony_ci    return 0;
9247db96d56Sopenharmony_ci}
9257db96d56Sopenharmony_ci
9267db96d56Sopenharmony_ci
9277db96d56Sopenharmony_cistatic void
9287db96d56Sopenharmony_citracemalloc_deinit(void)
9297db96d56Sopenharmony_ci{
9307db96d56Sopenharmony_ci    if (_Py_tracemalloc_config.initialized != TRACEMALLOC_INITIALIZED)
9317db96d56Sopenharmony_ci        return;
9327db96d56Sopenharmony_ci    _Py_tracemalloc_config.initialized = TRACEMALLOC_FINALIZED;
9337db96d56Sopenharmony_ci
9347db96d56Sopenharmony_ci    tracemalloc_stop();
9357db96d56Sopenharmony_ci
9367db96d56Sopenharmony_ci    /* destroy hash tables */
9377db96d56Sopenharmony_ci    _Py_hashtable_destroy(tracemalloc_domains);
9387db96d56Sopenharmony_ci    _Py_hashtable_destroy(tracemalloc_traces);
9397db96d56Sopenharmony_ci    _Py_hashtable_destroy(tracemalloc_tracebacks);
9407db96d56Sopenharmony_ci    _Py_hashtable_destroy(tracemalloc_filenames);
9417db96d56Sopenharmony_ci
9427db96d56Sopenharmony_ci#if defined(TRACE_RAW_MALLOC)
9437db96d56Sopenharmony_ci    if (tables_lock != NULL) {
9447db96d56Sopenharmony_ci        PyThread_free_lock(tables_lock);
9457db96d56Sopenharmony_ci        tables_lock = NULL;
9467db96d56Sopenharmony_ci    }
9477db96d56Sopenharmony_ci#endif
9487db96d56Sopenharmony_ci
9497db96d56Sopenharmony_ci#ifdef REENTRANT_THREADLOCAL
9507db96d56Sopenharmony_ci    PyThread_tss_delete(&tracemalloc_reentrant_key);
9517db96d56Sopenharmony_ci#endif
9527db96d56Sopenharmony_ci}
9537db96d56Sopenharmony_ci
9547db96d56Sopenharmony_ci
9557db96d56Sopenharmony_cistatic int
9567db96d56Sopenharmony_citracemalloc_start(int max_nframe)
9577db96d56Sopenharmony_ci{
9587db96d56Sopenharmony_ci    PyMemAllocatorEx alloc;
9597db96d56Sopenharmony_ci    size_t size;
9607db96d56Sopenharmony_ci
9617db96d56Sopenharmony_ci    if (max_nframe < 1 || (unsigned long) max_nframe > MAX_NFRAME) {
9627db96d56Sopenharmony_ci        PyErr_Format(PyExc_ValueError,
9637db96d56Sopenharmony_ci                     "the number of frames must be in range [1; %lu]",
9647db96d56Sopenharmony_ci                     MAX_NFRAME);
9657db96d56Sopenharmony_ci        return -1;
9667db96d56Sopenharmony_ci    }
9677db96d56Sopenharmony_ci
9687db96d56Sopenharmony_ci    if (tracemalloc_init() < 0) {
9697db96d56Sopenharmony_ci        return -1;
9707db96d56Sopenharmony_ci    }
9717db96d56Sopenharmony_ci
9727db96d56Sopenharmony_ci    if (_Py_tracemalloc_config.tracing) {
9737db96d56Sopenharmony_ci        /* hook already installed: do nothing */
9747db96d56Sopenharmony_ci        return 0;
9757db96d56Sopenharmony_ci    }
9767db96d56Sopenharmony_ci
9777db96d56Sopenharmony_ci    _Py_tracemalloc_config.max_nframe = max_nframe;
9787db96d56Sopenharmony_ci
9797db96d56Sopenharmony_ci    /* allocate a buffer to store a new traceback */
9807db96d56Sopenharmony_ci    size = TRACEBACK_SIZE(max_nframe);
9817db96d56Sopenharmony_ci    assert(tracemalloc_traceback == NULL);
9827db96d56Sopenharmony_ci    tracemalloc_traceback = raw_malloc(size);
9837db96d56Sopenharmony_ci    if (tracemalloc_traceback == NULL) {
9847db96d56Sopenharmony_ci        PyErr_NoMemory();
9857db96d56Sopenharmony_ci        return -1;
9867db96d56Sopenharmony_ci    }
9877db96d56Sopenharmony_ci
9887db96d56Sopenharmony_ci#ifdef TRACE_RAW_MALLOC
9897db96d56Sopenharmony_ci    alloc.malloc = tracemalloc_raw_malloc;
9907db96d56Sopenharmony_ci    alloc.calloc = tracemalloc_raw_calloc;
9917db96d56Sopenharmony_ci    alloc.realloc = tracemalloc_raw_realloc;
9927db96d56Sopenharmony_ci    alloc.free = tracemalloc_free;
9937db96d56Sopenharmony_ci
9947db96d56Sopenharmony_ci    alloc.ctx = &allocators.raw;
9957db96d56Sopenharmony_ci    PyMem_GetAllocator(PYMEM_DOMAIN_RAW, &allocators.raw);
9967db96d56Sopenharmony_ci    PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &alloc);
9977db96d56Sopenharmony_ci#endif
9987db96d56Sopenharmony_ci
9997db96d56Sopenharmony_ci    alloc.malloc = tracemalloc_malloc_gil;
10007db96d56Sopenharmony_ci    alloc.calloc = tracemalloc_calloc_gil;
10017db96d56Sopenharmony_ci    alloc.realloc = tracemalloc_realloc_gil;
10027db96d56Sopenharmony_ci    alloc.free = tracemalloc_free;
10037db96d56Sopenharmony_ci
10047db96d56Sopenharmony_ci    alloc.ctx = &allocators.mem;
10057db96d56Sopenharmony_ci    PyMem_GetAllocator(PYMEM_DOMAIN_MEM, &allocators.mem);
10067db96d56Sopenharmony_ci    PyMem_SetAllocator(PYMEM_DOMAIN_MEM, &alloc);
10077db96d56Sopenharmony_ci
10087db96d56Sopenharmony_ci    alloc.ctx = &allocators.obj;
10097db96d56Sopenharmony_ci    PyMem_GetAllocator(PYMEM_DOMAIN_OBJ, &allocators.obj);
10107db96d56Sopenharmony_ci    PyMem_SetAllocator(PYMEM_DOMAIN_OBJ, &alloc);
10117db96d56Sopenharmony_ci
10127db96d56Sopenharmony_ci    /* everything is ready: start tracing Python memory allocations */
10137db96d56Sopenharmony_ci    _Py_tracemalloc_config.tracing = 1;
10147db96d56Sopenharmony_ci
10157db96d56Sopenharmony_ci    return 0;
10167db96d56Sopenharmony_ci}
10177db96d56Sopenharmony_ci
10187db96d56Sopenharmony_ci
10197db96d56Sopenharmony_cistatic void
10207db96d56Sopenharmony_citracemalloc_stop(void)
10217db96d56Sopenharmony_ci{
10227db96d56Sopenharmony_ci    if (!_Py_tracemalloc_config.tracing)
10237db96d56Sopenharmony_ci        return;
10247db96d56Sopenharmony_ci
10257db96d56Sopenharmony_ci    /* stop tracing Python memory allocations */
10267db96d56Sopenharmony_ci    _Py_tracemalloc_config.tracing = 0;
10277db96d56Sopenharmony_ci
10287db96d56Sopenharmony_ci    /* unregister the hook on memory allocators */
10297db96d56Sopenharmony_ci#ifdef TRACE_RAW_MALLOC
10307db96d56Sopenharmony_ci    PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &allocators.raw);
10317db96d56Sopenharmony_ci#endif
10327db96d56Sopenharmony_ci    PyMem_SetAllocator(PYMEM_DOMAIN_MEM, &allocators.mem);
10337db96d56Sopenharmony_ci    PyMem_SetAllocator(PYMEM_DOMAIN_OBJ, &allocators.obj);
10347db96d56Sopenharmony_ci
10357db96d56Sopenharmony_ci    tracemalloc_clear_traces();
10367db96d56Sopenharmony_ci
10377db96d56Sopenharmony_ci    /* release memory */
10387db96d56Sopenharmony_ci    raw_free(tracemalloc_traceback);
10397db96d56Sopenharmony_ci    tracemalloc_traceback = NULL;
10407db96d56Sopenharmony_ci}
10417db96d56Sopenharmony_ci
10427db96d56Sopenharmony_ci
10437db96d56Sopenharmony_ci
10447db96d56Sopenharmony_ci/*[clinic input]
10457db96d56Sopenharmony_ci_tracemalloc.is_tracing
10467db96d56Sopenharmony_ci
10477db96d56Sopenharmony_ciReturn True if the tracemalloc module is tracing Python memory allocations.
10487db96d56Sopenharmony_ci[clinic start generated code]*/
10497db96d56Sopenharmony_ci
10507db96d56Sopenharmony_cistatic PyObject *
10517db96d56Sopenharmony_ci_tracemalloc_is_tracing_impl(PyObject *module)
10527db96d56Sopenharmony_ci/*[clinic end generated code: output=2d763b42601cd3ef input=af104b0a00192f63]*/
10537db96d56Sopenharmony_ci{
10547db96d56Sopenharmony_ci    return PyBool_FromLong(_Py_tracemalloc_config.tracing);
10557db96d56Sopenharmony_ci}
10567db96d56Sopenharmony_ci
10577db96d56Sopenharmony_ci
10587db96d56Sopenharmony_ci/*[clinic input]
10597db96d56Sopenharmony_ci_tracemalloc.clear_traces
10607db96d56Sopenharmony_ci
10617db96d56Sopenharmony_ciClear traces of memory blocks allocated by Python.
10627db96d56Sopenharmony_ci[clinic start generated code]*/
10637db96d56Sopenharmony_ci
10647db96d56Sopenharmony_cistatic PyObject *
10657db96d56Sopenharmony_ci_tracemalloc_clear_traces_impl(PyObject *module)
10667db96d56Sopenharmony_ci/*[clinic end generated code: output=a86080ee41b84197 input=0dab5b6c785183a5]*/
10677db96d56Sopenharmony_ci{
10687db96d56Sopenharmony_ci    if (!_Py_tracemalloc_config.tracing)
10697db96d56Sopenharmony_ci        Py_RETURN_NONE;
10707db96d56Sopenharmony_ci
10717db96d56Sopenharmony_ci    set_reentrant(1);
10727db96d56Sopenharmony_ci    tracemalloc_clear_traces();
10737db96d56Sopenharmony_ci    set_reentrant(0);
10747db96d56Sopenharmony_ci
10757db96d56Sopenharmony_ci    Py_RETURN_NONE;
10767db96d56Sopenharmony_ci}
10777db96d56Sopenharmony_ci
10787db96d56Sopenharmony_ci
10797db96d56Sopenharmony_cistatic PyObject*
10807db96d56Sopenharmony_ciframe_to_pyobject(frame_t *frame)
10817db96d56Sopenharmony_ci{
10827db96d56Sopenharmony_ci    PyObject *frame_obj, *lineno_obj;
10837db96d56Sopenharmony_ci
10847db96d56Sopenharmony_ci    frame_obj = PyTuple_New(2);
10857db96d56Sopenharmony_ci    if (frame_obj == NULL)
10867db96d56Sopenharmony_ci        return NULL;
10877db96d56Sopenharmony_ci
10887db96d56Sopenharmony_ci    Py_INCREF(frame->filename);
10897db96d56Sopenharmony_ci    PyTuple_SET_ITEM(frame_obj, 0, frame->filename);
10907db96d56Sopenharmony_ci
10917db96d56Sopenharmony_ci    lineno_obj = PyLong_FromUnsignedLong(frame->lineno);
10927db96d56Sopenharmony_ci    if (lineno_obj == NULL) {
10937db96d56Sopenharmony_ci        Py_DECREF(frame_obj);
10947db96d56Sopenharmony_ci        return NULL;
10957db96d56Sopenharmony_ci    }
10967db96d56Sopenharmony_ci    PyTuple_SET_ITEM(frame_obj, 1, lineno_obj);
10977db96d56Sopenharmony_ci
10987db96d56Sopenharmony_ci    return frame_obj;
10997db96d56Sopenharmony_ci}
11007db96d56Sopenharmony_ci
11017db96d56Sopenharmony_ci
11027db96d56Sopenharmony_cistatic PyObject*
11037db96d56Sopenharmony_citraceback_to_pyobject(traceback_t *traceback, _Py_hashtable_t *intern_table)
11047db96d56Sopenharmony_ci{
11057db96d56Sopenharmony_ci    PyObject *frames;
11067db96d56Sopenharmony_ci
11077db96d56Sopenharmony_ci    if (intern_table != NULL) {
11087db96d56Sopenharmony_ci        frames = _Py_hashtable_get(intern_table, (const void *)traceback);
11097db96d56Sopenharmony_ci        if (frames) {
11107db96d56Sopenharmony_ci            Py_INCREF(frames);
11117db96d56Sopenharmony_ci            return frames;
11127db96d56Sopenharmony_ci        }
11137db96d56Sopenharmony_ci    }
11147db96d56Sopenharmony_ci
11157db96d56Sopenharmony_ci    frames = PyTuple_New(traceback->nframe);
11167db96d56Sopenharmony_ci    if (frames == NULL)
11177db96d56Sopenharmony_ci        return NULL;
11187db96d56Sopenharmony_ci
11197db96d56Sopenharmony_ci    for (int i=0; i < traceback->nframe; i++) {
11207db96d56Sopenharmony_ci        PyObject *frame = frame_to_pyobject(&traceback->frames[i]);
11217db96d56Sopenharmony_ci        if (frame == NULL) {
11227db96d56Sopenharmony_ci            Py_DECREF(frames);
11237db96d56Sopenharmony_ci            return NULL;
11247db96d56Sopenharmony_ci        }
11257db96d56Sopenharmony_ci        PyTuple_SET_ITEM(frames, i, frame);
11267db96d56Sopenharmony_ci    }
11277db96d56Sopenharmony_ci
11287db96d56Sopenharmony_ci    if (intern_table != NULL) {
11297db96d56Sopenharmony_ci        if (_Py_hashtable_set(intern_table, traceback, frames) < 0) {
11307db96d56Sopenharmony_ci            Py_DECREF(frames);
11317db96d56Sopenharmony_ci            PyErr_NoMemory();
11327db96d56Sopenharmony_ci            return NULL;
11337db96d56Sopenharmony_ci        }
11347db96d56Sopenharmony_ci        /* intern_table keeps a new reference to frames */
11357db96d56Sopenharmony_ci        Py_INCREF(frames);
11367db96d56Sopenharmony_ci    }
11377db96d56Sopenharmony_ci    return frames;
11387db96d56Sopenharmony_ci}
11397db96d56Sopenharmony_ci
11407db96d56Sopenharmony_ci
11417db96d56Sopenharmony_cistatic PyObject*
11427db96d56Sopenharmony_citrace_to_pyobject(unsigned int domain, const trace_t *trace,
11437db96d56Sopenharmony_ci                  _Py_hashtable_t *intern_tracebacks)
11447db96d56Sopenharmony_ci{
11457db96d56Sopenharmony_ci    PyObject *trace_obj = NULL;
11467db96d56Sopenharmony_ci    PyObject *obj;
11477db96d56Sopenharmony_ci
11487db96d56Sopenharmony_ci    trace_obj = PyTuple_New(4);
11497db96d56Sopenharmony_ci    if (trace_obj == NULL)
11507db96d56Sopenharmony_ci        return NULL;
11517db96d56Sopenharmony_ci
11527db96d56Sopenharmony_ci    obj = PyLong_FromSize_t(domain);
11537db96d56Sopenharmony_ci    if (obj == NULL) {
11547db96d56Sopenharmony_ci        Py_DECREF(trace_obj);
11557db96d56Sopenharmony_ci        return NULL;
11567db96d56Sopenharmony_ci    }
11577db96d56Sopenharmony_ci    PyTuple_SET_ITEM(trace_obj, 0, obj);
11587db96d56Sopenharmony_ci
11597db96d56Sopenharmony_ci    obj = PyLong_FromSize_t(trace->size);
11607db96d56Sopenharmony_ci    if (obj == NULL) {
11617db96d56Sopenharmony_ci        Py_DECREF(trace_obj);
11627db96d56Sopenharmony_ci        return NULL;
11637db96d56Sopenharmony_ci    }
11647db96d56Sopenharmony_ci    PyTuple_SET_ITEM(trace_obj, 1, obj);
11657db96d56Sopenharmony_ci
11667db96d56Sopenharmony_ci    obj = traceback_to_pyobject(trace->traceback, intern_tracebacks);
11677db96d56Sopenharmony_ci    if (obj == NULL) {
11687db96d56Sopenharmony_ci        Py_DECREF(trace_obj);
11697db96d56Sopenharmony_ci        return NULL;
11707db96d56Sopenharmony_ci    }
11717db96d56Sopenharmony_ci    PyTuple_SET_ITEM(trace_obj, 2, obj);
11727db96d56Sopenharmony_ci
11737db96d56Sopenharmony_ci    obj = PyLong_FromUnsignedLong(trace->traceback->total_nframe);
11747db96d56Sopenharmony_ci    if (obj == NULL) {
11757db96d56Sopenharmony_ci        Py_DECREF(trace_obj);
11767db96d56Sopenharmony_ci        return NULL;
11777db96d56Sopenharmony_ci    }
11787db96d56Sopenharmony_ci    PyTuple_SET_ITEM(trace_obj, 3, obj);
11797db96d56Sopenharmony_ci
11807db96d56Sopenharmony_ci    return trace_obj;
11817db96d56Sopenharmony_ci}
11827db96d56Sopenharmony_ci
11837db96d56Sopenharmony_ci
11847db96d56Sopenharmony_citypedef struct {
11857db96d56Sopenharmony_ci    _Py_hashtable_t *traces;
11867db96d56Sopenharmony_ci    _Py_hashtable_t *domains;
11877db96d56Sopenharmony_ci    _Py_hashtable_t *tracebacks;
11887db96d56Sopenharmony_ci    PyObject *list;
11897db96d56Sopenharmony_ci    unsigned int domain;
11907db96d56Sopenharmony_ci} get_traces_t;
11917db96d56Sopenharmony_ci
11927db96d56Sopenharmony_ci
11937db96d56Sopenharmony_cistatic int
11947db96d56Sopenharmony_citracemalloc_copy_trace(_Py_hashtable_t *traces,
11957db96d56Sopenharmony_ci                       const void *key, const void *value,
11967db96d56Sopenharmony_ci                       void *user_data)
11977db96d56Sopenharmony_ci{
11987db96d56Sopenharmony_ci    _Py_hashtable_t *traces2 = (_Py_hashtable_t *)user_data;
11997db96d56Sopenharmony_ci
12007db96d56Sopenharmony_ci    trace_t *trace = (trace_t *)value;
12017db96d56Sopenharmony_ci
12027db96d56Sopenharmony_ci    trace_t *trace2 = raw_malloc(sizeof(trace_t));
12037db96d56Sopenharmony_ci    if (trace2 == NULL) {
12047db96d56Sopenharmony_ci        return -1;
12057db96d56Sopenharmony_ci    }
12067db96d56Sopenharmony_ci    *trace2 = *trace;
12077db96d56Sopenharmony_ci    if (_Py_hashtable_set(traces2, key, trace2) < 0) {
12087db96d56Sopenharmony_ci        raw_free(trace2);
12097db96d56Sopenharmony_ci        return -1;
12107db96d56Sopenharmony_ci    }
12117db96d56Sopenharmony_ci    return 0;
12127db96d56Sopenharmony_ci}
12137db96d56Sopenharmony_ci
12147db96d56Sopenharmony_ci
12157db96d56Sopenharmony_cistatic _Py_hashtable_t*
12167db96d56Sopenharmony_citracemalloc_copy_traces(_Py_hashtable_t *traces)
12177db96d56Sopenharmony_ci{
12187db96d56Sopenharmony_ci    _Py_hashtable_t *traces2 = tracemalloc_create_traces_table();
12197db96d56Sopenharmony_ci    if (traces2 == NULL) {
12207db96d56Sopenharmony_ci        return NULL;
12217db96d56Sopenharmony_ci    }
12227db96d56Sopenharmony_ci
12237db96d56Sopenharmony_ci    int err = _Py_hashtable_foreach(traces,
12247db96d56Sopenharmony_ci                                    tracemalloc_copy_trace,
12257db96d56Sopenharmony_ci                                    traces2);
12267db96d56Sopenharmony_ci    if (err) {
12277db96d56Sopenharmony_ci        _Py_hashtable_destroy(traces2);
12287db96d56Sopenharmony_ci        return NULL;
12297db96d56Sopenharmony_ci    }
12307db96d56Sopenharmony_ci    return traces2;
12317db96d56Sopenharmony_ci}
12327db96d56Sopenharmony_ci
12337db96d56Sopenharmony_ci
12347db96d56Sopenharmony_cistatic int
12357db96d56Sopenharmony_citracemalloc_copy_domain(_Py_hashtable_t *domains,
12367db96d56Sopenharmony_ci                        const void *key, const void *value,
12377db96d56Sopenharmony_ci                        void *user_data)
12387db96d56Sopenharmony_ci{
12397db96d56Sopenharmony_ci    _Py_hashtable_t *domains2 = (_Py_hashtable_t *)user_data;
12407db96d56Sopenharmony_ci
12417db96d56Sopenharmony_ci    unsigned int domain = (unsigned int)FROM_PTR(key);
12427db96d56Sopenharmony_ci    _Py_hashtable_t *traces = (_Py_hashtable_t *)value;
12437db96d56Sopenharmony_ci
12447db96d56Sopenharmony_ci    _Py_hashtable_t *traces2 = tracemalloc_copy_traces(traces);
12457db96d56Sopenharmony_ci    if (traces2 == NULL) {
12467db96d56Sopenharmony_ci        return -1;
12477db96d56Sopenharmony_ci    }
12487db96d56Sopenharmony_ci    if (_Py_hashtable_set(domains2, TO_PTR(domain), traces2) < 0) {
12497db96d56Sopenharmony_ci        _Py_hashtable_destroy(traces2);
12507db96d56Sopenharmony_ci        return -1;
12517db96d56Sopenharmony_ci    }
12527db96d56Sopenharmony_ci    return 0;
12537db96d56Sopenharmony_ci}
12547db96d56Sopenharmony_ci
12557db96d56Sopenharmony_ci
12567db96d56Sopenharmony_cistatic _Py_hashtable_t*
12577db96d56Sopenharmony_citracemalloc_copy_domains(_Py_hashtable_t *domains)
12587db96d56Sopenharmony_ci{
12597db96d56Sopenharmony_ci    _Py_hashtable_t *domains2 = tracemalloc_create_domains_table();
12607db96d56Sopenharmony_ci    if (domains2 == NULL) {
12617db96d56Sopenharmony_ci        return NULL;
12627db96d56Sopenharmony_ci    }
12637db96d56Sopenharmony_ci
12647db96d56Sopenharmony_ci    int err = _Py_hashtable_foreach(domains,
12657db96d56Sopenharmony_ci                                    tracemalloc_copy_domain,
12667db96d56Sopenharmony_ci                                    domains2);
12677db96d56Sopenharmony_ci    if (err) {
12687db96d56Sopenharmony_ci        _Py_hashtable_destroy(domains2);
12697db96d56Sopenharmony_ci        return NULL;
12707db96d56Sopenharmony_ci    }
12717db96d56Sopenharmony_ci    return domains2;
12727db96d56Sopenharmony_ci}
12737db96d56Sopenharmony_ci
12747db96d56Sopenharmony_ci
12757db96d56Sopenharmony_cistatic int
12767db96d56Sopenharmony_citracemalloc_get_traces_fill(_Py_hashtable_t *traces,
12777db96d56Sopenharmony_ci                            const void *key, const void *value,
12787db96d56Sopenharmony_ci                            void *user_data)
12797db96d56Sopenharmony_ci{
12807db96d56Sopenharmony_ci    get_traces_t *get_traces = user_data;
12817db96d56Sopenharmony_ci
12827db96d56Sopenharmony_ci    const trace_t *trace = (const trace_t *)value;
12837db96d56Sopenharmony_ci
12847db96d56Sopenharmony_ci    PyObject *tuple = trace_to_pyobject(get_traces->domain, trace,
12857db96d56Sopenharmony_ci                                        get_traces->tracebacks);
12867db96d56Sopenharmony_ci    if (tuple == NULL) {
12877db96d56Sopenharmony_ci        return 1;
12887db96d56Sopenharmony_ci    }
12897db96d56Sopenharmony_ci
12907db96d56Sopenharmony_ci    int res = PyList_Append(get_traces->list, tuple);
12917db96d56Sopenharmony_ci    Py_DECREF(tuple);
12927db96d56Sopenharmony_ci    if (res < 0) {
12937db96d56Sopenharmony_ci        return 1;
12947db96d56Sopenharmony_ci    }
12957db96d56Sopenharmony_ci
12967db96d56Sopenharmony_ci    return 0;
12977db96d56Sopenharmony_ci}
12987db96d56Sopenharmony_ci
12997db96d56Sopenharmony_ci
13007db96d56Sopenharmony_cistatic int
13017db96d56Sopenharmony_citracemalloc_get_traces_domain(_Py_hashtable_t *domains,
13027db96d56Sopenharmony_ci                              const void *key, const void *value,
13037db96d56Sopenharmony_ci                              void *user_data)
13047db96d56Sopenharmony_ci{
13057db96d56Sopenharmony_ci    get_traces_t *get_traces = user_data;
13067db96d56Sopenharmony_ci
13077db96d56Sopenharmony_ci    unsigned int domain = (unsigned int)FROM_PTR(key);
13087db96d56Sopenharmony_ci    _Py_hashtable_t *traces = (_Py_hashtable_t *)value;
13097db96d56Sopenharmony_ci
13107db96d56Sopenharmony_ci    get_traces->domain = domain;
13117db96d56Sopenharmony_ci    return _Py_hashtable_foreach(traces,
13127db96d56Sopenharmony_ci                                 tracemalloc_get_traces_fill,
13137db96d56Sopenharmony_ci                                 get_traces);
13147db96d56Sopenharmony_ci}
13157db96d56Sopenharmony_ci
13167db96d56Sopenharmony_ci
13177db96d56Sopenharmony_cistatic void
13187db96d56Sopenharmony_citracemalloc_pyobject_decref(void *value)
13197db96d56Sopenharmony_ci{
13207db96d56Sopenharmony_ci    PyObject *obj = (PyObject *)value;
13217db96d56Sopenharmony_ci    Py_DECREF(obj);
13227db96d56Sopenharmony_ci}
13237db96d56Sopenharmony_ci
13247db96d56Sopenharmony_ci
13257db96d56Sopenharmony_ci
13267db96d56Sopenharmony_ci/*[clinic input]
13277db96d56Sopenharmony_ci_tracemalloc._get_traces
13287db96d56Sopenharmony_ci
13297db96d56Sopenharmony_ciGet traces of all memory blocks allocated by Python.
13307db96d56Sopenharmony_ci
13317db96d56Sopenharmony_ciReturn a list of (size: int, traceback: tuple) tuples.
13327db96d56Sopenharmony_citraceback is a tuple of (filename: str, lineno: int) tuples.
13337db96d56Sopenharmony_ci
13347db96d56Sopenharmony_ciReturn an empty list if the tracemalloc module is disabled.
13357db96d56Sopenharmony_ci[clinic start generated code]*/
13367db96d56Sopenharmony_ci
13377db96d56Sopenharmony_cistatic PyObject *
13387db96d56Sopenharmony_ci_tracemalloc__get_traces_impl(PyObject *module)
13397db96d56Sopenharmony_ci/*[clinic end generated code: output=e9929876ced4b5cc input=6c7d2230b24255aa]*/
13407db96d56Sopenharmony_ci{
13417db96d56Sopenharmony_ci    get_traces_t get_traces;
13427db96d56Sopenharmony_ci    get_traces.domain = DEFAULT_DOMAIN;
13437db96d56Sopenharmony_ci    get_traces.traces = NULL;
13447db96d56Sopenharmony_ci    get_traces.domains = NULL;
13457db96d56Sopenharmony_ci    get_traces.tracebacks = NULL;
13467db96d56Sopenharmony_ci    get_traces.list = PyList_New(0);
13477db96d56Sopenharmony_ci    if (get_traces.list == NULL)
13487db96d56Sopenharmony_ci        goto error;
13497db96d56Sopenharmony_ci
13507db96d56Sopenharmony_ci    if (!_Py_tracemalloc_config.tracing)
13517db96d56Sopenharmony_ci        return get_traces.list;
13527db96d56Sopenharmony_ci
13537db96d56Sopenharmony_ci    /* the traceback hash table is used temporarily to intern traceback tuple
13547db96d56Sopenharmony_ci       of (filename, lineno) tuples */
13557db96d56Sopenharmony_ci    get_traces.tracebacks = hashtable_new(_Py_hashtable_hash_ptr,
13567db96d56Sopenharmony_ci                                          _Py_hashtable_compare_direct,
13577db96d56Sopenharmony_ci                                          NULL, tracemalloc_pyobject_decref);
13587db96d56Sopenharmony_ci    if (get_traces.tracebacks == NULL) {
13597db96d56Sopenharmony_ci        goto no_memory;
13607db96d56Sopenharmony_ci    }
13617db96d56Sopenharmony_ci
13627db96d56Sopenharmony_ci    // Copy all traces so tracemalloc_get_traces_fill() doesn't have to disable
13637db96d56Sopenharmony_ci    // temporarily tracemalloc which would impact other threads and so would
13647db96d56Sopenharmony_ci    // miss allocations while get_traces() is called.
13657db96d56Sopenharmony_ci    TABLES_LOCK();
13667db96d56Sopenharmony_ci    get_traces.traces = tracemalloc_copy_traces(tracemalloc_traces);
13677db96d56Sopenharmony_ci    TABLES_UNLOCK();
13687db96d56Sopenharmony_ci
13697db96d56Sopenharmony_ci    if (get_traces.traces == NULL) {
13707db96d56Sopenharmony_ci        goto no_memory;
13717db96d56Sopenharmony_ci    }
13727db96d56Sopenharmony_ci
13737db96d56Sopenharmony_ci    TABLES_LOCK();
13747db96d56Sopenharmony_ci    get_traces.domains = tracemalloc_copy_domains(tracemalloc_domains);
13757db96d56Sopenharmony_ci    TABLES_UNLOCK();
13767db96d56Sopenharmony_ci
13777db96d56Sopenharmony_ci    if (get_traces.domains == NULL) {
13787db96d56Sopenharmony_ci        goto no_memory;
13797db96d56Sopenharmony_ci    }
13807db96d56Sopenharmony_ci
13817db96d56Sopenharmony_ci    // Convert traces to a list of tuples
13827db96d56Sopenharmony_ci    set_reentrant(1);
13837db96d56Sopenharmony_ci    int err = _Py_hashtable_foreach(get_traces.traces,
13847db96d56Sopenharmony_ci                                    tracemalloc_get_traces_fill,
13857db96d56Sopenharmony_ci                                    &get_traces);
13867db96d56Sopenharmony_ci    if (!err) {
13877db96d56Sopenharmony_ci        err = _Py_hashtable_foreach(get_traces.domains,
13887db96d56Sopenharmony_ci                                    tracemalloc_get_traces_domain,
13897db96d56Sopenharmony_ci                                    &get_traces);
13907db96d56Sopenharmony_ci    }
13917db96d56Sopenharmony_ci    set_reentrant(0);
13927db96d56Sopenharmony_ci    if (err) {
13937db96d56Sopenharmony_ci        goto error;
13947db96d56Sopenharmony_ci    }
13957db96d56Sopenharmony_ci
13967db96d56Sopenharmony_ci    goto finally;
13977db96d56Sopenharmony_ci
13987db96d56Sopenharmony_cino_memory:
13997db96d56Sopenharmony_ci    PyErr_NoMemory();
14007db96d56Sopenharmony_ci
14017db96d56Sopenharmony_cierror:
14027db96d56Sopenharmony_ci    Py_CLEAR(get_traces.list);
14037db96d56Sopenharmony_ci
14047db96d56Sopenharmony_cifinally:
14057db96d56Sopenharmony_ci    if (get_traces.tracebacks != NULL) {
14067db96d56Sopenharmony_ci        _Py_hashtable_destroy(get_traces.tracebacks);
14077db96d56Sopenharmony_ci    }
14087db96d56Sopenharmony_ci    if (get_traces.traces != NULL) {
14097db96d56Sopenharmony_ci        _Py_hashtable_destroy(get_traces.traces);
14107db96d56Sopenharmony_ci    }
14117db96d56Sopenharmony_ci    if (get_traces.domains != NULL) {
14127db96d56Sopenharmony_ci        _Py_hashtable_destroy(get_traces.domains);
14137db96d56Sopenharmony_ci    }
14147db96d56Sopenharmony_ci
14157db96d56Sopenharmony_ci    return get_traces.list;
14167db96d56Sopenharmony_ci}
14177db96d56Sopenharmony_ci
14187db96d56Sopenharmony_ci
14197db96d56Sopenharmony_cistatic traceback_t*
14207db96d56Sopenharmony_citracemalloc_get_traceback(unsigned int domain, uintptr_t ptr)
14217db96d56Sopenharmony_ci{
14227db96d56Sopenharmony_ci
14237db96d56Sopenharmony_ci    if (!_Py_tracemalloc_config.tracing)
14247db96d56Sopenharmony_ci        return NULL;
14257db96d56Sopenharmony_ci
14267db96d56Sopenharmony_ci    trace_t *trace;
14277db96d56Sopenharmony_ci    TABLES_LOCK();
14287db96d56Sopenharmony_ci    _Py_hashtable_t *traces = tracemalloc_get_traces_table(domain);
14297db96d56Sopenharmony_ci    if (traces) {
14307db96d56Sopenharmony_ci        trace = _Py_hashtable_get(traces, TO_PTR(ptr));
14317db96d56Sopenharmony_ci    }
14327db96d56Sopenharmony_ci    else {
14337db96d56Sopenharmony_ci        trace = NULL;
14347db96d56Sopenharmony_ci    }
14357db96d56Sopenharmony_ci    TABLES_UNLOCK();
14367db96d56Sopenharmony_ci
14377db96d56Sopenharmony_ci    if (!trace) {
14387db96d56Sopenharmony_ci        return NULL;
14397db96d56Sopenharmony_ci    }
14407db96d56Sopenharmony_ci
14417db96d56Sopenharmony_ci    return trace->traceback;
14427db96d56Sopenharmony_ci}
14437db96d56Sopenharmony_ci
14447db96d56Sopenharmony_ci
14457db96d56Sopenharmony_ci
14467db96d56Sopenharmony_ci/*[clinic input]
14477db96d56Sopenharmony_ci_tracemalloc._get_object_traceback
14487db96d56Sopenharmony_ci
14497db96d56Sopenharmony_ci    obj: object
14507db96d56Sopenharmony_ci    /
14517db96d56Sopenharmony_ci
14527db96d56Sopenharmony_ciGet the traceback where the Python object obj was allocated.
14537db96d56Sopenharmony_ci
14547db96d56Sopenharmony_ciReturn a tuple of (filename: str, lineno: int) tuples.
14557db96d56Sopenharmony_ciReturn None if the tracemalloc module is disabled or did not
14567db96d56Sopenharmony_citrace the allocation of the object.
14577db96d56Sopenharmony_ci[clinic start generated code]*/
14587db96d56Sopenharmony_ci
14597db96d56Sopenharmony_cistatic PyObject *
14607db96d56Sopenharmony_ci_tracemalloc__get_object_traceback(PyObject *module, PyObject *obj)
14617db96d56Sopenharmony_ci/*[clinic end generated code: output=41ee0553a658b0aa input=29495f1b21c53212]*/
14627db96d56Sopenharmony_ci{
14637db96d56Sopenharmony_ci    PyTypeObject *type;
14647db96d56Sopenharmony_ci    void *ptr;
14657db96d56Sopenharmony_ci    traceback_t *traceback;
14667db96d56Sopenharmony_ci
14677db96d56Sopenharmony_ci    type = Py_TYPE(obj);
14687db96d56Sopenharmony_ci    if (PyType_IS_GC(type)) {
14697db96d56Sopenharmony_ci        ptr = (void *)((char *)obj - sizeof(PyGC_Head));
14707db96d56Sopenharmony_ci    }
14717db96d56Sopenharmony_ci    else {
14727db96d56Sopenharmony_ci        ptr = (void *)obj;
14737db96d56Sopenharmony_ci    }
14747db96d56Sopenharmony_ci
14757db96d56Sopenharmony_ci    traceback = tracemalloc_get_traceback(DEFAULT_DOMAIN, (uintptr_t)ptr);
14767db96d56Sopenharmony_ci    if (traceback == NULL)
14777db96d56Sopenharmony_ci        Py_RETURN_NONE;
14787db96d56Sopenharmony_ci
14797db96d56Sopenharmony_ci    return traceback_to_pyobject(traceback, NULL);
14807db96d56Sopenharmony_ci}
14817db96d56Sopenharmony_ci
14827db96d56Sopenharmony_ci
14837db96d56Sopenharmony_ci#define PUTS(fd, str) _Py_write_noraise(fd, str, (int)strlen(str))
14847db96d56Sopenharmony_ci
14857db96d56Sopenharmony_cistatic void
14867db96d56Sopenharmony_ci_PyMem_DumpFrame(int fd, frame_t * frame)
14877db96d56Sopenharmony_ci{
14887db96d56Sopenharmony_ci    PUTS(fd, "  File \"");
14897db96d56Sopenharmony_ci    _Py_DumpASCII(fd, frame->filename);
14907db96d56Sopenharmony_ci    PUTS(fd, "\", line ");
14917db96d56Sopenharmony_ci    _Py_DumpDecimal(fd, frame->lineno);
14927db96d56Sopenharmony_ci    PUTS(fd, "\n");
14937db96d56Sopenharmony_ci}
14947db96d56Sopenharmony_ci
14957db96d56Sopenharmony_ci/* Dump the traceback where a memory block was allocated into file descriptor
14967db96d56Sopenharmony_ci   fd. The function may block on TABLES_LOCK() but it is unlikely. */
14977db96d56Sopenharmony_civoid
14987db96d56Sopenharmony_ci_PyMem_DumpTraceback(int fd, const void *ptr)
14997db96d56Sopenharmony_ci{
15007db96d56Sopenharmony_ci    traceback_t *traceback;
15017db96d56Sopenharmony_ci    int i;
15027db96d56Sopenharmony_ci
15037db96d56Sopenharmony_ci    if (!_Py_tracemalloc_config.tracing) {
15047db96d56Sopenharmony_ci        PUTS(fd, "Enable tracemalloc to get the memory block "
15057db96d56Sopenharmony_ci                 "allocation traceback\n\n");
15067db96d56Sopenharmony_ci        return;
15077db96d56Sopenharmony_ci    }
15087db96d56Sopenharmony_ci
15097db96d56Sopenharmony_ci    traceback = tracemalloc_get_traceback(DEFAULT_DOMAIN, (uintptr_t)ptr);
15107db96d56Sopenharmony_ci    if (traceback == NULL)
15117db96d56Sopenharmony_ci        return;
15127db96d56Sopenharmony_ci
15137db96d56Sopenharmony_ci    PUTS(fd, "Memory block allocated at (most recent call first):\n");
15147db96d56Sopenharmony_ci    for (i=0; i < traceback->nframe; i++) {
15157db96d56Sopenharmony_ci        _PyMem_DumpFrame(fd, &traceback->frames[i]);
15167db96d56Sopenharmony_ci    }
15177db96d56Sopenharmony_ci    PUTS(fd, "\n");
15187db96d56Sopenharmony_ci}
15197db96d56Sopenharmony_ci
15207db96d56Sopenharmony_ci#undef PUTS
15217db96d56Sopenharmony_ci
15227db96d56Sopenharmony_ci
15237db96d56Sopenharmony_ci
15247db96d56Sopenharmony_ci/*[clinic input]
15257db96d56Sopenharmony_ci_tracemalloc.start
15267db96d56Sopenharmony_ci
15277db96d56Sopenharmony_ci    nframe: int = 1
15287db96d56Sopenharmony_ci    /
15297db96d56Sopenharmony_ci
15307db96d56Sopenharmony_ciStart tracing Python memory allocations.
15317db96d56Sopenharmony_ci
15327db96d56Sopenharmony_ciAlso set the maximum number of frames stored in the traceback of a
15337db96d56Sopenharmony_citrace to nframe.
15347db96d56Sopenharmony_ci[clinic start generated code]*/
15357db96d56Sopenharmony_ci
15367db96d56Sopenharmony_cistatic PyObject *
15377db96d56Sopenharmony_ci_tracemalloc_start_impl(PyObject *module, int nframe)
15387db96d56Sopenharmony_ci/*[clinic end generated code: output=caae05c23c159d3c input=40d849b5b29d1933]*/
15397db96d56Sopenharmony_ci{
15407db96d56Sopenharmony_ci    if (tracemalloc_start(nframe) < 0) {
15417db96d56Sopenharmony_ci        return NULL;
15427db96d56Sopenharmony_ci    }
15437db96d56Sopenharmony_ci    Py_RETURN_NONE;
15447db96d56Sopenharmony_ci}
15457db96d56Sopenharmony_ci
15467db96d56Sopenharmony_ci
15477db96d56Sopenharmony_ci/*[clinic input]
15487db96d56Sopenharmony_ci_tracemalloc.stop
15497db96d56Sopenharmony_ci
15507db96d56Sopenharmony_ciStop tracing Python memory allocations.
15517db96d56Sopenharmony_ci
15527db96d56Sopenharmony_ciAlso clear traces of memory blocks allocated by Python.
15537db96d56Sopenharmony_ci[clinic start generated code]*/
15547db96d56Sopenharmony_ci
15557db96d56Sopenharmony_cistatic PyObject *
15567db96d56Sopenharmony_ci_tracemalloc_stop_impl(PyObject *module)
15577db96d56Sopenharmony_ci/*[clinic end generated code: output=c3c42ae03e3955cd input=7478f075e51dae18]*/
15587db96d56Sopenharmony_ci{
15597db96d56Sopenharmony_ci    tracemalloc_stop();
15607db96d56Sopenharmony_ci    Py_RETURN_NONE;
15617db96d56Sopenharmony_ci}
15627db96d56Sopenharmony_ci
15637db96d56Sopenharmony_ci
15647db96d56Sopenharmony_ci/*[clinic input]
15657db96d56Sopenharmony_ci_tracemalloc.get_traceback_limit
15667db96d56Sopenharmony_ci
15677db96d56Sopenharmony_ciGet the maximum number of frames stored in the traceback of a trace.
15687db96d56Sopenharmony_ci
15697db96d56Sopenharmony_ciBy default, a trace of an allocated memory block only stores
15707db96d56Sopenharmony_cithe most recent frame: the limit is 1.
15717db96d56Sopenharmony_ci[clinic start generated code]*/
15727db96d56Sopenharmony_ci
15737db96d56Sopenharmony_cistatic PyObject *
15747db96d56Sopenharmony_ci_tracemalloc_get_traceback_limit_impl(PyObject *module)
15757db96d56Sopenharmony_ci/*[clinic end generated code: output=d556d9306ba95567 input=da3cd977fc68ae3b]*/
15767db96d56Sopenharmony_ci{
15777db96d56Sopenharmony_ci    return PyLong_FromLong(_Py_tracemalloc_config.max_nframe);
15787db96d56Sopenharmony_ci}
15797db96d56Sopenharmony_ci
15807db96d56Sopenharmony_ci
15817db96d56Sopenharmony_cistatic int
15827db96d56Sopenharmony_citracemalloc_get_tracemalloc_memory_cb(_Py_hashtable_t *domains,
15837db96d56Sopenharmony_ci                                      const void *key, const void *value,
15847db96d56Sopenharmony_ci                                      void *user_data)
15857db96d56Sopenharmony_ci{
15867db96d56Sopenharmony_ci    const _Py_hashtable_t *traces = value;
15877db96d56Sopenharmony_ci    size_t *size = (size_t*)user_data;
15887db96d56Sopenharmony_ci    *size += _Py_hashtable_size(traces);
15897db96d56Sopenharmony_ci    return 0;
15907db96d56Sopenharmony_ci}
15917db96d56Sopenharmony_ci
15927db96d56Sopenharmony_ci
15937db96d56Sopenharmony_ci/*[clinic input]
15947db96d56Sopenharmony_ci_tracemalloc.get_tracemalloc_memory
15957db96d56Sopenharmony_ci
15967db96d56Sopenharmony_ciGet the memory usage in bytes of the tracemalloc module.
15977db96d56Sopenharmony_ci
15987db96d56Sopenharmony_ciThis memory is used internally to trace memory allocations.
15997db96d56Sopenharmony_ci[clinic start generated code]*/
16007db96d56Sopenharmony_ci
16017db96d56Sopenharmony_cistatic PyObject *
16027db96d56Sopenharmony_ci_tracemalloc_get_tracemalloc_memory_impl(PyObject *module)
16037db96d56Sopenharmony_ci/*[clinic end generated code: output=e3f14e280a55f5aa input=5d919c0f4d5132ad]*/
16047db96d56Sopenharmony_ci{
16057db96d56Sopenharmony_ci    size_t size;
16067db96d56Sopenharmony_ci
16077db96d56Sopenharmony_ci    size = _Py_hashtable_size(tracemalloc_tracebacks);
16087db96d56Sopenharmony_ci    size += _Py_hashtable_size(tracemalloc_filenames);
16097db96d56Sopenharmony_ci
16107db96d56Sopenharmony_ci    TABLES_LOCK();
16117db96d56Sopenharmony_ci    size += _Py_hashtable_size(tracemalloc_traces);
16127db96d56Sopenharmony_ci    _Py_hashtable_foreach(tracemalloc_domains,
16137db96d56Sopenharmony_ci                          tracemalloc_get_tracemalloc_memory_cb, &size);
16147db96d56Sopenharmony_ci    TABLES_UNLOCK();
16157db96d56Sopenharmony_ci
16167db96d56Sopenharmony_ci    return PyLong_FromSize_t(size);
16177db96d56Sopenharmony_ci}
16187db96d56Sopenharmony_ci
16197db96d56Sopenharmony_ci
16207db96d56Sopenharmony_ci
16217db96d56Sopenharmony_ci/*[clinic input]
16227db96d56Sopenharmony_ci_tracemalloc.get_traced_memory
16237db96d56Sopenharmony_ci
16247db96d56Sopenharmony_ciGet the current size and peak size of memory blocks traced by tracemalloc.
16257db96d56Sopenharmony_ci
16267db96d56Sopenharmony_ciReturns a tuple: (current: int, peak: int).
16277db96d56Sopenharmony_ci[clinic start generated code]*/
16287db96d56Sopenharmony_ci
16297db96d56Sopenharmony_cistatic PyObject *
16307db96d56Sopenharmony_ci_tracemalloc_get_traced_memory_impl(PyObject *module)
16317db96d56Sopenharmony_ci/*[clinic end generated code: output=5b167189adb9e782 input=61ddb5478400ff66]*/
16327db96d56Sopenharmony_ci{
16337db96d56Sopenharmony_ci    Py_ssize_t size, peak_size;
16347db96d56Sopenharmony_ci
16357db96d56Sopenharmony_ci    if (!_Py_tracemalloc_config.tracing)
16367db96d56Sopenharmony_ci        return Py_BuildValue("ii", 0, 0);
16377db96d56Sopenharmony_ci
16387db96d56Sopenharmony_ci    TABLES_LOCK();
16397db96d56Sopenharmony_ci    size = tracemalloc_traced_memory;
16407db96d56Sopenharmony_ci    peak_size = tracemalloc_peak_traced_memory;
16417db96d56Sopenharmony_ci    TABLES_UNLOCK();
16427db96d56Sopenharmony_ci
16437db96d56Sopenharmony_ci    return Py_BuildValue("nn", size, peak_size);
16447db96d56Sopenharmony_ci}
16457db96d56Sopenharmony_ci
16467db96d56Sopenharmony_ci/*[clinic input]
16477db96d56Sopenharmony_ci_tracemalloc.reset_peak
16487db96d56Sopenharmony_ci
16497db96d56Sopenharmony_ciSet the peak size of memory blocks traced by tracemalloc to the current size.
16507db96d56Sopenharmony_ci
16517db96d56Sopenharmony_ciDo nothing if the tracemalloc module is not tracing memory allocations.
16527db96d56Sopenharmony_ci
16537db96d56Sopenharmony_ci[clinic start generated code]*/
16547db96d56Sopenharmony_ci
16557db96d56Sopenharmony_cistatic PyObject *
16567db96d56Sopenharmony_ci_tracemalloc_reset_peak_impl(PyObject *module)
16577db96d56Sopenharmony_ci/*[clinic end generated code: output=140c2870f691dbb2 input=18afd0635066e9ce]*/
16587db96d56Sopenharmony_ci{
16597db96d56Sopenharmony_ci    if (!_Py_tracemalloc_config.tracing) {
16607db96d56Sopenharmony_ci        Py_RETURN_NONE;
16617db96d56Sopenharmony_ci    }
16627db96d56Sopenharmony_ci
16637db96d56Sopenharmony_ci    TABLES_LOCK();
16647db96d56Sopenharmony_ci    tracemalloc_peak_traced_memory = tracemalloc_traced_memory;
16657db96d56Sopenharmony_ci    TABLES_UNLOCK();
16667db96d56Sopenharmony_ci
16677db96d56Sopenharmony_ci    Py_RETURN_NONE;
16687db96d56Sopenharmony_ci}
16697db96d56Sopenharmony_ci
16707db96d56Sopenharmony_ci
16717db96d56Sopenharmony_cistatic PyMethodDef module_methods[] = {
16727db96d56Sopenharmony_ci    _TRACEMALLOC_IS_TRACING_METHODDEF
16737db96d56Sopenharmony_ci    _TRACEMALLOC_CLEAR_TRACES_METHODDEF
16747db96d56Sopenharmony_ci    _TRACEMALLOC__GET_TRACES_METHODDEF
16757db96d56Sopenharmony_ci    _TRACEMALLOC__GET_OBJECT_TRACEBACK_METHODDEF
16767db96d56Sopenharmony_ci    _TRACEMALLOC_START_METHODDEF
16777db96d56Sopenharmony_ci    _TRACEMALLOC_STOP_METHODDEF
16787db96d56Sopenharmony_ci    _TRACEMALLOC_GET_TRACEBACK_LIMIT_METHODDEF
16797db96d56Sopenharmony_ci    _TRACEMALLOC_GET_TRACEMALLOC_MEMORY_METHODDEF
16807db96d56Sopenharmony_ci    _TRACEMALLOC_GET_TRACED_MEMORY_METHODDEF
16817db96d56Sopenharmony_ci    _TRACEMALLOC_RESET_PEAK_METHODDEF
16827db96d56Sopenharmony_ci    /* sentinel */
16837db96d56Sopenharmony_ci    {NULL, NULL}
16847db96d56Sopenharmony_ci};
16857db96d56Sopenharmony_ci
16867db96d56Sopenharmony_ciPyDoc_STRVAR(module_doc,
16877db96d56Sopenharmony_ci"Debug module to trace memory blocks allocated by Python.");
16887db96d56Sopenharmony_ci
16897db96d56Sopenharmony_cistatic struct PyModuleDef module_def = {
16907db96d56Sopenharmony_ci    PyModuleDef_HEAD_INIT,
16917db96d56Sopenharmony_ci    "_tracemalloc",
16927db96d56Sopenharmony_ci    module_doc,
16937db96d56Sopenharmony_ci    0, /* non-negative size to be able to unload the module */
16947db96d56Sopenharmony_ci    module_methods,
16957db96d56Sopenharmony_ci    NULL,
16967db96d56Sopenharmony_ci};
16977db96d56Sopenharmony_ci
16987db96d56Sopenharmony_ciPyMODINIT_FUNC
16997db96d56Sopenharmony_ciPyInit__tracemalloc(void)
17007db96d56Sopenharmony_ci{
17017db96d56Sopenharmony_ci    PyObject *m;
17027db96d56Sopenharmony_ci    m = PyModule_Create(&module_def);
17037db96d56Sopenharmony_ci    if (m == NULL)
17047db96d56Sopenharmony_ci        return NULL;
17057db96d56Sopenharmony_ci
17067db96d56Sopenharmony_ci    if (tracemalloc_init() < 0) {
17077db96d56Sopenharmony_ci        Py_DECREF(m);
17087db96d56Sopenharmony_ci        return NULL;
17097db96d56Sopenharmony_ci    }
17107db96d56Sopenharmony_ci
17117db96d56Sopenharmony_ci    return m;
17127db96d56Sopenharmony_ci}
17137db96d56Sopenharmony_ci
17147db96d56Sopenharmony_ci
17157db96d56Sopenharmony_ciint
17167db96d56Sopenharmony_ci_PyTraceMalloc_Init(int nframe)
17177db96d56Sopenharmony_ci{
17187db96d56Sopenharmony_ci    assert(PyGILState_Check());
17197db96d56Sopenharmony_ci    if (nframe == 0) {
17207db96d56Sopenharmony_ci        return 0;
17217db96d56Sopenharmony_ci    }
17227db96d56Sopenharmony_ci    return tracemalloc_start(nframe);
17237db96d56Sopenharmony_ci}
17247db96d56Sopenharmony_ci
17257db96d56Sopenharmony_ci
17267db96d56Sopenharmony_civoid
17277db96d56Sopenharmony_ci_PyTraceMalloc_Fini(void)
17287db96d56Sopenharmony_ci{
17297db96d56Sopenharmony_ci    assert(PyGILState_Check());
17307db96d56Sopenharmony_ci    tracemalloc_deinit();
17317db96d56Sopenharmony_ci}
17327db96d56Sopenharmony_ci
17337db96d56Sopenharmony_ciint
17347db96d56Sopenharmony_ciPyTraceMalloc_Track(unsigned int domain, uintptr_t ptr,
17357db96d56Sopenharmony_ci                    size_t size)
17367db96d56Sopenharmony_ci{
17377db96d56Sopenharmony_ci    int res;
17387db96d56Sopenharmony_ci    PyGILState_STATE gil_state;
17397db96d56Sopenharmony_ci
17407db96d56Sopenharmony_ci    if (!_Py_tracemalloc_config.tracing) {
17417db96d56Sopenharmony_ci        /* tracemalloc is not tracing: do nothing */
17427db96d56Sopenharmony_ci        return -2;
17437db96d56Sopenharmony_ci    }
17447db96d56Sopenharmony_ci
17457db96d56Sopenharmony_ci    gil_state = PyGILState_Ensure();
17467db96d56Sopenharmony_ci
17477db96d56Sopenharmony_ci    TABLES_LOCK();
17487db96d56Sopenharmony_ci    res = tracemalloc_add_trace(domain, ptr, size);
17497db96d56Sopenharmony_ci    TABLES_UNLOCK();
17507db96d56Sopenharmony_ci
17517db96d56Sopenharmony_ci    PyGILState_Release(gil_state);
17527db96d56Sopenharmony_ci    return res;
17537db96d56Sopenharmony_ci}
17547db96d56Sopenharmony_ci
17557db96d56Sopenharmony_ci
17567db96d56Sopenharmony_ciint
17577db96d56Sopenharmony_ciPyTraceMalloc_Untrack(unsigned int domain, uintptr_t ptr)
17587db96d56Sopenharmony_ci{
17597db96d56Sopenharmony_ci    if (!_Py_tracemalloc_config.tracing) {
17607db96d56Sopenharmony_ci        /* tracemalloc is not tracing: do nothing */
17617db96d56Sopenharmony_ci        return -2;
17627db96d56Sopenharmony_ci    }
17637db96d56Sopenharmony_ci
17647db96d56Sopenharmony_ci    TABLES_LOCK();
17657db96d56Sopenharmony_ci    tracemalloc_remove_trace(domain, ptr);
17667db96d56Sopenharmony_ci    TABLES_UNLOCK();
17677db96d56Sopenharmony_ci
17687db96d56Sopenharmony_ci    return 0;
17697db96d56Sopenharmony_ci}
17707db96d56Sopenharmony_ci
17717db96d56Sopenharmony_ci
17727db96d56Sopenharmony_ci/* If the object memory block is already traced, update its trace
17737db96d56Sopenharmony_ci   with the current Python traceback.
17747db96d56Sopenharmony_ci
17757db96d56Sopenharmony_ci   Do nothing if tracemalloc is not tracing memory allocations
17767db96d56Sopenharmony_ci   or if the object memory block is not already traced. */
17777db96d56Sopenharmony_ciint
17787db96d56Sopenharmony_ci_PyTraceMalloc_NewReference(PyObject *op)
17797db96d56Sopenharmony_ci{
17807db96d56Sopenharmony_ci    assert(PyGILState_Check());
17817db96d56Sopenharmony_ci
17827db96d56Sopenharmony_ci    if (!_Py_tracemalloc_config.tracing) {
17837db96d56Sopenharmony_ci        /* tracemalloc is not tracing: do nothing */
17847db96d56Sopenharmony_ci        return -1;
17857db96d56Sopenharmony_ci    }
17867db96d56Sopenharmony_ci
17877db96d56Sopenharmony_ci    uintptr_t ptr;
17887db96d56Sopenharmony_ci    PyTypeObject *type = Py_TYPE(op);
17897db96d56Sopenharmony_ci    if (PyType_IS_GC(type)) {
17907db96d56Sopenharmony_ci        ptr = (uintptr_t)((char *)op - sizeof(PyGC_Head));
17917db96d56Sopenharmony_ci    }
17927db96d56Sopenharmony_ci    else {
17937db96d56Sopenharmony_ci        ptr = (uintptr_t)op;
17947db96d56Sopenharmony_ci    }
17957db96d56Sopenharmony_ci
17967db96d56Sopenharmony_ci    int res = -1;
17977db96d56Sopenharmony_ci
17987db96d56Sopenharmony_ci    TABLES_LOCK();
17997db96d56Sopenharmony_ci    trace_t *trace = _Py_hashtable_get(tracemalloc_traces, TO_PTR(ptr));
18007db96d56Sopenharmony_ci    if (trace != NULL) {
18017db96d56Sopenharmony_ci        /* update the traceback of the memory block */
18027db96d56Sopenharmony_ci        traceback_t *traceback = traceback_new();
18037db96d56Sopenharmony_ci        if (traceback != NULL) {
18047db96d56Sopenharmony_ci            trace->traceback = traceback;
18057db96d56Sopenharmony_ci            res = 0;
18067db96d56Sopenharmony_ci        }
18077db96d56Sopenharmony_ci    }
18087db96d56Sopenharmony_ci    /* else: cannot track the object, its memory block size is unknown */
18097db96d56Sopenharmony_ci    TABLES_UNLOCK();
18107db96d56Sopenharmony_ci
18117db96d56Sopenharmony_ci    return res;
18127db96d56Sopenharmony_ci}
18137db96d56Sopenharmony_ci
18147db96d56Sopenharmony_ci
18157db96d56Sopenharmony_ciPyObject*
18167db96d56Sopenharmony_ci_PyTraceMalloc_GetTraceback(unsigned int domain, uintptr_t ptr)
18177db96d56Sopenharmony_ci{
18187db96d56Sopenharmony_ci    traceback_t *traceback;
18197db96d56Sopenharmony_ci
18207db96d56Sopenharmony_ci    traceback = tracemalloc_get_traceback(domain, ptr);
18217db96d56Sopenharmony_ci    if (traceback == NULL)
18227db96d56Sopenharmony_ci        Py_RETURN_NONE;
18237db96d56Sopenharmony_ci
18247db96d56Sopenharmony_ci    return traceback_to_pyobject(traceback, NULL);
18257db96d56Sopenharmony_ci}
1826