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