-
Notifications
You must be signed in to change notification settings - Fork 6
Introduced a script to capture leaks from malloc / free #44
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
9a2be61
519bff3
c35af91
e73561c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| # Leak detector | ||
|
|
||
| Matches all calls to `malloc` and `free` and shows any unmatched `malloc` call | ||
| with a Bbcount to jump to. | ||
|
|
||
| ## Usage | ||
| ``` | ||
| ugo start | ||
chimicus marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| mleak | ||
| ``` | ||
|
|
||
| Before using the script it must be loaded in to the debugger: | ||
| ``` | ||
| source PATHTOADDONS/leak_detector/leak_detector.py | ||
| ``` | ||
chimicus marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,79 @@ | ||
| """ | ||
chimicus marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| Find memory leaks when malloc and free are used. | ||
| Starting from the current position it matches all calls to malloc | ||
| with calls to free with the same pointer and | ||
| keeps track of the calls that have no corresponding call to free. | ||
| It is recommended to go to the start of time and then use the command. | ||
| It prints a full list of unmatched calls at the end. | ||
| Usage: mleak | ||
chimicus marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| Contibutors: Emiliano Testa | ||
| Copyright (C) 2022 Undo Ltd | ||
| """ | ||
|
|
||
| import copy | ||
| import gdb | ||
chimicus marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| from undodb.debugger_extensions import ( | ||
| udb, | ||
chimicus marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| ) | ||
|
|
||
|
|
||
| ALLOC_FN = "malloc" | ||
| FREE_FN = "free" | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think you need these as globals if they are only used in one place. |
||
| all_allocs = [] | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It would be nicer if thee state were not a global. See below. |
||
|
|
||
|
|
||
| class MemAlloc: | ||
chimicus marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| def __init__(self, addr, size, bbcount): | ||
| self.addr = addr | ||
| self.size = size | ||
| self.bbcount = bbcount | ||
|
|
||
|
|
||
| def handle_alloc_fn(): | ||
| frame = gdb.selected_frame() | ||
| size = frame.read_register("rdi") | ||
| bbcount = udb.time.get().bbcount | ||
| gdb.execute("finish") | ||
| frame = gdb.selected_frame() | ||
| addr = frame.read_register("rax") | ||
| all_allocs.append(MemAlloc(addr, size, bbcount)) | ||
|
|
||
|
|
||
| def handle_free_fn(): | ||
| frame = gdb.selected_frame() | ||
| addr = frame.read_register("rdi") | ||
| for alloc in copy.copy(all_allocs): | ||
| if alloc.addr == addr: | ||
| all_allocs.remove(alloc) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use a set and then you can just do |
||
|
|
||
|
|
||
| def handle_bp_event(event): | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can achieve the same by defining a And similar for Returning Also use
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I thought about using this approach but the documentation states: and, because I need to get to the end of malloc() I decided not to use this technique and I went for the stop handlers instead. |
||
| if hasattr(event, "breakpoints"): | ||
| for bp in event.breakpoints: | ||
| if bp.location == ALLOC_FN: | ||
| handle_alloc_fn() | ||
| elif bp.location == FREE_FN: | ||
| handle_free_fn() | ||
|
|
||
|
|
||
| class LeakDetect(gdb.Command): | ||
chimicus marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| def __init__(self): | ||
| super().__init__("mleaks", gdb.COMMAND_USER) | ||
|
|
||
| @staticmethod | ||
| def invoke(arg, from_tty): | ||
| gdb.Breakpoint(ALLOC_FN) | ||
| gdb.Breakpoint(FREE_FN) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You should remove the breakpoints you create after you are done. If you follow my suggestions from above you will have: |
||
| gdb.events.stop.connect(handle_bp_event) | ||
| end_of_time = udb.get_event_log_extent().max_bbcount | ||
| gdb.execute("continue") | ||
chimicus marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| while udb.time.get().bbcount < end_of_time: | ||
chimicus marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| gdb.execute("continue") | ||
| print("Calls to allocator fn that don't have a corresponding free") | ||
| for alloc in all_allocs: | ||
| print(f"{hex(alloc.addr)} - {hex(alloc.size)} - {alloc.bbcount}") | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If you use a set then the results will be in an arbitrary order. You can do this:
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There are a few possible improvements here:
Maybe something like this: The various bits after the
|
||
|
|
||
|
|
||
| LeakDetect() | ||
Uh oh!
There was an error while loading. Please reload this page.