tracemalloc.c 40 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604
  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_initconfig.h" // _PyStatus_NO_MEMORY()
  6. #include "pycore_object.h" // _PyType_PreHeaderSize
  7. #include "pycore_pymem.h" // _Py_tracemalloc_config
  8. #include "pycore_runtime.h" // _Py_ID()
  9. #include "pycore_traceback.h"
  10. #include <pycore_frame.h>
  11. #include "frameobject.h" // _PyInterpreterFrame_GetLine
  12. #include <stdlib.h> // malloc()
  13. #define tracemalloc_config _PyRuntime.tracemalloc.config
  14. _Py_DECLARE_STR(anon_unknown, "<unknown>");
  15. /* Forward declaration */
  16. static void* raw_malloc(size_t size);
  17. static void raw_free(void *ptr);
  18. #ifdef Py_DEBUG
  19. # define TRACE_DEBUG
  20. #endif
  21. #define TO_PTR(key) ((const void *)(uintptr_t)(key))
  22. #define FROM_PTR(key) ((uintptr_t)(key))
  23. #define allocators _PyRuntime.tracemalloc.allocators
  24. #if defined(TRACE_RAW_MALLOC)
  25. /* This lock is needed because tracemalloc_free() is called without
  26. the GIL held from PyMem_RawFree(). It cannot acquire the lock because it
  27. would introduce a deadlock in _PyThreadState_DeleteCurrent(). */
  28. # define tables_lock _PyRuntime.tracemalloc.tables_lock
  29. # define TABLES_LOCK() PyThread_acquire_lock(tables_lock, 1)
  30. # define TABLES_UNLOCK() PyThread_release_lock(tables_lock)
  31. #else
  32. /* variables are protected by the GIL */
  33. # define TABLES_LOCK()
  34. # define TABLES_UNLOCK()
  35. #endif
  36. #define DEFAULT_DOMAIN 0
  37. typedef struct tracemalloc_frame frame_t;
  38. typedef struct tracemalloc_traceback traceback_t;
  39. #define TRACEBACK_SIZE(NFRAME) \
  40. (sizeof(traceback_t) + sizeof(frame_t) * (NFRAME - 1))
  41. /* The maximum number of frames is either:
  42. - The maximum number of frames we can store in `traceback_t.nframe`
  43. - The maximum memory size_t we can allocate */
  44. static const unsigned long MAX_NFRAME = Py_MIN(UINT16_MAX, ((SIZE_MAX - sizeof(traceback_t)) / sizeof(frame_t) + 1));
  45. #define tracemalloc_empty_traceback _PyRuntime.tracemalloc.empty_traceback
  46. /* Trace of a memory block */
  47. typedef struct {
  48. /* Size of the memory block in bytes */
  49. size_t size;
  50. /* Traceback where the memory block was allocated */
  51. traceback_t *traceback;
  52. } trace_t;
  53. #define tracemalloc_traced_memory _PyRuntime.tracemalloc.traced_memory
  54. #define tracemalloc_peak_traced_memory _PyRuntime.tracemalloc.peak_traced_memory
  55. #define tracemalloc_filenames _PyRuntime.tracemalloc.filenames
  56. #define tracemalloc_traceback _PyRuntime.tracemalloc.traceback
  57. #define tracemalloc_tracebacks _PyRuntime.tracemalloc.tracebacks
  58. #define tracemalloc_traces _PyRuntime.tracemalloc.traces
  59. #define tracemalloc_domains _PyRuntime.tracemalloc.domains
  60. #ifdef TRACE_DEBUG
  61. static void
  62. tracemalloc_error(const char *format, ...)
  63. {
  64. va_list ap;
  65. fprintf(stderr, "tracemalloc: ");
  66. va_start(ap, format);
  67. vfprintf(stderr, format, ap);
  68. va_end(ap);
  69. fprintf(stderr, "\n");
  70. fflush(stderr);
  71. }
  72. #endif
  73. #if defined(TRACE_RAW_MALLOC)
  74. #define REENTRANT_THREADLOCAL
  75. #define tracemalloc_reentrant_key _PyRuntime.tracemalloc.reentrant_key
  76. /* Any non-NULL pointer can be used */
  77. #define REENTRANT Py_True
  78. static int
  79. get_reentrant(void)
  80. {
  81. void *ptr;
  82. assert(PyThread_tss_is_created(&tracemalloc_reentrant_key));
  83. ptr = PyThread_tss_get(&tracemalloc_reentrant_key);
  84. if (ptr != NULL) {
  85. assert(ptr == REENTRANT);
  86. return 1;
  87. }
  88. else
  89. return 0;
  90. }
  91. static void
  92. set_reentrant(int reentrant)
  93. {
  94. assert(reentrant == 0 || reentrant == 1);
  95. assert(PyThread_tss_is_created(&tracemalloc_reentrant_key));
  96. if (reentrant) {
  97. assert(!get_reentrant());
  98. PyThread_tss_set(&tracemalloc_reentrant_key, REENTRANT);
  99. }
  100. else {
  101. assert(get_reentrant());
  102. PyThread_tss_set(&tracemalloc_reentrant_key, NULL);
  103. }
  104. }
  105. #else
  106. /* TRACE_RAW_MALLOC not defined: variable protected by the GIL */
  107. static int tracemalloc_reentrant = 0;
  108. static int
  109. get_reentrant(void)
  110. {
  111. return tracemalloc_reentrant;
  112. }
  113. static void
  114. set_reentrant(int reentrant)
  115. {
  116. assert(reentrant != tracemalloc_reentrant);
  117. tracemalloc_reentrant = reentrant;
  118. }
  119. #endif
  120. static Py_uhash_t
  121. hashtable_hash_pyobject(const void *key)
  122. {
  123. PyObject *obj = (PyObject *)key;
  124. return PyObject_Hash(obj);
  125. }
  126. static int
  127. hashtable_compare_unicode(const void *key1, const void *key2)
  128. {
  129. PyObject *obj1 = (PyObject *)key1;
  130. PyObject *obj2 = (PyObject *)key2;
  131. if (obj1 != NULL && obj2 != NULL) {
  132. return (PyUnicode_Compare(obj1, obj2) == 0);
  133. }
  134. else {
  135. return obj1 == obj2;
  136. }
  137. }
  138. static Py_uhash_t
  139. hashtable_hash_uint(const void *key_raw)
  140. {
  141. unsigned int key = (unsigned int)FROM_PTR(key_raw);
  142. return (Py_uhash_t)key;
  143. }
  144. static _Py_hashtable_t *
  145. hashtable_new(_Py_hashtable_hash_func hash_func,
  146. _Py_hashtable_compare_func compare_func,
  147. _Py_hashtable_destroy_func key_destroy_func,
  148. _Py_hashtable_destroy_func value_destroy_func)
  149. {
  150. _Py_hashtable_allocator_t hashtable_alloc = {malloc, free};
  151. return _Py_hashtable_new_full(hash_func, compare_func,
  152. key_destroy_func, value_destroy_func,
  153. &hashtable_alloc);
  154. }
  155. static void*
  156. raw_malloc(size_t size)
  157. {
  158. return allocators.raw.malloc(allocators.raw.ctx, size);
  159. }
  160. static void
  161. raw_free(void *ptr)
  162. {
  163. allocators.raw.free(allocators.raw.ctx, ptr);
  164. }
  165. static Py_uhash_t
  166. hashtable_hash_traceback(const void *key)
  167. {
  168. const traceback_t *traceback = (const traceback_t *)key;
  169. return traceback->hash;
  170. }
  171. static int
  172. hashtable_compare_traceback(const void *key1, const void *key2)
  173. {
  174. const traceback_t *traceback1 = (const traceback_t *)key1;
  175. const traceback_t *traceback2 = (const traceback_t *)key2;
  176. if (traceback1->nframe != traceback2->nframe) {
  177. return 0;
  178. }
  179. if (traceback1->total_nframe != traceback2->total_nframe) {
  180. return 0;
  181. }
  182. for (int i=0; i < traceback1->nframe; i++) {
  183. const frame_t *frame1 = &traceback1->frames[i];
  184. const frame_t *frame2 = &traceback2->frames[i];
  185. if (frame1->lineno != frame2->lineno) {
  186. return 0;
  187. }
  188. if (frame1->filename != frame2->filename) {
  189. assert(PyUnicode_Compare(frame1->filename, frame2->filename) != 0);
  190. return 0;
  191. }
  192. }
  193. return 1;
  194. }
  195. static void
  196. tracemalloc_get_frame(_PyInterpreterFrame *pyframe, frame_t *frame)
  197. {
  198. frame->filename = &_Py_STR(anon_unknown);
  199. int lineno = PyUnstable_InterpreterFrame_GetLine(pyframe);
  200. if (lineno < 0) {
  201. lineno = 0;
  202. }
  203. frame->lineno = (unsigned int)lineno;
  204. PyObject *filename = pyframe->f_code->co_filename;
  205. if (filename == NULL) {
  206. #ifdef TRACE_DEBUG
  207. tracemalloc_error("failed to get the filename of the code object");
  208. #endif
  209. return;
  210. }
  211. if (!PyUnicode_Check(filename)) {
  212. #ifdef TRACE_DEBUG
  213. tracemalloc_error("filename is not a unicode string");
  214. #endif
  215. return;
  216. }
  217. if (!PyUnicode_IS_READY(filename)) {
  218. /* Don't make a Unicode string ready to avoid reentrant calls
  219. to tracemalloc_malloc() or tracemalloc_realloc() */
  220. #ifdef TRACE_DEBUG
  221. tracemalloc_error("filename is not a ready unicode string");
  222. #endif
  223. return;
  224. }
  225. /* intern the filename */
  226. _Py_hashtable_entry_t *entry;
  227. entry = _Py_hashtable_get_entry(tracemalloc_filenames, filename);
  228. if (entry != NULL) {
  229. filename = (PyObject *)entry->key;
  230. }
  231. else {
  232. /* tracemalloc_filenames is responsible to keep a reference
  233. to the filename */
  234. if (_Py_hashtable_set(tracemalloc_filenames, Py_NewRef(filename),
  235. NULL) < 0) {
  236. Py_DECREF(filename);
  237. #ifdef TRACE_DEBUG
  238. tracemalloc_error("failed to intern the filename");
  239. #endif
  240. return;
  241. }
  242. }
  243. /* the tracemalloc_filenames table keeps a reference to the filename */
  244. frame->filename = filename;
  245. }
  246. static Py_uhash_t
  247. traceback_hash(traceback_t *traceback)
  248. {
  249. /* code based on tuplehash() of Objects/tupleobject.c */
  250. Py_uhash_t x, y; /* Unsigned for defined overflow behavior. */
  251. int len = traceback->nframe;
  252. Py_uhash_t mult = _PyHASH_MULTIPLIER;
  253. frame_t *frame;
  254. x = 0x345678UL;
  255. frame = traceback->frames;
  256. while (--len >= 0) {
  257. y = (Py_uhash_t)PyObject_Hash(frame->filename);
  258. y ^= (Py_uhash_t)frame->lineno;
  259. frame++;
  260. x = (x ^ y) * mult;
  261. /* the cast might truncate len; that doesn't change hash stability */
  262. mult += (Py_uhash_t)(82520UL + len + len);
  263. }
  264. x ^= traceback->total_nframe;
  265. x += 97531UL;
  266. return x;
  267. }
  268. static void
  269. traceback_get_frames(traceback_t *traceback)
  270. {
  271. PyThreadState *tstate = PyGILState_GetThisThreadState();
  272. if (tstate == NULL) {
  273. #ifdef TRACE_DEBUG
  274. tracemalloc_error("failed to get the current thread state");
  275. #endif
  276. return;
  277. }
  278. _PyInterpreterFrame *pyframe = _PyThreadState_GetFrame(tstate);
  279. while (pyframe) {
  280. if (traceback->nframe < tracemalloc_config.max_nframe) {
  281. tracemalloc_get_frame(pyframe, &traceback->frames[traceback->nframe]);
  282. assert(traceback->frames[traceback->nframe].filename != NULL);
  283. traceback->nframe++;
  284. }
  285. if (traceback->total_nframe < UINT16_MAX) {
  286. traceback->total_nframe++;
  287. }
  288. pyframe = _PyFrame_GetFirstComplete(pyframe->previous);
  289. }
  290. }
  291. static traceback_t *
  292. traceback_new(void)
  293. {
  294. traceback_t *traceback;
  295. _Py_hashtable_entry_t *entry;
  296. assert(PyGILState_Check());
  297. /* get frames */
  298. traceback = tracemalloc_traceback;
  299. traceback->nframe = 0;
  300. traceback->total_nframe = 0;
  301. traceback_get_frames(traceback);
  302. if (traceback->nframe == 0)
  303. return &tracemalloc_empty_traceback;
  304. traceback->hash = traceback_hash(traceback);
  305. /* intern the traceback */
  306. entry = _Py_hashtable_get_entry(tracemalloc_tracebacks, traceback);
  307. if (entry != NULL) {
  308. traceback = (traceback_t *)entry->key;
  309. }
  310. else {
  311. traceback_t *copy;
  312. size_t traceback_size;
  313. traceback_size = TRACEBACK_SIZE(traceback->nframe);
  314. copy = raw_malloc(traceback_size);
  315. if (copy == NULL) {
  316. #ifdef TRACE_DEBUG
  317. tracemalloc_error("failed to intern the traceback: malloc failed");
  318. #endif
  319. return NULL;
  320. }
  321. memcpy(copy, traceback, traceback_size);
  322. if (_Py_hashtable_set(tracemalloc_tracebacks, copy, NULL) < 0) {
  323. raw_free(copy);
  324. #ifdef TRACE_DEBUG
  325. tracemalloc_error("failed to intern the traceback: putdata failed");
  326. #endif
  327. return NULL;
  328. }
  329. traceback = copy;
  330. }
  331. return traceback;
  332. }
  333. static _Py_hashtable_t*
  334. tracemalloc_create_traces_table(void)
  335. {
  336. return hashtable_new(_Py_hashtable_hash_ptr,
  337. _Py_hashtable_compare_direct,
  338. NULL, raw_free);
  339. }
  340. static _Py_hashtable_t*
  341. tracemalloc_create_domains_table(void)
  342. {
  343. return hashtable_new(hashtable_hash_uint,
  344. _Py_hashtable_compare_direct,
  345. NULL,
  346. (_Py_hashtable_destroy_func)_Py_hashtable_destroy);
  347. }
  348. static _Py_hashtable_t*
  349. tracemalloc_get_traces_table(unsigned int domain)
  350. {
  351. if (domain == DEFAULT_DOMAIN) {
  352. return tracemalloc_traces;
  353. }
  354. else {
  355. return _Py_hashtable_get(tracemalloc_domains, TO_PTR(domain));
  356. }
  357. }
  358. static void
  359. tracemalloc_remove_trace(unsigned int domain, uintptr_t ptr)
  360. {
  361. assert(tracemalloc_config.tracing);
  362. _Py_hashtable_t *traces = tracemalloc_get_traces_table(domain);
  363. if (!traces) {
  364. return;
  365. }
  366. trace_t *trace = _Py_hashtable_steal(traces, TO_PTR(ptr));
  367. if (!trace) {
  368. return;
  369. }
  370. assert(tracemalloc_traced_memory >= trace->size);
  371. tracemalloc_traced_memory -= trace->size;
  372. raw_free(trace);
  373. }
  374. #define REMOVE_TRACE(ptr) \
  375. tracemalloc_remove_trace(DEFAULT_DOMAIN, (uintptr_t)(ptr))
  376. static int
  377. tracemalloc_add_trace(unsigned int domain, uintptr_t ptr,
  378. size_t size)
  379. {
  380. assert(tracemalloc_config.tracing);
  381. traceback_t *traceback = traceback_new();
  382. if (traceback == NULL) {
  383. return -1;
  384. }
  385. _Py_hashtable_t *traces = tracemalloc_get_traces_table(domain);
  386. if (traces == NULL) {
  387. traces = tracemalloc_create_traces_table();
  388. if (traces == NULL) {
  389. return -1;
  390. }
  391. if (_Py_hashtable_set(tracemalloc_domains, TO_PTR(domain), traces) < 0) {
  392. _Py_hashtable_destroy(traces);
  393. return -1;
  394. }
  395. }
  396. trace_t *trace = _Py_hashtable_get(traces, TO_PTR(ptr));
  397. if (trace != NULL) {
  398. /* the memory block is already tracked */
  399. assert(tracemalloc_traced_memory >= trace->size);
  400. tracemalloc_traced_memory -= trace->size;
  401. trace->size = size;
  402. trace->traceback = traceback;
  403. }
  404. else {
  405. trace = raw_malloc(sizeof(trace_t));
  406. if (trace == NULL) {
  407. return -1;
  408. }
  409. trace->size = size;
  410. trace->traceback = traceback;
  411. int res = _Py_hashtable_set(traces, TO_PTR(ptr), trace);
  412. if (res != 0) {
  413. raw_free(trace);
  414. return res;
  415. }
  416. }
  417. assert(tracemalloc_traced_memory <= SIZE_MAX - size);
  418. tracemalloc_traced_memory += size;
  419. if (tracemalloc_traced_memory > tracemalloc_peak_traced_memory) {
  420. tracemalloc_peak_traced_memory = tracemalloc_traced_memory;
  421. }
  422. return 0;
  423. }
  424. #define ADD_TRACE(ptr, size) \
  425. tracemalloc_add_trace(DEFAULT_DOMAIN, (uintptr_t)(ptr), size)
  426. static void*
  427. tracemalloc_alloc(int use_calloc, void *ctx, size_t nelem, size_t elsize)
  428. {
  429. PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx;
  430. void *ptr;
  431. assert(elsize == 0 || nelem <= SIZE_MAX / elsize);
  432. if (use_calloc)
  433. ptr = alloc->calloc(alloc->ctx, nelem, elsize);
  434. else
  435. ptr = alloc->malloc(alloc->ctx, nelem * elsize);
  436. if (ptr == NULL)
  437. return NULL;
  438. TABLES_LOCK();
  439. if (tracemalloc_config.tracing) {
  440. if (ADD_TRACE(ptr, nelem * elsize) < 0) {
  441. /* Failed to allocate a trace for the new memory block */
  442. alloc->free(alloc->ctx, ptr);
  443. ptr = NULL;
  444. }
  445. }
  446. // else: gh-128679: tracemalloc.stop() was called by another thread
  447. TABLES_UNLOCK();
  448. return ptr;
  449. }
  450. static void*
  451. tracemalloc_realloc(void *ctx, void *ptr, size_t new_size)
  452. {
  453. PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx;
  454. void *ptr2;
  455. ptr2 = alloc->realloc(alloc->ctx, ptr, new_size);
  456. if (ptr2 == NULL)
  457. return NULL;
  458. TABLES_LOCK();
  459. if (!tracemalloc_config.tracing) {
  460. // gh-128679: tracemalloc.stop() was called by another thread
  461. goto done;
  462. }
  463. if (ptr != NULL) {
  464. /* an existing memory block has been resized */
  465. /* tracemalloc_add_trace() updates the trace if there is already
  466. a trace at address ptr2 */
  467. if (ptr2 != ptr) {
  468. REMOVE_TRACE(ptr);
  469. }
  470. if (ADD_TRACE(ptr2, new_size) < 0) {
  471. /* Memory allocation failed. The error cannot be reported to
  472. the caller, because realloc() may already have shrunk the
  473. memory block and so removed bytes.
  474. This case is very unlikely: a hash entry has just been
  475. released, so the hash table should have at least one free entry.
  476. The GIL and the table lock ensures that only one thread is
  477. allocating memory. */
  478. Py_FatalError("tracemalloc_realloc() failed to allocate a trace");
  479. }
  480. }
  481. else {
  482. /* new allocation */
  483. if (ADD_TRACE(ptr2, new_size) < 0) {
  484. /* Failed to allocate a trace for the new memory block */
  485. alloc->free(alloc->ctx, ptr2);
  486. ptr2 = NULL;
  487. }
  488. }
  489. done:
  490. TABLES_UNLOCK();
  491. return ptr2;
  492. }
  493. static void
  494. tracemalloc_free(void *ctx, void *ptr)
  495. {
  496. PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx;
  497. if (ptr == NULL)
  498. return;
  499. /* GIL cannot be locked in PyMem_RawFree() because it would introduce
  500. a deadlock in _PyThreadState_DeleteCurrent(). */
  501. alloc->free(alloc->ctx, ptr);
  502. TABLES_LOCK();
  503. if (tracemalloc_config.tracing) {
  504. REMOVE_TRACE(ptr);
  505. }
  506. // else: gh-128679: tracemalloc.stop() was called by another thread
  507. TABLES_UNLOCK();
  508. }
  509. static void*
  510. tracemalloc_alloc_gil(int use_calloc, void *ctx, size_t nelem, size_t elsize)
  511. {
  512. void *ptr;
  513. if (get_reentrant()) {
  514. PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx;
  515. if (use_calloc)
  516. return alloc->calloc(alloc->ctx, nelem, elsize);
  517. else
  518. return alloc->malloc(alloc->ctx, nelem * elsize);
  519. }
  520. /* Ignore reentrant call. PyObjet_Malloc() calls PyMem_Malloc() for
  521. allocations larger than 512 bytes, don't trace the same memory
  522. allocation twice. */
  523. set_reentrant(1);
  524. ptr = tracemalloc_alloc(use_calloc, ctx, nelem, elsize);
  525. set_reentrant(0);
  526. return ptr;
  527. }
  528. static void*
  529. tracemalloc_malloc_gil(void *ctx, size_t size)
  530. {
  531. return tracemalloc_alloc_gil(0, ctx, 1, size);
  532. }
  533. static void*
  534. tracemalloc_calloc_gil(void *ctx, size_t nelem, size_t elsize)
  535. {
  536. return tracemalloc_alloc_gil(1, ctx, nelem, elsize);
  537. }
  538. static void*
  539. tracemalloc_realloc_gil(void *ctx, void *ptr, size_t new_size)
  540. {
  541. void *ptr2;
  542. if (get_reentrant()) {
  543. /* Reentrant call to PyMem_Realloc() and PyMem_RawRealloc().
  544. Example: PyMem_RawRealloc() is called internally by pymalloc
  545. (_PyObject_Malloc() and _PyObject_Realloc()) to allocate a new
  546. arena (new_arena()). */
  547. PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx;
  548. ptr2 = alloc->realloc(alloc->ctx, ptr, new_size);
  549. if (ptr2 != NULL && ptr != NULL) {
  550. TABLES_LOCK();
  551. if (tracemalloc_config.tracing) {
  552. REMOVE_TRACE(ptr);
  553. }
  554. TABLES_UNLOCK();
  555. }
  556. return ptr2;
  557. }
  558. /* Ignore reentrant call. PyObjet_Realloc() calls PyMem_Realloc() for
  559. allocations larger than 512 bytes. Don't trace the same memory
  560. allocation twice. */
  561. set_reentrant(1);
  562. ptr2 = tracemalloc_realloc(ctx, ptr, new_size);
  563. set_reentrant(0);
  564. return ptr2;
  565. }
  566. #ifdef TRACE_RAW_MALLOC
  567. static void*
  568. tracemalloc_raw_alloc(int use_calloc, void *ctx, size_t nelem, size_t elsize)
  569. {
  570. PyGILState_STATE gil_state;
  571. void *ptr;
  572. if (get_reentrant()) {
  573. PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx;
  574. if (use_calloc)
  575. return alloc->calloc(alloc->ctx, nelem, elsize);
  576. else
  577. return alloc->malloc(alloc->ctx, nelem * elsize);
  578. }
  579. /* Ignore reentrant call. PyGILState_Ensure() may call PyMem_RawMalloc()
  580. indirectly which would call PyGILState_Ensure() if reentrant are not
  581. disabled. */
  582. set_reentrant(1);
  583. gil_state = PyGILState_Ensure();
  584. ptr = tracemalloc_alloc(use_calloc, ctx, nelem, elsize);
  585. PyGILState_Release(gil_state);
  586. set_reentrant(0);
  587. return ptr;
  588. }
  589. static void*
  590. tracemalloc_raw_malloc(void *ctx, size_t size)
  591. {
  592. return tracemalloc_raw_alloc(0, ctx, 1, size);
  593. }
  594. static void*
  595. tracemalloc_raw_calloc(void *ctx, size_t nelem, size_t elsize)
  596. {
  597. return tracemalloc_raw_alloc(1, ctx, nelem, elsize);
  598. }
  599. static void*
  600. tracemalloc_raw_realloc(void *ctx, void *ptr, size_t new_size)
  601. {
  602. PyGILState_STATE gil_state;
  603. void *ptr2;
  604. if (get_reentrant()) {
  605. /* Reentrant call to PyMem_RawRealloc(). */
  606. PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx;
  607. ptr2 = alloc->realloc(alloc->ctx, ptr, new_size);
  608. if (ptr2 != NULL && ptr != NULL) {
  609. TABLES_LOCK();
  610. if (tracemalloc_config.tracing) {
  611. REMOVE_TRACE(ptr);
  612. }
  613. TABLES_UNLOCK();
  614. }
  615. return ptr2;
  616. }
  617. /* Ignore reentrant call. PyGILState_Ensure() may call PyMem_RawMalloc()
  618. indirectly which would call PyGILState_Ensure() if reentrant calls are
  619. not disabled. */
  620. set_reentrant(1);
  621. gil_state = PyGILState_Ensure();
  622. ptr2 = tracemalloc_realloc(ctx, ptr, new_size);
  623. PyGILState_Release(gil_state);
  624. set_reentrant(0);
  625. return ptr2;
  626. }
  627. #endif /* TRACE_RAW_MALLOC */
  628. static void
  629. tracemalloc_clear_filename(void *value)
  630. {
  631. PyObject *filename = (PyObject *)value;
  632. Py_DECREF(filename);
  633. }
  634. /* reentrant flag must be set to call this function and GIL must be held */
  635. static void
  636. tracemalloc_clear_traces_unlocked(void)
  637. {
  638. set_reentrant(1);
  639. /* The GIL protects variables against concurrent access */
  640. assert(PyGILState_Check());
  641. _Py_hashtable_clear(tracemalloc_traces);
  642. _Py_hashtable_clear(tracemalloc_domains);
  643. tracemalloc_traced_memory = 0;
  644. tracemalloc_peak_traced_memory = 0;
  645. _Py_hashtable_clear(tracemalloc_tracebacks);
  646. _Py_hashtable_clear(tracemalloc_filenames);
  647. set_reentrant(0);
  648. }
  649. PyStatus
  650. _PyTraceMalloc_Init(void)
  651. {
  652. assert(tracemalloc_config.initialized == TRACEMALLOC_NOT_INITIALIZED);
  653. PyMem_GetAllocator(PYMEM_DOMAIN_RAW, &allocators.raw);
  654. #ifdef REENTRANT_THREADLOCAL
  655. if (PyThread_tss_create(&tracemalloc_reentrant_key) != 0) {
  656. return _PyStatus_NO_MEMORY();
  657. }
  658. #endif
  659. #if defined(TRACE_RAW_MALLOC)
  660. if (tables_lock == NULL) {
  661. tables_lock = PyThread_allocate_lock();
  662. if (tables_lock == NULL) {
  663. return _PyStatus_NO_MEMORY();
  664. }
  665. }
  666. #endif
  667. tracemalloc_filenames = hashtable_new(hashtable_hash_pyobject,
  668. hashtable_compare_unicode,
  669. tracemalloc_clear_filename, NULL);
  670. tracemalloc_tracebacks = hashtable_new(hashtable_hash_traceback,
  671. hashtable_compare_traceback,
  672. raw_free, NULL);
  673. tracemalloc_traces = tracemalloc_create_traces_table();
  674. tracemalloc_domains = tracemalloc_create_domains_table();
  675. if (tracemalloc_filenames == NULL || tracemalloc_tracebacks == NULL
  676. || tracemalloc_traces == NULL || tracemalloc_domains == NULL)
  677. {
  678. return _PyStatus_NO_MEMORY();
  679. }
  680. tracemalloc_empty_traceback.nframe = 1;
  681. tracemalloc_empty_traceback.total_nframe = 1;
  682. /* borrowed reference */
  683. tracemalloc_empty_traceback.frames[0].filename = &_Py_STR(anon_unknown);
  684. tracemalloc_empty_traceback.frames[0].lineno = 0;
  685. tracemalloc_empty_traceback.hash = traceback_hash(&tracemalloc_empty_traceback);
  686. tracemalloc_config.initialized = TRACEMALLOC_INITIALIZED;
  687. return _PyStatus_OK();
  688. }
  689. static void
  690. tracemalloc_deinit(void)
  691. {
  692. if (tracemalloc_config.initialized != TRACEMALLOC_INITIALIZED)
  693. return;
  694. tracemalloc_config.initialized = TRACEMALLOC_FINALIZED;
  695. _PyTraceMalloc_Stop();
  696. /* destroy hash tables */
  697. _Py_hashtable_destroy(tracemalloc_domains);
  698. _Py_hashtable_destroy(tracemalloc_traces);
  699. _Py_hashtable_destroy(tracemalloc_tracebacks);
  700. _Py_hashtable_destroy(tracemalloc_filenames);
  701. #if defined(TRACE_RAW_MALLOC)
  702. if (tables_lock != NULL) {
  703. PyThread_free_lock(tables_lock);
  704. tables_lock = NULL;
  705. }
  706. #endif
  707. #ifdef REENTRANT_THREADLOCAL
  708. PyThread_tss_delete(&tracemalloc_reentrant_key);
  709. #endif
  710. }
  711. int
  712. _PyTraceMalloc_Start(int max_nframe)
  713. {
  714. PyMemAllocatorEx alloc;
  715. size_t size;
  716. if (max_nframe < 1 || (unsigned long) max_nframe > MAX_NFRAME) {
  717. PyErr_Format(PyExc_ValueError,
  718. "the number of frames must be in range [1; %lu]",
  719. MAX_NFRAME);
  720. return -1;
  721. }
  722. if (tracemalloc_config.tracing) {
  723. /* hook already installed: do nothing */
  724. return 0;
  725. }
  726. tracemalloc_config.max_nframe = max_nframe;
  727. /* allocate a buffer to store a new traceback */
  728. size = TRACEBACK_SIZE(max_nframe);
  729. assert(tracemalloc_traceback == NULL);
  730. tracemalloc_traceback = raw_malloc(size);
  731. if (tracemalloc_traceback == NULL) {
  732. PyErr_NoMemory();
  733. return -1;
  734. }
  735. #ifdef TRACE_RAW_MALLOC
  736. alloc.malloc = tracemalloc_raw_malloc;
  737. alloc.calloc = tracemalloc_raw_calloc;
  738. alloc.realloc = tracemalloc_raw_realloc;
  739. alloc.free = tracemalloc_free;
  740. alloc.ctx = &allocators.raw;
  741. PyMem_GetAllocator(PYMEM_DOMAIN_RAW, &allocators.raw);
  742. PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &alloc);
  743. #endif
  744. alloc.malloc = tracemalloc_malloc_gil;
  745. alloc.calloc = tracemalloc_calloc_gil;
  746. alloc.realloc = tracemalloc_realloc_gil;
  747. alloc.free = tracemalloc_free;
  748. alloc.ctx = &allocators.mem;
  749. PyMem_GetAllocator(PYMEM_DOMAIN_MEM, &allocators.mem);
  750. PyMem_SetAllocator(PYMEM_DOMAIN_MEM, &alloc);
  751. alloc.ctx = &allocators.obj;
  752. PyMem_GetAllocator(PYMEM_DOMAIN_OBJ, &allocators.obj);
  753. PyMem_SetAllocator(PYMEM_DOMAIN_OBJ, &alloc);
  754. /* everything is ready: start tracing Python memory allocations */
  755. tracemalloc_config.tracing = 1;
  756. return 0;
  757. }
  758. void
  759. _PyTraceMalloc_Stop(void)
  760. {
  761. // Lock to synchronize with tracemalloc_free() which checks
  762. // 'tracing' while holding the lock.
  763. TABLES_LOCK();
  764. if (!tracemalloc_config.tracing) {
  765. goto done;
  766. }
  767. /* stop tracing Python memory allocations */
  768. tracemalloc_config.tracing = 0;
  769. /* unregister the hook on memory allocators */
  770. #ifdef TRACE_RAW_MALLOC
  771. PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &allocators.raw);
  772. #endif
  773. PyMem_SetAllocator(PYMEM_DOMAIN_MEM, &allocators.mem);
  774. PyMem_SetAllocator(PYMEM_DOMAIN_OBJ, &allocators.obj);
  775. tracemalloc_clear_traces_unlocked();
  776. /* release memory */
  777. raw_free(tracemalloc_traceback);
  778. tracemalloc_traceback = NULL;
  779. done:
  780. TABLES_UNLOCK();
  781. }
  782. static PyObject*
  783. frame_to_pyobject(frame_t *frame)
  784. {
  785. PyObject *frame_obj, *lineno_obj;
  786. frame_obj = PyTuple_New(2);
  787. if (frame_obj == NULL)
  788. return NULL;
  789. PyTuple_SET_ITEM(frame_obj, 0, Py_NewRef(frame->filename));
  790. lineno_obj = PyLong_FromUnsignedLong(frame->lineno);
  791. if (lineno_obj == NULL) {
  792. Py_DECREF(frame_obj);
  793. return NULL;
  794. }
  795. PyTuple_SET_ITEM(frame_obj, 1, lineno_obj);
  796. return frame_obj;
  797. }
  798. static PyObject*
  799. traceback_to_pyobject(traceback_t *traceback, _Py_hashtable_t *intern_table)
  800. {
  801. PyObject *frames;
  802. if (intern_table != NULL) {
  803. frames = _Py_hashtable_get(intern_table, (const void *)traceback);
  804. if (frames) {
  805. return Py_NewRef(frames);
  806. }
  807. }
  808. frames = PyTuple_New(traceback->nframe);
  809. if (frames == NULL)
  810. return NULL;
  811. for (int i=0; i < traceback->nframe; i++) {
  812. PyObject *frame = frame_to_pyobject(&traceback->frames[i]);
  813. if (frame == NULL) {
  814. Py_DECREF(frames);
  815. return NULL;
  816. }
  817. PyTuple_SET_ITEM(frames, i, frame);
  818. }
  819. if (intern_table != NULL) {
  820. if (_Py_hashtable_set(intern_table, traceback, frames) < 0) {
  821. Py_DECREF(frames);
  822. PyErr_NoMemory();
  823. return NULL;
  824. }
  825. /* intern_table keeps a new reference to frames */
  826. Py_INCREF(frames);
  827. }
  828. return frames;
  829. }
  830. static PyObject*
  831. trace_to_pyobject(unsigned int domain, const trace_t *trace,
  832. _Py_hashtable_t *intern_tracebacks)
  833. {
  834. PyObject *trace_obj = NULL;
  835. PyObject *obj;
  836. trace_obj = PyTuple_New(4);
  837. if (trace_obj == NULL)
  838. return NULL;
  839. obj = PyLong_FromSize_t(domain);
  840. if (obj == NULL) {
  841. Py_DECREF(trace_obj);
  842. return NULL;
  843. }
  844. PyTuple_SET_ITEM(trace_obj, 0, obj);
  845. obj = PyLong_FromSize_t(trace->size);
  846. if (obj == NULL) {
  847. Py_DECREF(trace_obj);
  848. return NULL;
  849. }
  850. PyTuple_SET_ITEM(trace_obj, 1, obj);
  851. obj = traceback_to_pyobject(trace->traceback, intern_tracebacks);
  852. if (obj == NULL) {
  853. Py_DECREF(trace_obj);
  854. return NULL;
  855. }
  856. PyTuple_SET_ITEM(trace_obj, 2, obj);
  857. obj = PyLong_FromUnsignedLong(trace->traceback->total_nframe);
  858. if (obj == NULL) {
  859. Py_DECREF(trace_obj);
  860. return NULL;
  861. }
  862. PyTuple_SET_ITEM(trace_obj, 3, obj);
  863. return trace_obj;
  864. }
  865. typedef struct {
  866. _Py_hashtable_t *traces;
  867. _Py_hashtable_t *domains;
  868. _Py_hashtable_t *tracebacks;
  869. PyObject *list;
  870. unsigned int domain;
  871. } get_traces_t;
  872. static int
  873. tracemalloc_copy_trace(_Py_hashtable_t *traces,
  874. const void *key, const void *value,
  875. void *user_data)
  876. {
  877. _Py_hashtable_t *traces2 = (_Py_hashtable_t *)user_data;
  878. trace_t *trace = (trace_t *)value;
  879. trace_t *trace2 = raw_malloc(sizeof(trace_t));
  880. if (trace2 == NULL) {
  881. return -1;
  882. }
  883. *trace2 = *trace;
  884. if (_Py_hashtable_set(traces2, key, trace2) < 0) {
  885. raw_free(trace2);
  886. return -1;
  887. }
  888. return 0;
  889. }
  890. static _Py_hashtable_t*
  891. tracemalloc_copy_traces(_Py_hashtable_t *traces)
  892. {
  893. _Py_hashtable_t *traces2 = tracemalloc_create_traces_table();
  894. if (traces2 == NULL) {
  895. return NULL;
  896. }
  897. int err = _Py_hashtable_foreach(traces,
  898. tracemalloc_copy_trace,
  899. traces2);
  900. if (err) {
  901. _Py_hashtable_destroy(traces2);
  902. return NULL;
  903. }
  904. return traces2;
  905. }
  906. static int
  907. tracemalloc_copy_domain(_Py_hashtable_t *domains,
  908. const void *key, const void *value,
  909. void *user_data)
  910. {
  911. _Py_hashtable_t *domains2 = (_Py_hashtable_t *)user_data;
  912. unsigned int domain = (unsigned int)FROM_PTR(key);
  913. _Py_hashtable_t *traces = (_Py_hashtable_t *)value;
  914. _Py_hashtable_t *traces2 = tracemalloc_copy_traces(traces);
  915. if (traces2 == NULL) {
  916. return -1;
  917. }
  918. if (_Py_hashtable_set(domains2, TO_PTR(domain), traces2) < 0) {
  919. _Py_hashtable_destroy(traces2);
  920. return -1;
  921. }
  922. return 0;
  923. }
  924. static _Py_hashtable_t*
  925. tracemalloc_copy_domains(_Py_hashtable_t *domains)
  926. {
  927. _Py_hashtable_t *domains2 = tracemalloc_create_domains_table();
  928. if (domains2 == NULL) {
  929. return NULL;
  930. }
  931. int err = _Py_hashtable_foreach(domains,
  932. tracemalloc_copy_domain,
  933. domains2);
  934. if (err) {
  935. _Py_hashtable_destroy(domains2);
  936. return NULL;
  937. }
  938. return domains2;
  939. }
  940. static int
  941. tracemalloc_get_traces_fill(_Py_hashtable_t *traces,
  942. const void *key, const void *value,
  943. void *user_data)
  944. {
  945. get_traces_t *get_traces = user_data;
  946. const trace_t *trace = (const trace_t *)value;
  947. PyObject *tuple = trace_to_pyobject(get_traces->domain, trace,
  948. get_traces->tracebacks);
  949. if (tuple == NULL) {
  950. return 1;
  951. }
  952. int res = PyList_Append(get_traces->list, tuple);
  953. Py_DECREF(tuple);
  954. if (res < 0) {
  955. return 1;
  956. }
  957. return 0;
  958. }
  959. static int
  960. tracemalloc_get_traces_domain(_Py_hashtable_t *domains,
  961. const void *key, const void *value,
  962. void *user_data)
  963. {
  964. get_traces_t *get_traces = user_data;
  965. unsigned int domain = (unsigned int)FROM_PTR(key);
  966. _Py_hashtable_t *traces = (_Py_hashtable_t *)value;
  967. get_traces->domain = domain;
  968. return _Py_hashtable_foreach(traces,
  969. tracemalloc_get_traces_fill,
  970. get_traces);
  971. }
  972. static void
  973. tracemalloc_pyobject_decref(void *value)
  974. {
  975. PyObject *obj = (PyObject *)value;
  976. Py_DECREF(obj);
  977. }
  978. static traceback_t*
  979. tracemalloc_get_traceback_unlocked(unsigned int domain, uintptr_t ptr)
  980. {
  981. if (!tracemalloc_config.tracing) {
  982. return NULL;
  983. }
  984. _Py_hashtable_t *traces = tracemalloc_get_traces_table(domain);
  985. trace_t *trace = NULL;
  986. if (traces) {
  987. trace = _Py_hashtable_get(traces, TO_PTR(ptr));
  988. }
  989. if (!trace) {
  990. return NULL;
  991. }
  992. return trace->traceback;
  993. }
  994. #define PUTS(fd, str) _Py_write_noraise(fd, str, (int)strlen(str))
  995. static void
  996. _PyMem_DumpFrame(int fd, frame_t * frame)
  997. {
  998. PUTS(fd, " File \"");
  999. _Py_DumpASCII(fd, frame->filename);
  1000. PUTS(fd, "\", line ");
  1001. _Py_DumpDecimal(fd, frame->lineno);
  1002. PUTS(fd, "\n");
  1003. }
  1004. /* Dump the traceback where a memory block was allocated into file descriptor
  1005. fd. The function may block on TABLES_LOCK() but it is unlikely. */
  1006. void
  1007. _PyMem_DumpTraceback(int fd, const void *ptr)
  1008. {
  1009. traceback_t *traceback;
  1010. int i;
  1011. TABLES_LOCK();
  1012. if (tracemalloc_config.tracing) {
  1013. traceback = tracemalloc_get_traceback_unlocked(DEFAULT_DOMAIN,
  1014. (uintptr_t)ptr);
  1015. }
  1016. else {
  1017. traceback = NULL;
  1018. PUTS(fd, "Enable tracemalloc to get the memory block "
  1019. "allocation traceback\n\n");
  1020. }
  1021. TABLES_UNLOCK();
  1022. if (traceback == NULL)
  1023. return;
  1024. PUTS(fd, "Memory block allocated at (most recent call first):\n");
  1025. for (i=0; i < traceback->nframe; i++) {
  1026. _PyMem_DumpFrame(fd, &traceback->frames[i]);
  1027. }
  1028. PUTS(fd, "\n");
  1029. }
  1030. #undef PUTS
  1031. static int
  1032. tracemalloc_get_tracemalloc_memory_cb(_Py_hashtable_t *domains,
  1033. const void *key, const void *value,
  1034. void *user_data)
  1035. {
  1036. const _Py_hashtable_t *traces = value;
  1037. size_t *size = (size_t*)user_data;
  1038. *size += _Py_hashtable_size(traces);
  1039. return 0;
  1040. }
  1041. int
  1042. PyTraceMalloc_Track(unsigned int domain, uintptr_t ptr,
  1043. size_t size)
  1044. {
  1045. PyGILState_STATE gil_state = PyGILState_Ensure();
  1046. int result;
  1047. // gh-129185: Check before TABLES_LOCK() to support calls after
  1048. // _PyTraceMalloc_Fini().
  1049. if (!tracemalloc_config.tracing) {
  1050. result = -2;
  1051. goto done;
  1052. }
  1053. TABLES_LOCK();
  1054. if (tracemalloc_config.tracing) {
  1055. result = tracemalloc_add_trace(domain, ptr, size);
  1056. }
  1057. else {
  1058. // gh-128679: tracemalloc.stop() was called by another thread
  1059. result = -2;
  1060. }
  1061. TABLES_UNLOCK();
  1062. done:
  1063. PyGILState_Release(gil_state);
  1064. return result;
  1065. }
  1066. int
  1067. PyTraceMalloc_Untrack(unsigned int domain, uintptr_t ptr)
  1068. {
  1069. // Need the GIL to prevent races on the first 'tracing' test
  1070. PyGILState_STATE gil_state = PyGILState_Ensure();
  1071. int result;
  1072. // gh-129185: Check before TABLES_LOCK() to support calls after
  1073. // _PyTraceMalloc_Fini()
  1074. if (!tracemalloc_config.tracing) {
  1075. result = -2;
  1076. goto done;
  1077. }
  1078. TABLES_LOCK();
  1079. if (tracemalloc_config.tracing) {
  1080. tracemalloc_remove_trace(domain, ptr);
  1081. result = 0;
  1082. }
  1083. else {
  1084. /* tracemalloc is not tracing: do nothing */
  1085. result = -2;
  1086. }
  1087. TABLES_UNLOCK();
  1088. done:
  1089. PyGILState_Release(gil_state);
  1090. return result;
  1091. }
  1092. void
  1093. _PyTraceMalloc_Fini(void)
  1094. {
  1095. assert(PyGILState_Check());
  1096. tracemalloc_deinit();
  1097. }
  1098. /* If the object memory block is already traced, update its trace
  1099. with the current Python traceback.
  1100. Do nothing if tracemalloc is not tracing memory allocations
  1101. or if the object memory block is not already traced. */
  1102. int
  1103. _PyTraceMalloc_NewReference(PyObject *op)
  1104. {
  1105. assert(PyGILState_Check());
  1106. if (!tracemalloc_config.tracing) {
  1107. /* tracemalloc is not tracing: do nothing */
  1108. return -1;
  1109. }
  1110. PyTypeObject *type = Py_TYPE(op);
  1111. const size_t presize = _PyType_PreHeaderSize(type);
  1112. uintptr_t ptr = (uintptr_t)((char *)op - presize);
  1113. int res = -1;
  1114. TABLES_LOCK();
  1115. if (!tracemalloc_config.tracing) {
  1116. // gh-128679: tracemalloc.stop() was called by another thread
  1117. goto done;
  1118. }
  1119. trace_t *trace = _Py_hashtable_get(tracemalloc_traces, TO_PTR(ptr));
  1120. if (trace != NULL) {
  1121. /* update the traceback of the memory block */
  1122. traceback_t *traceback = traceback_new();
  1123. if (traceback != NULL) {
  1124. trace->traceback = traceback;
  1125. res = 0;
  1126. }
  1127. }
  1128. /* else: cannot track the object, its memory block size is unknown */
  1129. done:
  1130. TABLES_UNLOCK();
  1131. return res;
  1132. }
  1133. PyObject*
  1134. _PyTraceMalloc_GetTraceback(unsigned int domain, uintptr_t ptr)
  1135. {
  1136. traceback_t *traceback;
  1137. TABLES_LOCK();
  1138. traceback = tracemalloc_get_traceback_unlocked(domain, ptr);
  1139. TABLES_UNLOCK();
  1140. if (traceback == NULL)
  1141. Py_RETURN_NONE;
  1142. return traceback_to_pyobject(traceback, NULL);
  1143. }
  1144. int
  1145. _PyTraceMalloc_IsTracing(void)
  1146. {
  1147. TABLES_LOCK();
  1148. int tracing = tracemalloc_config.tracing;
  1149. TABLES_UNLOCK();
  1150. return tracing;
  1151. }
  1152. void
  1153. _PyTraceMalloc_ClearTraces(void)
  1154. {
  1155. TABLES_LOCK();
  1156. if (tracemalloc_config.tracing) {
  1157. tracemalloc_clear_traces_unlocked();
  1158. }
  1159. TABLES_UNLOCK();
  1160. }
  1161. PyObject *
  1162. _PyTraceMalloc_GetTraces(void)
  1163. {
  1164. get_traces_t get_traces;
  1165. get_traces.domain = DEFAULT_DOMAIN;
  1166. get_traces.traces = NULL;
  1167. get_traces.domains = NULL;
  1168. get_traces.tracebacks = NULL;
  1169. get_traces.list = PyList_New(0);
  1170. if (get_traces.list == NULL)
  1171. goto error;
  1172. if (!tracemalloc_config.tracing)
  1173. return get_traces.list;
  1174. /* the traceback hash table is used temporarily to intern traceback tuple
  1175. of (filename, lineno) tuples */
  1176. get_traces.tracebacks = hashtable_new(_Py_hashtable_hash_ptr,
  1177. _Py_hashtable_compare_direct,
  1178. NULL, tracemalloc_pyobject_decref);
  1179. if (get_traces.tracebacks == NULL) {
  1180. goto no_memory;
  1181. }
  1182. // Copy all traces so tracemalloc_get_traces_fill() doesn't have to disable
  1183. // temporarily tracemalloc which would impact other threads and so would
  1184. // miss allocations while get_traces() is called.
  1185. TABLES_LOCK();
  1186. get_traces.traces = tracemalloc_copy_traces(tracemalloc_traces);
  1187. TABLES_UNLOCK();
  1188. if (get_traces.traces == NULL) {
  1189. goto no_memory;
  1190. }
  1191. TABLES_LOCK();
  1192. get_traces.domains = tracemalloc_copy_domains(tracemalloc_domains);
  1193. TABLES_UNLOCK();
  1194. if (get_traces.domains == NULL) {
  1195. goto no_memory;
  1196. }
  1197. // Convert traces to a list of tuples
  1198. set_reentrant(1);
  1199. int err = _Py_hashtable_foreach(get_traces.traces,
  1200. tracemalloc_get_traces_fill,
  1201. &get_traces);
  1202. if (!err) {
  1203. err = _Py_hashtable_foreach(get_traces.domains,
  1204. tracemalloc_get_traces_domain,
  1205. &get_traces);
  1206. }
  1207. set_reentrant(0);
  1208. if (err) {
  1209. goto error;
  1210. }
  1211. goto finally;
  1212. no_memory:
  1213. PyErr_NoMemory();
  1214. error:
  1215. Py_CLEAR(get_traces.list);
  1216. finally:
  1217. if (get_traces.tracebacks != NULL) {
  1218. _Py_hashtable_destroy(get_traces.tracebacks);
  1219. }
  1220. if (get_traces.traces != NULL) {
  1221. _Py_hashtable_destroy(get_traces.traces);
  1222. }
  1223. if (get_traces.domains != NULL) {
  1224. _Py_hashtable_destroy(get_traces.domains);
  1225. }
  1226. return get_traces.list;
  1227. }
  1228. PyObject *
  1229. _PyTraceMalloc_GetObjectTraceback(PyObject *obj)
  1230. /*[clinic end generated code: output=41ee0553a658b0aa input=29495f1b21c53212]*/
  1231. {
  1232. PyTypeObject *type = Py_TYPE(obj);
  1233. const size_t presize = _PyType_PreHeaderSize(type);
  1234. uintptr_t ptr = (uintptr_t)((char *)obj - presize);
  1235. return _PyTraceMalloc_GetTraceback(DEFAULT_DOMAIN, ptr);
  1236. }
  1237. int _PyTraceMalloc_GetTracebackLimit(void) {
  1238. return tracemalloc_config.max_nframe;
  1239. }
  1240. size_t
  1241. _PyTraceMalloc_GetMemory(void) {
  1242. size_t size;
  1243. TABLES_LOCK();
  1244. if (tracemalloc_config.tracing) {
  1245. size = _Py_hashtable_size(tracemalloc_tracebacks);
  1246. size += _Py_hashtable_size(tracemalloc_filenames);
  1247. size += _Py_hashtable_size(tracemalloc_traces);
  1248. _Py_hashtable_foreach(tracemalloc_domains,
  1249. tracemalloc_get_tracemalloc_memory_cb, &size);
  1250. }
  1251. else {
  1252. size = 0;
  1253. }
  1254. TABLES_UNLOCK();
  1255. return size;
  1256. }
  1257. PyObject *
  1258. _PyTraceMalloc_GetTracedMemory(void)
  1259. {
  1260. Py_ssize_t size, peak_size;
  1261. TABLES_LOCK();
  1262. if (tracemalloc_config.tracing) {
  1263. size = tracemalloc_traced_memory;
  1264. peak_size = tracemalloc_peak_traced_memory;
  1265. }
  1266. else {
  1267. size = 0;
  1268. peak_size = 0;
  1269. }
  1270. TABLES_UNLOCK();
  1271. return Py_BuildValue("nn", size, peak_size);
  1272. }
  1273. void
  1274. _PyTraceMalloc_ResetPeak(void)
  1275. {
  1276. TABLES_LOCK();
  1277. if (tracemalloc_config.tracing) {
  1278. tracemalloc_peak_traced_memory = tracemalloc_traced_memory;
  1279. }
  1280. TABLES_UNLOCK();
  1281. }