]>
git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - gdb/testsuite/gdb.python/py-inferior-leak.py
1 # Copyright (C) 2021-2023 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/>.
20 # A global variable in which we store a reference to the gdb.Inferior
21 # object sent to us in the new_inferior event.
24 # Register the new_inferior event handler.
25 def new_inferior_handler(event
):
30 gdb
.events
.new_inferior
.connect(new_inferior_handler
)
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")]
36 # Add a new inferior, and return the number of the new inferior.
38 output
= gdb
.execute("add-inferior", False, True)
39 m
= re
.search(r
"Added inferior (\d+)", output
)
43 raise RuntimeError("no match")
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.
54 # Start tracing, and take a snapshot of the current allocations.
56 snapshot1
= tracemalloc
.take_snapshot()
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.
62 gdb
.execute("remove-inferiors %s" % num
)
64 # Possibly clear the global INF variable.
68 # Now grab a second snapshot of memory allocations, and stop
69 # tracing memory allocations.
70 snapshot2
= tracemalloc
.take_snapshot()
73 # Filter the snapshots; we only care about allocations originating
75 snapshot1
= snapshot1
.filter_traces(filters
)
76 snapshot2
= snapshot2
.filter_traces(filters
)
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")
82 # Total up all the deallocated things.
85 total
+= stat
.size_diff
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.
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)
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")
108 # Print a PASS message that the test script can see.