Skip to content

Instantly share code, notes, and snippets.

@oleavr
Last active August 6, 2016 19:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save oleavr/27c2e80a58f808df4d290d8a17117114 to your computer and use it in GitHub Desktop.
Save oleavr/27c2e80a58f808df4d290d8a17117114 to your computer and use it in GitHub Desktop.
GVariant leak tracker in 78 lines of code

GVariant leak tracker in 78 lines of code

To use it on a running process, first pip install frida to grab Frida's python bindings and CLI tools, then:

$ frida FooApp -l gvariant-leak-tracker.js

Then in the REPL you can call count() and list() to inspect the values currently alive:

[Local::ProcName::FooApp]-> count()
2
[Local::ProcName::FooApp]-> list()
0x7fc1185e96d0: {
  "refCount": 1,
  "constructor": "g_variant_new_from_children",
  "creator": [
    "0x106187873 FooApp!parse_value_from_blob gdbusmessage.c:1737",
    "0x106187a0b FooApp!parse_value_from_blob gdbusmessage.c:1802",
    "0x106186e10 FooApp!g_dbus_message_new_from_blob gdbusmessage.c:2144",
    "0x106193a34 FooApp!_g_dbus_worker_do_read_cb gdbusprivate.c:756",
    "0x106112f62 FooApp!async_ready_callback_wrapper ginputstream.c:530",
    "0x106141fd4 FooApp!g_task_return_now gtask.c:1124",
    "0x106142025 FooApp!complete_in_idle_cb gtask.c:1139",
    "0x10620e863 FooApp!g_idle_dispatch gmain.c:5485",
    "0x106212503 FooApp!g_main_dispatch gmain.c:3210",
    "0x106212350 FooApp!g_main_context_dispatch gmain.c:3828",
    "0x10621283e FooApp!g_main_context_iterate gmain.c:3898",
    "0x106212c42 FooApp!g_main_loop_run gmain.c:4089",
    "0x10619319e FooApp!gdbus_shared_thread_func gdbusprivate.c:251",
    "0x10623123d FooApp!g_thread_proxy gthread.c:764",
    "0x7fff8b1ec99d libsystem_pthread.dylib!_pthread_body",
    "0x7fff8b1ec91a libsystem_pthread.dylib!_pthread_body"
  ],
  "log": [
    {
      "event": "g_variant_ref",
      "caller": [
        "0x10623d3f3 FooApp!g_variant_builder_add_value gvariant.c:3450",
        "0x106187a44 FooApp!parse_value_from_blob gdbusmessage.c:1813",
        "0x106186e10 FooApp!g_dbus_message_new_from_blob gdbusmessage.c:2144",
        "0x106193a34 FooApp!_g_dbus_worker_do_read_cb gdbusprivate.c:756",
        "0x106112f62 FooApp!async_ready_callback_wrapper ginputstream.c:530",
        "0x106141fd4 FooApp!g_task_return_now gtask.c:1124",
        "0x106142025 FooApp!complete_in_idle_cb gtask.c:1139",
        "0x10620e863 FooApp!g_idle_dispatch gmain.c:5485",
        "0x106212503 FooApp!g_main_dispatch gmain.c:3210",
        "0x106212350 FooApp!g_main_context_dispatch gmain.c:3828",
        "0x10621283e FooApp!g_main_context_iterate gmain.c:3898",
        "0x106212c42 FooApp!g_main_loop_run gmain.c:4089",
        "0x10619319e FooApp!gdbus_shared_thread_func gdbusprivate.c:251",
        "0x10623123d FooApp!g_thread_proxy gthread.c:764",
        "0x7fff8b1ec99d libsystem_pthread.dylib!_pthread_body",
        "0x7fff8b1ec91a libsystem_pthread.dylib!_pthread_body"
      ]
    },
    {
      "event": "g_variant_unref",
      "caller": [
        "0x106186e10 FooApp!g_dbus_message_new_from_blob gdbusmessage.c:2144",
        "0x106193a34 FooApp!_g_dbus_worker_do_read_cb gdbusprivate.c:756",
        "0x106112f62 FooApp!async_ready_callback_wrapper ginputstream.c:530",
        "0x106141fd4 FooApp!g_task_return_now gtask.c:1124",
        "0x106142025 FooApp!complete_in_idle_cb gtask.c:1139",
        "0x10620e863 FooApp!g_idle_dispatch gmain.c:5485",
        "0x106212503 FooApp!g_main_dispatch gmain.c:3210",
        "0x106212350 FooApp!g_main_context_dispatch gmain.c:3828",
        "0x10621283e FooApp!g_main_context_iterate gmain.c:3898",
        "0x106212c42 FooApp!g_main_loop_run gmain.c:4089",
        "0x10619319e FooApp!gdbus_shared_thread_func gdbusprivate.c:251",
        "0x10623123d FooApp!g_thread_proxy gthread.c:764",
        "0x7fff8b1ec99d libsystem_pthread.dylib!_pthread_body",
        "0x7fff8b1ec91a libsystem_pthread.dylib!_pthread_body",
        "0x7fff8b1ea351 libsystem_pthread.dylib!thread_start"
      ]
    },
    {
      "event": "g_variant_ref",
      "caller": [
        "0x10623f6f1 FooApp!g_variant_valist_get gvariant.c:5128",
        "0x106239ef0 FooApp!g_variant_get_va gvariant.c:5358",
        "0x10623f4b6 FooApp!g_variant_get gvariant.c:5303",
        "0x10618f63b FooApp!process_get_all_reply gdbusproxy.c:1173",
        "0x10618feb8 FooApp!async_initable_init_second_finish gdbusproxy.c:1725",
        "0x10618e41b FooApp!init_second_async_cb gdbusproxy.c:1804",
        "0x106141fd4 FooApp!g_task_return_now gtask.c:1124",
        "0x106141146 FooApp!g_task_return gtask.c:1183",
        "0x106141407 FooApp!g_task_return_pointer gtask.c:1555",
        "0x10618fb6a FooApp!async_init_get_all_cb gdbusproxy.c:1445",
        "0x106141fd4 FooApp!g_task_return_now gtask.c:1124",
        "0x106141146 FooApp!g_task_return gtask.c:1183",
        "0x106141407 FooApp!g_task_return_pointer gtask.c:1555",
        "0x10618416c FooApp!g_dbus_connection_call_done gdbusconnection.c:5403",
        "0x106141fd4 FooApp!g_task_return_now gtask.c:1124",
        "0x106142025 FooApp!complete_in_idle_cb gtask.c:1139"
      ]
    },
    {
      "event": "g_variant_ref",
      "caller": [
        "0x106241b11 FooApp!g_variant_valist_get_nnp gvariant.c:4734",
        "0x1062415cd FooApp!g_variant_valist_get_leaf gvariant.c:4913",
        "0x10623f530 FooApp!g_variant_valist_get gvariant.c:5094",
        "0x10623f709 FooApp!g_variant_valist_get gvariant.c:5130",
        "0x106239ef0 FooApp!g_variant_get_va gvariant.c:5358",
        "0x10623f4b6 FooApp!g_variant_get gvariant.c:5303",
        "0x10618f63b FooApp!process_get_all_reply gdbusproxy.c:1173",
        "0x10618feb8 FooApp!async_initable_init_second_finish gdbusproxy.c:1725",
        "0x10618e41b FooApp!init_second_async_cb gdbusproxy.c:1804",
        "0x106141fd4 FooApp!g_task_return_now gtask.c:1124",
        "0x106141146 FooApp!g_task_return gtask.c:1183",
        "0x106141407 FooApp!g_task_return_pointer gtask.c:1555",
        "0x10618fb6a FooApp!async_init_get_all_cb gdbusproxy.c:1445",
        "0x106141fd4 FooApp!g_task_return_now gtask.c:1124",
        "0x106141146 FooApp!g_task_return gtask.c:1183",
        "0x106141407 FooApp!g_task_return_pointer gtask.c:1555"
      ]
    },
    {
      "event": "g_variant_unref",
      "caller": [
        "0x106239ef0 FooApp!g_variant_get_va gvariant.c:5358",
        "0x10623f4b6 FooApp!g_variant_get gvariant.c:5303",
        "0x10618f63b FooApp!process_get_all_reply gdbusproxy.c:1173",
        "0x10618feb8 FooApp!async_initable_init_second_finish gdbusproxy.c:1725",
        "0x10618e41b FooApp!init_second_async_cb gdbusproxy.c:1804",
        "0x106141fd4 FooApp!g_task_return_now gtask.c:1124",
        "0x106141146 FooApp!g_task_return gtask.c:1183",
        "0x106141407 FooApp!g_task_return_pointer gtask.c:1555",
        "0x10618fb6a FooApp!async_init_get_all_cb gdbusproxy.c:1445",
        "0x106141fd4 FooApp!g_task_return_now gtask.c:1124",
        "0x106141146 FooApp!g_task_return gtask.c:1183",
        "0x106141407 FooApp!g_task_return_pointer gtask.c:1555",
        "0x10618416c FooApp!g_dbus_connection_call_done gdbusconnection.c:5403",
        "0x106141fd4 FooApp!g_task_return_now gtask.c:1124",
        "0x106142025 FooApp!complete_in_idle_cb gtask.c:1139",
        "0x10620e863 FooApp!g_idle_dispatch gmain.c:5485"
      ]
    },
    {
      "event": "g_variant_unref",
      "caller": [
        "0x10618f67d FooApp!process_get_all_reply gdbusproxy.c:1182",
        "0x10618feb8 FooApp!async_initable_init_second_finish gdbusproxy.c:1725",
        "0x10618e41b FooApp!init_second_async_cb gdbusproxy.c:1804",
        "0x106141fd4 FooApp!g_task_return_now gtask.c:1124",
        "0x106141146 FooApp!g_task_return gtask.c:1183",
        "0x106141407 FooApp!g_task_return_pointer gtask.c:1555",
        "0x10618fb6a FooApp!async_init_get_all_cb gdbusproxy.c:1445",
        "0x106141fd4 FooApp!g_task_return_now gtask.c:1124",
        "0x106141146 FooApp!g_task_return gtask.c:1183",
        "0x106141407 FooApp!g_task_return_pointer gtask.c:1555",
        "0x10618416c FooApp!g_dbus_connection_call_done gdbusconnection.c:5403",
        "0x106141fd4 FooApp!g_task_return_now gtask.c:1124",
        "0x106142025 FooApp!complete_in_idle_cb gtask.c:1139",
        "0x10620e863 FooApp!g_idle_dispatch gmain.c:5485",
        "0x106212503 FooApp!g_main_dispatch gmain.c:3210",
        "0x106212350 FooApp!g_main_context_dispatch gmain.c:3828"
      ]
    }
  ]
}
0x7fc1185e9350: {
  "refCount": 1,
  "constructor": "g_variant_new_from_children",
  "creator": [
    "0x106187a74 FooApp!parse_value_from_blob gdbusmessage.c:1817",
    "0x106186e10 FooApp!g_dbus_message_new_from_blob gdbusmessage.c:2144",
    "0x106193a34 FooApp!_g_dbus_worker_do_read_cb gdbusprivate.c:756",
    "0x106112f62 FooApp!async_ready_callback_wrapper ginputstream.c:530",
    "0x106141fd4 FooApp!g_task_return_now gtask.c:1124",
    "0x106142025 FooApp!complete_in_idle_cb gtask.c:1139",
    "0x10620e863 FooApp!g_idle_dispatch gmain.c:5485",
    "0x106212503 FooApp!g_main_dispatch gmain.c:3210",
    "0x106212350 FooApp!g_main_context_dispatch gmain.c:3828",
    "0x10621283e FooApp!g_main_context_iterate gmain.c:3898",
    "0x106212c42 FooApp!g_main_loop_run gmain.c:4089",
    "0x10619319e FooApp!gdbus_shared_thread_func gdbusprivate.c:251",
    "0x10623123d FooApp!g_thread_proxy gthread.c:764",
    "0x7fff8b1ec99d libsystem_pthread.dylib!_pthread_body",
    "0x7fff8b1ec91a libsystem_pthread.dylib!_pthread_body",
    "0x7fff8b1ea351 libsystem_pthread.dylib!thread_start"
  ],
  "log": [
    {
      "event": "g_variant_ref",
      "caller": [
        "0x106184131 FooApp!g_dbus_connection_call_done gdbusconnection.c:5396",
        "0x106141fd4 FooApp!g_task_return_now gtask.c:1124",
        "0x106142025 FooApp!complete_in_idle_cb gtask.c:1139",
        "0x10620e863 FooApp!g_idle_dispatch gmain.c:5485",
        "0x106212503 FooApp!g_main_dispatch gmain.c:3210",
        "0x106212350 FooApp!g_main_context_dispatch gmain.c:3828",
        "0x10621283e FooApp!g_main_context_iterate gmain.c:3898",
        "0x106212c42 FooApp!g_main_loop_run gmain.c:4089",
        "0x10604c18f FooApp!frida_server_application_run server.c:866",
        "0x10604b959 FooApp!frida_server_main server.c:741",
        "0x10604c1c7 FooApp!main server.c:787",
        "0x10604aba4 FooApp!start"
      ]
    },
    {
      "event": "g_variant_unref",
      "caller": [
        "0x1061ccede FooApp!g_object_unref gobject.c:3187",
        "0x1061841af FooApp!g_dbus_connection_call_done gdbusconnection.c:5403",
        "0x106141fd4 FooApp!g_task_return_now gtask.c:1124",
        "0x106142025 FooApp!complete_in_idle_cb gtask.c:1139",
        "0x10620e863 FooApp!g_idle_dispatch gmain.c:5485",
        "0x106212503 FooApp!g_main_dispatch gmain.c:3210",
        "0x106212350 FooApp!g_main_context_dispatch gmain.c:3828",
        "0x10621283e FooApp!g_main_context_iterate gmain.c:3898",
        "0x106212c42 FooApp!g_main_loop_run gmain.c:4089",
        "0x10604c18f FooApp!frida_server_application_run server.c:866",
        "0x10604b959 FooApp!frida_server_main server.c:741",
        "0x10604c1c7 FooApp!main server.c:787",
        "0x10604aba4 FooApp!start"
      ]
    }
  ]
}
undefined
[Local::ProcName::FooApp]->
'use strict';
var variants = {};
function count() {
return Object.keys(variants).length;
}
function list() {
Object.keys(variants).forEach(function (handle) {
var details = variants[handle];
console.log(handle + ': ' + JSON.stringify(details, null, 2));
});
}
DebugSymbol.findFunctionsMatching('g_variant_new*').forEach(function (address) {
var name = DebugSymbol.fromAddress(address).name;
Interceptor.attach(address, {
onLeave: function (retval) {
var details = getDetails(retval);
details.constructor = name;
details.creator = backtrace(this.context);
}
});
});
Interceptor.attach(DebugSymbol.getFunctionByName('g_variant_ref'), {
onEnter: function (args) {
var self = args[0];
var details = getDetails(self);
details.refCount = readRefCount(self) + 1;
details.log.push({
event: 'g_variant_ref',
caller: backtrace(this.context)
});
}
});
Interceptor.attach(DebugSymbol.getFunctionByName('g_variant_unref'), {
onEnter: function (args) {
var self = args[0];
var details = getDetails(self);
details.refCount = readRefCount(self) - 1;
if (details.refCount === 0) {
delete variants[self];
} else {
details.log.push({
event: 'g_variant_unref',
caller: backtrace(this.context)
});
}
}
});
function getDetails(handle) {
var details = variants[handle];
if (details === undefined) {
details = {
refCount: readRefCount(handle),
constructor: 'g_variant_alloc',
creator: null,
log: []
};
variants[handle] = details;
}
return details;
}
function readRefCount(handle) {
return Memory.readInt(handle.add(0x24));
}
function backtrace(context) {
return Thread.backtrace(context).map(DebugSymbol.fromAddress).map(function (symbol) { return symbol.toString(); });
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment