allocation_tracker.cc revision c0745da4fb23eea23abac3c3cfd51cc7f1d38f6d
13b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson/******************************************************************************
23b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson *
33b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson *  Copyright (C) 2014 Google, Inc.
43b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson *
53b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson *  Licensed under the Apache License, Version 2.0 (the "License");
63b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson *  you may not use this file except in compliance with the License.
73b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson *  You may obtain a copy of the License at:
83b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson *
93b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson *  http://www.apache.org/licenses/LICENSE-2.0
103b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson *
113b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson *  Unless required by applicable law or agreed to in writing, software
123b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson *  distributed under the License is distributed on an "AS IS" BASIS,
133b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
143b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson *  See the License for the specific language governing permissions and
153b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson *  limitations under the License.
163b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson *
173b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson ******************************************************************************/
183b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson
19c0745da4fb23eea23abac3c3cfd51cc7f1d38f6dSharvil Nanavati#define LOG_TAG "bt_allocation_tracker"
20c0745da4fb23eea23abac3c3cfd51cc7f1d38f6dSharvil Nanavati
213b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson#include <assert.h>
223b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson#include <pthread.h>
234ed68b407ee836df7780a00d6b50b081b334c3abZach Johnson#include <stdint.h>
243b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson#include <utils/Log.h>
253b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson
263b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson#include "allocation_tracker.h"
2753f36a45bd5333db3b55f1d7fbcd7a3362027de0Zach Johnson#include "allocator.h"
283b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson#include "hash_functions.h"
293b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson#include "hash_map.h"
303b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson#include "osi.h"
313b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson
323b72a14c2515c1169d5501ada5499cf232fc643bZach Johnsontypedef struct {
334ed68b407ee836df7780a00d6b50b081b334c3abZach Johnson  uint8_t allocator_id;
343b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson  void *ptr;
353b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson  size_t size;
363b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson  bool freed;
373b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson} allocation_t;
383b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson
3953f36a45bd5333db3b55f1d7fbcd7a3362027de0Zach Johnson// Hidden constructor for hash map for our use only. Everything else should use the
4053f36a45bd5333db3b55f1d7fbcd7a3362027de0Zach Johnson// normal interface.
4153f36a45bd5333db3b55f1d7fbcd7a3362027de0Zach Johnsonhash_map_t *hash_map_new_internal(
4253f36a45bd5333db3b55f1d7fbcd7a3362027de0Zach Johnson    size_t size,
4353f36a45bd5333db3b55f1d7fbcd7a3362027de0Zach Johnson    hash_index_fn hash_fn,
4453f36a45bd5333db3b55f1d7fbcd7a3362027de0Zach Johnson    key_free_fn key_fn,
4553f36a45bd5333db3b55f1d7fbcd7a3362027de0Zach Johnson    data_free_fn,
4653f36a45bd5333db3b55f1d7fbcd7a3362027de0Zach Johnson    const allocator_t *zeroed_allocator);
4753f36a45bd5333db3b55f1d7fbcd7a3362027de0Zach Johnson
483b72a14c2515c1169d5501ada5499cf232fc643bZach Johnsonstatic bool allocation_entry_freed_checker(hash_map_entry_t *entry, void *context);
4953f36a45bd5333db3b55f1d7fbcd7a3362027de0Zach Johnsonstatic void *untracked_calloc(size_t size);
5053f36a45bd5333db3b55f1d7fbcd7a3362027de0Zach Johnson
51c0e2f9927b8d60123b388c3d117e8f82c90d46e3Zach Johnsonstatic const size_t allocation_hash_map_size = 1024;
52f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnsonstatic const char *canary = "tinybird";
5353f36a45bd5333db3b55f1d7fbcd7a3362027de0Zach Johnsonstatic const allocator_t untracked_calloc_allocator = {
5453f36a45bd5333db3b55f1d7fbcd7a3362027de0Zach Johnson  untracked_calloc,
5553f36a45bd5333db3b55f1d7fbcd7a3362027de0Zach Johnson  free
5653f36a45bd5333db3b55f1d7fbcd7a3362027de0Zach Johnson};
573b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson
58f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnsonstatic size_t canary_size;
593b72a14c2515c1169d5501ada5499cf232fc643bZach Johnsonstatic hash_map_t *allocations;
603b72a14c2515c1169d5501ada5499cf232fc643bZach Johnsonstatic pthread_mutex_t lock;
613b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson
62c0745da4fb23eea23abac3c3cfd51cc7f1d38f6dSharvil Nanavativoid allocation_tracker_init(void) {
633b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson  if (allocations)
643b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson    return;
653b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson
66f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnson  canary_size = strlen(canary);
67f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnson
683b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson  pthread_mutex_init(&lock, NULL);
6953f36a45bd5333db3b55f1d7fbcd7a3362027de0Zach Johnson  allocations = hash_map_new_internal(
70c0e2f9927b8d60123b388c3d117e8f82c90d46e3Zach Johnson    allocation_hash_map_size,
71c0e2f9927b8d60123b388c3d117e8f82c90d46e3Zach Johnson    hash_function_pointer,
7253f36a45bd5333db3b55f1d7fbcd7a3362027de0Zach Johnson    NULL,
7353f36a45bd5333db3b55f1d7fbcd7a3362027de0Zach Johnson    free,
7453f36a45bd5333db3b55f1d7fbcd7a3362027de0Zach Johnson    &untracked_calloc_allocator);
753b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson}
763b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson
77ee2aa45def216a3c4d6a23481fa96f1b02a5de8cZach Johnson// Test function only. Do not call in the normal course of operations.
78c0745da4fb23eea23abac3c3cfd51cc7f1d38f6dSharvil Nanavativoid allocation_tracker_uninit(void) {
79ee2aa45def216a3c4d6a23481fa96f1b02a5de8cZach Johnson  hash_map_free(allocations);
80ee2aa45def216a3c4d6a23481fa96f1b02a5de8cZach Johnson  allocations = NULL;
81ee2aa45def216a3c4d6a23481fa96f1b02a5de8cZach Johnson}
82ee2aa45def216a3c4d6a23481fa96f1b02a5de8cZach Johnson
833b72a14c2515c1169d5501ada5499cf232fc643bZach Johnsonvoid allocation_tracker_reset(void) {
843b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson  if (!allocations)
853b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson    return;
863b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson
873b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson  hash_map_clear(allocations);
883b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson}
893b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson
90c0745da4fb23eea23abac3c3cfd51cc7f1d38f6dSharvil Nanavatisize_t allocation_tracker_expect_no_allocations(void) {
913b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson  if (!allocations)
923b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson    return 0;
933b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson
943b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson  pthread_mutex_lock(&lock);
953b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson
963b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson  size_t unfreed_memory_size = 0;
973b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson  hash_map_foreach(allocations, allocation_entry_freed_checker, &unfreed_memory_size);
983b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson
993b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson  pthread_mutex_unlock(&lock);
1003b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson
1013b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson  return unfreed_memory_size;
1023b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson}
1033b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson
104c0745da4fb23eea23abac3c3cfd51cc7f1d38f6dSharvil Nanavativoid *allocation_tracker_notify_alloc(uint8_t allocator_id, void *ptr, size_t requested_size) {
1053b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson  if (!allocations || !ptr)
106f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnson    return ptr;
107f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnson
108f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnson  char *return_ptr = (char *)ptr;
109f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnson
110c0745da4fb23eea23abac3c3cfd51cc7f1d38f6dSharvil Nanavati  return_ptr += canary_size;
1113b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson
1123b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson  pthread_mutex_lock(&lock);
1133b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson
114f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnson  allocation_t *allocation = (allocation_t *)hash_map_get(allocations, return_ptr);
1153b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson  if (allocation) {
1163b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson    assert(allocation->freed); // Must have been freed before
1173b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson  } else {
1183b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson    allocation = (allocation_t *)calloc(1, sizeof(allocation_t));
119f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnson    hash_map_set(allocations, return_ptr, allocation);
1203b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson  }
1213b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson
1224ed68b407ee836df7780a00d6b50b081b334c3abZach Johnson  allocation->allocator_id = allocator_id;
1233b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson  allocation->freed = false;
124f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnson  allocation->size = requested_size;
125f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnson  allocation->ptr = return_ptr;
1263b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson
1273b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson  pthread_mutex_unlock(&lock);
128f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnson
129c0745da4fb23eea23abac3c3cfd51cc7f1d38f6dSharvil Nanavati  // Add the canary on both sides
130c0745da4fb23eea23abac3c3cfd51cc7f1d38f6dSharvil Nanavati  memcpy(return_ptr - canary_size, canary, canary_size);
131c0745da4fb23eea23abac3c3cfd51cc7f1d38f6dSharvil Nanavati  memcpy(return_ptr + requested_size, canary, canary_size);
132f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnson
133f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnson  return return_ptr;
1343b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson}
1353b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson
1364ed68b407ee836df7780a00d6b50b081b334c3abZach Johnsonvoid *allocation_tracker_notify_free(uint8_t allocator_id, void *ptr) {
1373b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson  if (!allocations || !ptr)
138f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnson    return ptr;
1393b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson
1403b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson  pthread_mutex_lock(&lock);
1413b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson
1423b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson  allocation_t *allocation = (allocation_t *)hash_map_get(allocations, ptr);
1434ed68b407ee836df7780a00d6b50b081b334c3abZach Johnson  assert(allocation);                               // Must have been tracked before
1444ed68b407ee836df7780a00d6b50b081b334c3abZach Johnson  assert(!allocation->freed);                       // Must not be a double free
1454ed68b407ee836df7780a00d6b50b081b334c3abZach Johnson  assert(allocation->allocator_id == allocator_id); // Must be from the same allocator
1463b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson  allocation->freed = true;
1473b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson
148c0745da4fb23eea23abac3c3cfd51cc7f1d38f6dSharvil Nanavati  const char *beginning_canary = ((char *)ptr) - canary_size;
149c0745da4fb23eea23abac3c3cfd51cc7f1d38f6dSharvil Nanavati  const char *end_canary = ((char *)ptr) + allocation->size;
150f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnson
151c0745da4fb23eea23abac3c3cfd51cc7f1d38f6dSharvil Nanavati  for (size_t i = 0; i < canary_size; i++) {
152c0745da4fb23eea23abac3c3cfd51cc7f1d38f6dSharvil Nanavati    assert(beginning_canary[i] == canary[i]);
153c0745da4fb23eea23abac3c3cfd51cc7f1d38f6dSharvil Nanavati    assert(end_canary[i] == canary[i]);
154f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnson  }
155f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnson
1563b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson  pthread_mutex_unlock(&lock);
157f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnson
158c0745da4fb23eea23abac3c3cfd51cc7f1d38f6dSharvil Nanavati  return ((char *)ptr) - canary_size;
159f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnson}
160f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnson
161f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnsonsize_t allocation_tracker_resize_for_canary(size_t size) {
162c0745da4fb23eea23abac3c3cfd51cc7f1d38f6dSharvil Nanavati  return (!allocations) ? size : size + (2 * canary_size);
1633b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson}
1643b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson
1653b72a14c2515c1169d5501ada5499cf232fc643bZach Johnsonstatic bool allocation_entry_freed_checker(hash_map_entry_t *entry, void *context) {
1663b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson  allocation_t *allocation = (allocation_t *)entry->data;
1673b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson  if (!allocation->freed) {
1683b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson    *((size_t *)context) += allocation->size; // Report back the unfreed byte count
1693b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson    ALOGE("%s found unfreed allocation. address: 0x%x size: %d bytes", __func__, (uintptr_t)allocation->ptr, allocation->size);
1703b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson  }
1713b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson
1723b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson  return true;
1733b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson}
17453f36a45bd5333db3b55f1d7fbcd7a3362027de0Zach Johnson
17553f36a45bd5333db3b55f1d7fbcd7a3362027de0Zach Johnsonstatic void *untracked_calloc(size_t size) {
17653f36a45bd5333db3b55f1d7fbcd7a3362027de0Zach Johnson  return calloc(size, 1);
17753f36a45bd5333db3b55f1d7fbcd7a3362027de0Zach Johnson}
178