]>
git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - gdb/testsuite/gdb.python/py-inferior-leak.py
1 # Copyright (C) 2021-2024 Free Software Foundation, Inc.
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.
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.
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/>.
21 # A global variable in which we store a reference to the gdb.Inferior
22 # object sent to us in the new_inferior event.
26 # Register the new_inferior event handler.
27 def new_inferior_handler(event
):
32 gdb
.events
.new_inferior
.connect(new_inferior_handler
)
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")]
39 # Add a new inferior, and return the number of the new inferior.
41 output
= gdb
.execute("add-inferior", False, True)
42 m
= re
.search(r
"Added inferior (\d+)", output
)
46 raise RuntimeError("no match")
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.
57 # Start tracing, and take a snapshot of the current allocations.
59 snapshot1
= tracemalloc
.take_snapshot()
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.
65 gdb
.execute("remove-inferiors %s" % num
)
67 # Possibly clear the global INF variable.
71 # Now grab a second snapshot of memory allocations, and stop
72 # tracing memory allocations.
73 snapshot2
= tracemalloc
.take_snapshot()
76 # Filter the snapshots; we only care about allocations originating
78 snapshot1
= snapshot1
.filter_traces(filters
)
79 snapshot2
= snapshot2
.filter_traces(filters
)
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")
85 # Total up all the deallocated things.
88 total
+= stat
.size_diff
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.
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)
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")
111 # Print a PASS message that the test script can see.