Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commite3b3e01

Browse files
authored
[3.13]gh-129185: Fix PyTraceMalloc_Untrack() at Python exit (#129191) (#129217)
gh-129185: Fix PyTraceMalloc_Untrack() at Python exit (#129191)Support calling PyTraceMalloc_Track() and PyTraceMalloc_Untrack()during late Python finalization.* Call _PyTraceMalloc_Fini() later in Python finalization.* Test also PyTraceMalloc_Untrack() without the GIL* PyTraceMalloc_Untrack() now gets the GIL.* Test also PyTraceMalloc_Untrack() in test_tracemalloc_track_race().(cherry picked from commit46c7e13)
1 parentd674792 commite3b3e01

File tree

5 files changed

+78
-14
lines changed

5 files changed

+78
-14
lines changed

‎Lib/test/test_tracemalloc.py‎

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
importcontextlib
22
importos
33
importsys
4+
importtextwrap
45
importtracemalloc
56
importunittest
67
fromunittest.mockimportpatch
@@ -19,6 +20,7 @@
1920
_testinternalcapi=None
2021

2122

23+
DEFAULT_DOMAIN=0
2224
EMPTY_STRING_SIZE=sys.getsizeof(b'')
2325
INVALID_NFRAME= (-1,2**30)
2426

@@ -1027,8 +1029,8 @@ def track(self, release_gil=False, nframe=1):
10271029
release_gil)
10281030
returnframes
10291031

1030-
defuntrack(self):
1031-
_testcapi.tracemalloc_untrack(self.domain,self.ptr)
1032+
defuntrack(self,release_gil=False):
1033+
_testcapi.tracemalloc_untrack(self.domain,self.ptr,release_gil)
10321034

10331035
defget_traced_memory(self):
10341036
# Get the traced size in the domain
@@ -1070,21 +1072,27 @@ def test_track_already_tracked(self):
10701072
self.assertEqual(self.get_traceback(),
10711073
tracemalloc.Traceback(frames))
10721074

1073-
deftest_untrack(self):
1075+
defcheck_untrack(self,release_gil):
10741076
tracemalloc.start()
10751077

10761078
self.track()
10771079
self.assertIsNotNone(self.get_traceback())
10781080
self.assertEqual(self.get_traced_memory(),self.size)
10791081

10801082
# untrack must remove the trace
1081-
self.untrack()
1083+
self.untrack(release_gil)
10821084
self.assertIsNone(self.get_traceback())
10831085
self.assertEqual(self.get_traced_memory(),0)
10841086

10851087
# calling _PyTraceMalloc_Untrack() multiple times must not crash
1086-
self.untrack()
1087-
self.untrack()
1088+
self.untrack(release_gil)
1089+
self.untrack(release_gil)
1090+
1091+
deftest_untrack(self):
1092+
self.check_untrack(False)
1093+
1094+
deftest_untrack_without_gil(self):
1095+
self.check_untrack(True)
10881096

10891097
deftest_stop_track(self):
10901098
tracemalloc.start()
@@ -1110,6 +1118,29 @@ def test_tracemalloc_track_race(self):
11101118
# gh-128679: Test fix for tracemalloc.stop() race condition
11111119
_testcapi.tracemalloc_track_race()
11121120

1121+
deftest_late_untrack(self):
1122+
code=textwrap.dedent(f"""
1123+
from test import support
1124+
import tracemalloc
1125+
import _testcapi
1126+
1127+
class Tracked:
1128+
def __init__(self, domain, size):
1129+
self.domain = domain
1130+
self.ptr = id(self)
1131+
self.size = size
1132+
_testcapi.tracemalloc_track(self.domain, self.ptr, self.size)
1133+
1134+
def __del__(self, untrack=_testcapi.tracemalloc_untrack):
1135+
untrack(self.domain, self.ptr, 1)
1136+
1137+
domain ={DEFAULT_DOMAIN}
1138+
tracemalloc.start()
1139+
obj = Tracked(domain, 1024 * 1024)
1140+
support.late_deletion(obj)
1141+
""")
1142+
assert_python_ok("-c",code)
1143+
11131144

11141145
if__name__=="__main__":
11151146
unittest.main()

‎Modules/_testcapi/mem.c‎

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -557,16 +557,25 @@ tracemalloc_untrack(PyObject *self, PyObject *args)
557557
{
558558
unsignedintdomain;
559559
PyObject*ptr_obj;
560+
intrelease_gil=0;
560561

561-
if (!PyArg_ParseTuple(args,"IO",&domain,&ptr_obj)) {
562+
if (!PyArg_ParseTuple(args,"IO|i",&domain,&ptr_obj,&release_gil)) {
562563
returnNULL;
563564
}
564565
void*ptr=PyLong_AsVoidPtr(ptr_obj);
565566
if (PyErr_Occurred()) {
566567
returnNULL;
567568
}
568569

569-
intres=PyTraceMalloc_Untrack(domain, (uintptr_t)ptr);
570+
intres;
571+
if (release_gil) {
572+
Py_BEGIN_ALLOW_THREADS
573+
res=PyTraceMalloc_Untrack(domain, (uintptr_t)ptr);
574+
Py_END_ALLOW_THREADS
575+
}
576+
else {
577+
res=PyTraceMalloc_Untrack(domain, (uintptr_t)ptr);
578+
}
570579
if (res<0) {
571580
PyErr_SetString(PyExc_RuntimeError,"PyTraceMalloc_Untrack error");
572581
returnNULL;

‎Modules/_testcapimodule.c‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3327,6 +3327,7 @@ static void
33273327
tracemalloc_track_race_thread(void*data)
33283328
{
33293329
PyTraceMalloc_Track(123,10,1);
3330+
PyTraceMalloc_Untrack(123,10);
33303331

33313332
PyThread_type_locklock= (PyThread_type_lock)data;
33323333
PyThread_release_lock(lock);

‎Python/pylifecycle.c‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2156,7 +2156,7 @@ _Py_Finalize(_PyRuntimeState *runtime)
21562156

21572157
/* Disable tracemalloc after all Python objects have been destroyed,
21582158
so it is possible to use tracemalloc in objects destructor. */
2159-
_PyTraceMalloc_Fini();
2159+
_PyTraceMalloc_Stop();
21602160

21612161
/* Finalize any remaining import state */
21622162
// XXX Move these up to where finalize_modules() is currently.
@@ -2209,6 +2209,8 @@ _Py_Finalize(_PyRuntimeState *runtime)
22092209

22102210
finalize_interp_clear(tstate);
22112211

2212+
_PyTraceMalloc_Fini();
2213+
22122214
#ifdefPy_TRACE_REFS
22132215
/* Display addresses (& refcnts) of all objects still alive.
22142216
* An address can be used to find the repr of the object, printed

‎Python/tracemalloc.c‎

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1319,29 +1319,48 @@ PyTraceMalloc_Track(unsigned int domain, uintptr_t ptr,
13191319
size_tsize)
13201320
{
13211321
PyGILState_STATEgil_state=PyGILState_Ensure();
1322+
intresult;
1323+
1324+
// gh-129185: Check before TABLES_LOCK() to support calls after
1325+
// _PyTraceMalloc_Fini().
1326+
if (!tracemalloc_config.tracing) {
1327+
result=-2;
1328+
gotodone;
1329+
}
1330+
13221331
TABLES_LOCK();
13231332

1324-
intres;
13251333
if (tracemalloc_config.tracing) {
1326-
res=tracemalloc_add_trace(domain,ptr,size);
1334+
result=tracemalloc_add_trace(domain,ptr,size);
13271335
}
13281336
else {
13291337
// gh-128679: tracemalloc.stop() was called by another thread
1330-
res=-2;
1338+
result=-2;
13311339
}
13321340

13331341
TABLES_UNLOCK();
1342+
done:
13341343
PyGILState_Release(gil_state);
1335-
returnres;
1344+
returnresult;
13361345
}
13371346

13381347

13391348
int
13401349
PyTraceMalloc_Untrack(unsignedintdomain,uintptr_tptr)
13411350
{
1351+
// Need the GIL to prevent races on the first 'tracing' test
1352+
PyGILState_STATEgil_state=PyGILState_Ensure();
1353+
intresult;
1354+
1355+
// gh-129185: Check before TABLES_LOCK() to support calls after
1356+
// _PyTraceMalloc_Fini()
1357+
if (!tracemalloc_config.tracing) {
1358+
result=-2;
1359+
gotodone;
1360+
}
1361+
13421362
TABLES_LOCK();
13431363

1344-
intresult;
13451364
if (tracemalloc_config.tracing) {
13461365
tracemalloc_remove_trace(domain,ptr);
13471366
result=0;
@@ -1352,6 +1371,8 @@ PyTraceMalloc_Untrack(unsigned int domain, uintptr_t ptr)
13521371
}
13531372

13541373
TABLES_UNLOCK();
1374+
done:
1375+
PyGILState_Release(gil_state);
13551376
returnresult;
13561377
}
13571378

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp