]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - gdb/testsuite/gdb.python/py-inferior-leak.py
Update copyright year range in header of all files managed by GDB
[thirdparty/binutils-gdb.git] / gdb / testsuite / gdb.python / py-inferior-leak.py
1 # Copyright (C) 2021-2023 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 tracemalloc
17 import gdb
18 import re
19
20 # A global variable in which we store a reference to the gdb.Inferior
21 # object sent to us in the new_inferior event.
22 inf = None
23
24 # Register the new_inferior event handler.
25 def new_inferior_handler(event):
26 global inf
27 inf = event.inferior
28
29
30 gdb.events.new_inferior.connect(new_inferior_handler)
31
32 # A global filters list, we only care about memory allocations
33 # originating from this script.
34 filters = [tracemalloc.Filter(True, "*py-inferior-leak.py")]
35
36 # Add a new inferior, and return the number of the new inferior.
37 def add_inferior():
38 output = gdb.execute("add-inferior", False, True)
39 m = re.search(r"Added inferior (\d+)", output)
40 if m:
41 num = int(m.group(1))
42 else:
43 raise RuntimeError("no match")
44 return num
45
46
47 # Run the test. When CLEAR is True we clear the global INF variable
48 # before comparing the before and after memory allocation traces.
49 # When CLEAR is False we leave INF set to reference the gdb.Inferior
50 # object, thus preventing the gdb.Inferior from being deallocated.
51 def test(clear):
52 global filters, inf
53
54 # Start tracing, and take a snapshot of the current allocations.
55 tracemalloc.start()
56 snapshot1 = tracemalloc.take_snapshot()
57
58 # Create an inferior, this triggers the new_inferior event, which
59 # in turn holds a reference to the new gdb.Inferior object in the
60 # global INF variable.
61 num = add_inferior()
62 gdb.execute("remove-inferiors %s" % num)
63
64 # Possibly clear the global INF variable.
65 if clear:
66 inf = None
67
68 # Now grab a second snapshot of memory allocations, and stop
69 # tracing memory allocations.
70 snapshot2 = tracemalloc.take_snapshot()
71 tracemalloc.stop()
72
73 # Filter the snapshots; we only care about allocations originating
74 # from this file.
75 snapshot1 = snapshot1.filter_traces(filters)
76 snapshot2 = snapshot2.filter_traces(filters)
77
78 # Compare the snapshots, this leaves only things that were
79 # allocated, but not deallocated since the first snapshot.
80 stats = snapshot2.compare_to(snapshot1, "traceback")
81
82 # Total up all the deallocated things.
83 total = 0
84 for stat in stats:
85 total += stat.size_diff
86 return total
87
88
89 # The first time we run this some global state will be allocated which
90 # shows up as memory that is allocated, but not released. So, run the
91 # test once and discard the result.
92 test(True)
93
94 # Now run the test twice, the first time we clear our global reference
95 # to the gdb.Inferior object, which should allow Python to deallocate
96 # the object. The second time we hold onto the global reference,
97 # preventing Python from performing the deallocation.
98 bytes_with_clear = test(True)
99 bytes_without_clear = test(False)
100
101 # The bug that used to exist in GDB was that even when we released the
102 # global reference the gdb.Inferior object would not be deallocated.
103 if bytes_with_clear > 0:
104 raise gdb.GdbError("memory leak when gdb.Inferior should be released")
105 if bytes_without_clear == 0:
106 raise gdb.GdbError("gdb.Inferior object is no longer allocated")
107
108 # Print a PASS message that the test script can see.
109 print("PASS")