Skip to content

Commit 617dba1

Browse files
author
Magne Hov
committed
fixup! Add malloc free leak detector scripts
1 parent 59de618 commit 617dba1

File tree

4 files changed

+21
-15
lines changed

4 files changed

+21
-15
lines changed

_linters/mypy-stubs/gdb/__init__.pyi

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ class Breakpoint(object):
217217
commands: Optional[str]
218218
def __init__(
219219
self,
220-
spec: str,
220+
spec: str = ...,
221221
type: gdbtypes.BreakpointType = ...,
222222
wp_class: gdbtypes.WatchPointType = ...,
223223
internal: bool = ...,
@@ -232,7 +232,8 @@ class Breakpoint(object):
232232
def is_valid(self) -> bool: ...
233233
def delete(self) -> None: ...
234234

235-
class FinishBreakpoint(Breakpoint): ...
235+
class FinishBreakpoint(Breakpoint):
236+
return_value: Optional[Value]
236237

237238
class Symbol(object):
238239
type: Type

_linters/mypy.ini

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
[mypy]
22
python_version = 3.6
33

4+
[mypy-undo.udb_launcher]
5+
ignore_missing_imports = True
6+
47
[mypy-undodb.debugger_extensions]
58
ignore_missing_imports = True
69

malloc_free_check/malloc_free_check_extension.py

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,16 @@
1616
from undodb.debugger_extensions.debugger_io import redirect_to_launcher_output
1717

1818

19-
def leak_check() -> None:
19+
def leak_check() -> int:
2020
"""
2121
Implements breakpoints and stops on all calls to malloc() and free(), capturing the
2222
timestamp, size and returned pointer for malloc(), then confirms the address pointer is later
2323
seen in a free() call.
2424
2525
If a subsequent free() is not seen, then at the end of execution, output the timestamp and
2626
details of the memory which was never freed.
27+
28+
Returns the number of unmatched allocations found.
2729
"""
2830
# Set a breakpoint for the specified function.
2931
gdb.Breakpoint("malloc")
@@ -53,38 +55,39 @@ def leak_check() -> None:
5355

5456
# For now, capture the timestamp and size of memory requested.
5557
time = udb.time.get()
56-
size = gdb.parse_and_eval("$rdi")
58+
size = int(gdb.parse_and_eval("$rdi"))
5759

5860
gdb.execute("continue")
5961

6062
# Should stop at the finish breakpoint, so capture the pointer.
61-
addr = mfbp.return_value
63+
assert mfbp.return_value is not None, "Expected to see a return value."
64+
addr = int(mfbp.return_value)
6265

6366
if addr:
6467
# Store details in the dictionary.
65-
allocations[format(addr)] = time, size
68+
allocations[hex(addr)] = time, size
6669
else:
6770
print(f"-- INFO: Malloc called for {size} byte(s) but null returned.")
6871

6972
print(f"{time}: malloc() called: {size} byte(s) allocated at {addr}.")
7073

7174
elif re.search("free", mypc):
7275
# In free(), get the pointer address.
73-
addr = gdb.parse_and_eval("$rdi")
76+
addr = int(gdb.parse_and_eval("$rdi"))
7477

7578
time = udb.time.get()
7679

7780
# Delete entry from the dictionary as this memory was released.
7881
if addr > 0:
79-
if allocations[hex(int(format(addr)))]:
80-
del allocations[hex(int(format(addr)))]
82+
if allocations[hex(addr)]:
83+
del allocations[hex(addr)]
8184
else:
8285
print("--- INFO: Free called with unknown address")
8386
else:
8487
print("--- INFO: Free called with null address")
8588

8689
# with redirect_to_launcher_output():
87-
print(f"{time}: free() called for {int(addr):#x}")
90+
print(f"{time}: free() called for {addr:#x}")
8891

8992
# If Allocations has any entries remaining, they were not released.
9093
with redirect_to_launcher_output():
@@ -96,11 +99,10 @@ def leak_check() -> None:
9699

97100
# Increase the amount of source from default (10) to 16 lines for more context.
98101
gdb.execute("set listsize 16")
99-
for addr in allocations:
100-
time, size = allocations[addr]
102+
for location, (time, size) in allocations.items():
101103
total += size
102104
print("===============================================================================")
103-
print(f"{time}: {size} bytes was allocated at {addr}, but never freed.")
105+
print(f"{time}: {size} bytes was allocated at {location}, but never freed.")
104106
print("===============================================================================")
105107
udb.time.goto(time)
106108
print("Backtrace:")
@@ -124,10 +126,10 @@ def leak_check() -> None:
124126
# UDB will automatically load the modules passed to UdbLauncher.add_extension and, if present,
125127
# automatically execute any function (with no arguments) called "run".
126128
def run() -> None:
127-
# Needed to allow GDB to fixup breakpoints properly after glibc has been loaded
129+
# Needed to allow GDB to fixup breakpoints properly after glibc has been loaded.
128130
gdb.Breakpoint("main")
129131

130132
unmatched = leak_check()
131133

132-
# Pass the number of time we hit the breakpoint back to the outer script.
134+
# Pass the number of unmatched allocations back to the outer script.
133135
udb.result_data["unmatched"] = unmatched

0 commit comments

Comments
 (0)