diff options
author | Arve Hjønnevåg <arve@android.com> | 2012-10-16 18:29:54 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-10-22 16:23:19 -0400 |
commit | 675d66b0ed5fd170d6a44cf8dbb3fa56a5347bdb (patch) | |
tree | 379272035fc1fbfaa86d78f22e3cfb05c12a833f | |
parent | 922b67c1ac53014d80649a961a2fde700cd065d8 (diff) |
Staging: android: binder: Fix memory leak on thread/process exit
If a thread or process exited while a reply, one-way transaction or
death notification was pending, the struct holding the pending work
was leaked.
Signed-off-by: Arve Hjønnevåg <arve@android.com>
Cc: stable <stable@vger.kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | drivers/staging/android/binder.c | 28 |
1 files changed, 27 insertions, 1 deletions
diff --git a/drivers/staging/android/binder.c b/drivers/staging/android/binder.c index 7b0ba92e7e46..db6c4c5c2551 100644 --- a/drivers/staging/android/binder.c +++ b/drivers/staging/android/binder.c | |||
@@ -2419,14 +2419,38 @@ static void binder_release_work(struct list_head *list) | |||
2419 | struct binder_transaction *t; | 2419 | struct binder_transaction *t; |
2420 | 2420 | ||
2421 | t = container_of(w, struct binder_transaction, work); | 2421 | t = container_of(w, struct binder_transaction, work); |
2422 | if (t->buffer->target_node && !(t->flags & TF_ONE_WAY)) | 2422 | if (t->buffer->target_node && |
2423 | !(t->flags & TF_ONE_WAY)) { | ||
2423 | binder_send_failed_reply(t, BR_DEAD_REPLY); | 2424 | binder_send_failed_reply(t, BR_DEAD_REPLY); |
2425 | } else { | ||
2426 | binder_debug(BINDER_DEBUG_DEAD_TRANSACTION, | ||
2427 | "binder: undelivered transaction %d\n", | ||
2428 | t->debug_id); | ||
2429 | t->buffer->transaction = NULL; | ||
2430 | kfree(t); | ||
2431 | binder_stats_deleted(BINDER_STAT_TRANSACTION); | ||
2432 | } | ||
2424 | } break; | 2433 | } break; |
2425 | case BINDER_WORK_TRANSACTION_COMPLETE: { | 2434 | case BINDER_WORK_TRANSACTION_COMPLETE: { |
2435 | binder_debug(BINDER_DEBUG_DEAD_TRANSACTION, | ||
2436 | "binder: undelivered TRANSACTION_COMPLETE\n"); | ||
2426 | kfree(w); | 2437 | kfree(w); |
2427 | binder_stats_deleted(BINDER_STAT_TRANSACTION_COMPLETE); | 2438 | binder_stats_deleted(BINDER_STAT_TRANSACTION_COMPLETE); |
2428 | } break; | 2439 | } break; |
2440 | case BINDER_WORK_DEAD_BINDER_AND_CLEAR: | ||
2441 | case BINDER_WORK_CLEAR_DEATH_NOTIFICATION: { | ||
2442 | struct binder_ref_death *death; | ||
2443 | |||
2444 | death = container_of(w, struct binder_ref_death, work); | ||
2445 | binder_debug(BINDER_DEBUG_DEAD_TRANSACTION, | ||
2446 | "binder: undelivered death notification, %p\n", | ||
2447 | death->cookie); | ||
2448 | kfree(death); | ||
2449 | binder_stats_deleted(BINDER_STAT_DEATH); | ||
2450 | } break; | ||
2429 | default: | 2451 | default: |
2452 | pr_err("binder: unexpected work type, %d, not freed\n", | ||
2453 | w->type); | ||
2430 | break; | 2454 | break; |
2431 | } | 2455 | } |
2432 | } | 2456 | } |
@@ -2899,6 +2923,7 @@ static void binder_deferred_release(struct binder_proc *proc) | |||
2899 | nodes++; | 2923 | nodes++; |
2900 | rb_erase(&node->rb_node, &proc->nodes); | 2924 | rb_erase(&node->rb_node, &proc->nodes); |
2901 | list_del_init(&node->work.entry); | 2925 | list_del_init(&node->work.entry); |
2926 | binder_release_work(&node->async_todo); | ||
2902 | if (hlist_empty(&node->refs)) { | 2927 | if (hlist_empty(&node->refs)) { |
2903 | kfree(node); | 2928 | kfree(node); |
2904 | binder_stats_deleted(BINDER_STAT_NODE); | 2929 | binder_stats_deleted(BINDER_STAT_NODE); |
@@ -2937,6 +2962,7 @@ static void binder_deferred_release(struct binder_proc *proc) | |||
2937 | binder_delete_ref(ref); | 2962 | binder_delete_ref(ref); |
2938 | } | 2963 | } |
2939 | binder_release_work(&proc->todo); | 2964 | binder_release_work(&proc->todo); |
2965 | binder_release_work(&proc->delivered_death); | ||
2940 | buffers = 0; | 2966 | buffers = 0; |
2941 | 2967 | ||
2942 | while ((n = rb_first(&proc->allocated_buffers))) { | 2968 | while ((n = rb_first(&proc->allocated_buffers))) { |