Skip to content
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

Add a method to trace call paths (for create/ref/deref) #8

Open
wants to merge 5 commits into
base: master
Choose a base branch
from

Conversation

Lekensteyn
Copy link
Contributor

(based on PR #7, branch https://github.com/Lekensteyn/gobject-list/tree/fix-libunwind)

Useful to debug reference count leaks where a lot objects are still
held just because a single object was not released elsewhere...

Totally not optimized and slows down a lot, but it gets the job done.

I used this to track down a very annoying reference count leak in UPower
which slows made it harder to analyze real issues.

Colored example at https://lekensteyn.nl/gobject-list-upower.html

Uncolored example for a very simple program which calls just g_cancellable_new() and fails to unref it:

$ GOBJECT_LIST_DISPLAY=all LD_PRELOAD=./libgobject-list.so ./a.out
 ++ Created object 0x212b610, GCancellable
#0  g_object_new + [0x00000161]
#1  main + [0x00000014]
#2  __libc_start_main + [0x000000f0]
#3  _start + [0x00000029]
Error getting frame: unspecified (general) error (1)
Leak!

Still Alive:
 - 0x212b610, GCancellable: 1 refs
1 objects

References:
#1
# GCancellable (+1/-0 = 1)
| # _start (+1/-0 = 1)
| | # __libc_start_main (+1/-0 = 1)
| | | # main (+1/-0 = 1)
| | | | # g_object_new (+1/-0 = 1)

I opened this PR in the hope it is useful to others.

@Lekensteyn Lekensteyn changed the title Trace callstack Add a method to trace call paths (for create/ref/deref) Nov 20, 2014
@danni
Copy link
Owner

danni commented Aug 8, 2015

I don't really know what all the colours etc mean. This probably needs some doco.

In general if it's slowing things down too much then might you not be better off with Valgrind? Part of the point of this tool was to not slow things down like Valgrind does.

The '#endif' is position on a weird place which results in a compile
warning (-Wimplicit-function). Fix this and print a diagnostic message
on startup if a backtrace is requested but support is missing.

Note: only affects builds where you manually disable HAVE_LIBUNWIND.
The length param of unw_get_proc_name already takes care of the
terminator, so remove the subtraction.

The manual describes that the error code is given by the negative, so
fix the condition checking against UNW_ENOMEM (verified by shrinking the
buffer).

Finally, the error message confused me (as a user) as it seems to
suggest something about the process name (rather than procedure).
Mention the more applicable "frame" instead (longer alternative:
"procedure name of frame").
Allow a different compiler to be specified and split the actual object
compile to a different target. Add a Phony target to avoid breaking when
a literal "all" or "clean" exist.
Useful to debug reference count leaks where a lot objects are still
held just because a single object was not released elsewhere...

Totally not optimized and slows down a lot, but it gets the job done.
@Lekensteyn
Copy link
Contributor Author

Valgrind is unusably slow and meanwhile a better tool has popped up, LeakSanitizer.

The slowness here referred to unwinding the full stack. LSan also needs to do that (and alternatively offers an even slower option, controllable via ASAN_OPTIONS=fast_unwind_on_malloc=0). LSan however is a compile-time instrumentation and cannot be used at runtime.

So I think that this patch does offer an advantage if LSan is not available/usable. When disabled (default), it does not cause a slowdown.

The color choices were arbitrary but can indeed be documented (in README?):

The call stack is printed as a tree where items have the format NAME (refs_count / unrefs_count = difference). An uninteresting tree item (= ref count matches unref count) is colored grey. Items with mismatching ref/unref counts are colored as follows:

  • The regular text is blue.
  • The refs_count is yellow.
  • The unrefs_count is red.
  • The difference is yellow if there are leaks, and red if there are more unrefs than refs.

GHashTable *children;
char *label;
unsigned count[COUNT_LAST];
} BtTrie;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BtTree ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A trie is a data structure also known as prefix tree. "BtTrie" = "prefix tree for backtraces storage".

@danni
Copy link
Owner

danni commented Aug 11, 2015

Please stick to the existing GNU/GNOME coding style for things like blocks. It makes the code easier to read. Also be very strict and explicit about how memory and references are passed around because the worst thing is when the memory checking tool leaks memory.

@Lekensteyn
Copy link
Contributor Author

Thank you for your feedback, I'll address your comments and return later.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants