]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - gdb/testsuite/gdb.python/py-inferior-leak.py
gdb, gdbserver, python, testsuite: Remove MPX.
[thirdparty/binutils-gdb.git] / gdb / testsuite / gdb.python / py-inferior-leak.py
1 # Copyright (C) 2021-2024 Free Software Foundation, Inc.
2
3 # This program is free software; you can redistribute it and/or modify
4 # it under the terms of the GNU General Public License as published by
5 # the Free Software Foundation; either version 3 of the License, or
6 # (at your option) any later version.
7 #
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
12 #
13 # You should have received a copy of the GNU General Public License
14 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15
16 import re
17 import tracemalloc
18
19 import gdb
20
21 # A global variable in which we store a reference to the gdb.Inferior
22 # object sent to us in the new_inferior event.
23 inf = None
24
25
26 # Register the new_inferior event handler.
27 def new_inferior_handler(event):
28 global inf
29 inf = event.inferior
30
31
32 gdb.events.new_inferior.connect(new_inferior_handler)
33
34 # A global filters list, we only care about memory allocations
35 # originating from this script.
36 filters = [tracemalloc.Filter(True, "*py-inferior-leak.py")]
37
38
39 # Add a new inferior, and return the number of the new inferior.
40 def add_inferior():
41 output = gdb.execute("add-inferior", False, True)
42 m = re.search(r"Added inferior (\d+)", output)
43 if m:
44 num = int(m.group(1))
45 else:
46 raise RuntimeError("no match")
47 return num
48
49
50 # Run the test. When CLEAR is True we clear the global INF variable
51 # before comparing the before and after memory allocation traces.
52 # When CLEAR is False we leave INF set to reference the gdb.Inferior
53 # object, thus preventing the gdb.Inferior from being deallocated.
54 def test(clear):
55 global filters, inf
56
57 # Start tracing, and take a snapshot of the current allocations.
58 tracemalloc.start()
59 snapshot1 = tracemalloc.take_snapshot()
60
61 # Create an inferior, this triggers the new_inferior event, which
62 # in turn holds a reference to the new gdb.Inferior object in the
63 # global INF variable.
64 num = add_inferior()
65 gdb.execute("remove-inferiors %s" % num)
66
67 # Possibly clear the global INF variable.
68 if clear:
69 inf = None
70
71 # Now grab a second snapshot of memory allocations, and stop
72 # tracing memory allocations.
73 snapshot2 = tracemalloc.take_snapshot()
74 tracemalloc.stop()
75
76 # Filter the snapshots; we only care about allocations originating
77 # from this file.
78 snapshot1 = snapshot1.filter_traces(filters)
79 snapshot2 = snapshot2.filter_traces(filters)
80
81 # Compare the snapshots, this leaves only things that were
82 # allocated, but not deallocated since the first snapshot.
83 stats = snapshot2.compare_to(snapshot1, "traceback")
84
85 # Total up all the deallocated things.
86 total = 0
87 for stat in stats:
88 total += stat.size_diff
89 return total
90
91
92 # The first time we run this some global state will be allocated which
93 # shows up as memory that is allocated, but not released. So, run the
94 # test once and discard the result.
95 test(True)
96
97 # Now run the test twice, the first time we clear our global reference
98 # to the gdb.Inferior object, which should allow Python to deallocate
99 # the object. The second time we hold onto the global reference,
100 # preventing Python from performing the deallocation.
101 bytes_with_clear = test(True)
102 bytes_without_clear = test(False)
103
104 # The bug that used to exist in GDB was that even when we released the
105 # global reference the gdb.Inferior object would not be deallocated.
106 if bytes_with_clear > 0:
107 raise gdb.GdbError("memory leak when gdb.Inferior should be released")
108 if bytes_without_clear == 0:
109 raise gdb.GdbError("gdb.Inferior object is no longer allocated")
110
111 # Print a PASS message that the test script can see.
112 print("PASS")