allocation_tracker.c revision aa3a0114b6f018d0dd296d5bdb113d2f881cbc51
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 253b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson#include "allocation_tracker.h" 2653f36a45bd5333db3b55f1d7fbcd7a3362027de0Zach Johnson#include "allocator.h" 273b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson#include "hash_functions.h" 283b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson#include "hash_map.h" 293b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson#include "osi.h" 3044802768c447ab480d4227b3a852a97d923b816dSharvil Nanavati#include "osi/include/log.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, 46aa3a0114b6f018d0dd296d5bdb113d2f881cbc51Zach Johnson key_equality_fn equality_fn, 4753f36a45bd5333db3b55f1d7fbcd7a3362027de0Zach Johnson const allocator_t *zeroed_allocator); 4853f36a45bd5333db3b55f1d7fbcd7a3362027de0Zach Johnson 493b72a14c2515c1169d5501ada5499cf232fc643bZach Johnsonstatic bool allocation_entry_freed_checker(hash_map_entry_t *entry, void *context); 5053f36a45bd5333db3b55f1d7fbcd7a3362027de0Zach Johnsonstatic void *untracked_calloc(size_t size); 5153f36a45bd5333db3b55f1d7fbcd7a3362027de0Zach Johnson 52c0e2f9927b8d60123b388c3d117e8f82c90d46e3Zach Johnsonstatic const size_t allocation_hash_map_size = 1024; 53f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnsonstatic const char *canary = "tinybird"; 5453f36a45bd5333db3b55f1d7fbcd7a3362027de0Zach Johnsonstatic const allocator_t untracked_calloc_allocator = { 5553f36a45bd5333db3b55f1d7fbcd7a3362027de0Zach Johnson untracked_calloc, 5653f36a45bd5333db3b55f1d7fbcd7a3362027de0Zach Johnson free 5753f36a45bd5333db3b55f1d7fbcd7a3362027de0Zach Johnson}; 583b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson 59f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnsonstatic size_t canary_size; 603b72a14c2515c1169d5501ada5499cf232fc643bZach Johnsonstatic hash_map_t *allocations; 613b72a14c2515c1169d5501ada5499cf232fc643bZach Johnsonstatic pthread_mutex_t lock; 623b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson 63c0745da4fb23eea23abac3c3cfd51cc7f1d38f6dSharvil Nanavativoid allocation_tracker_init(void) { 643b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson if (allocations) 653b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson return; 663b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson 67f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnson canary_size = strlen(canary); 68f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnson 693b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson pthread_mutex_init(&lock, NULL); 7053f36a45bd5333db3b55f1d7fbcd7a3362027de0Zach Johnson allocations = hash_map_new_internal( 71c0e2f9927b8d60123b388c3d117e8f82c90d46e3Zach Johnson allocation_hash_map_size, 72c0e2f9927b8d60123b388c3d117e8f82c90d46e3Zach Johnson hash_function_pointer, 7353f36a45bd5333db3b55f1d7fbcd7a3362027de0Zach Johnson NULL, 7453f36a45bd5333db3b55f1d7fbcd7a3362027de0Zach Johnson free, 75aa3a0114b6f018d0dd296d5bdb113d2f881cbc51Zach Johnson NULL, 7653f36a45bd5333db3b55f1d7fbcd7a3362027de0Zach Johnson &untracked_calloc_allocator); 773b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson} 783b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson 79ee2aa45def216a3c4d6a23481fa96f1b02a5de8cZach Johnson// Test function only. Do not call in the normal course of operations. 80c0745da4fb23eea23abac3c3cfd51cc7f1d38f6dSharvil Nanavativoid allocation_tracker_uninit(void) { 81ee2aa45def216a3c4d6a23481fa96f1b02a5de8cZach Johnson hash_map_free(allocations); 82ee2aa45def216a3c4d6a23481fa96f1b02a5de8cZach Johnson allocations = NULL; 83ee2aa45def216a3c4d6a23481fa96f1b02a5de8cZach Johnson} 84ee2aa45def216a3c4d6a23481fa96f1b02a5de8cZach Johnson 853b72a14c2515c1169d5501ada5499cf232fc643bZach Johnsonvoid allocation_tracker_reset(void) { 863b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson if (!allocations) 873b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson return; 883b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson 893b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson hash_map_clear(allocations); 903b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson} 913b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson 92c0745da4fb23eea23abac3c3cfd51cc7f1d38f6dSharvil Nanavatisize_t allocation_tracker_expect_no_allocations(void) { 933b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson if (!allocations) 943b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson return 0; 953b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson 963b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson pthread_mutex_lock(&lock); 973b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson 983b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson size_t unfreed_memory_size = 0; 993b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson hash_map_foreach(allocations, allocation_entry_freed_checker, &unfreed_memory_size); 1003b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson 1013b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson pthread_mutex_unlock(&lock); 1023b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson 1033b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson return unfreed_memory_size; 1043b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson} 1053b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson 106c0745da4fb23eea23abac3c3cfd51cc7f1d38f6dSharvil Nanavativoid *allocation_tracker_notify_alloc(uint8_t allocator_id, void *ptr, size_t requested_size) { 1073b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson if (!allocations || !ptr) 108f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnson return ptr; 109f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnson 110f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnson char *return_ptr = (char *)ptr; 111f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnson 112c0745da4fb23eea23abac3c3cfd51cc7f1d38f6dSharvil Nanavati return_ptr += canary_size; 1133b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson 1143b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson pthread_mutex_lock(&lock); 1153b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson 116f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnson allocation_t *allocation = (allocation_t *)hash_map_get(allocations, return_ptr); 1173b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson if (allocation) { 1183b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson assert(allocation->freed); // Must have been freed before 1193b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson } else { 1203b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson allocation = (allocation_t *)calloc(1, sizeof(allocation_t)); 121f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnson hash_map_set(allocations, return_ptr, allocation); 1223b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson } 1233b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson 1244ed68b407ee836df7780a00d6b50b081b334c3abZach Johnson allocation->allocator_id = allocator_id; 1253b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson allocation->freed = false; 126f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnson allocation->size = requested_size; 127f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnson allocation->ptr = return_ptr; 1283b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson 1293b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson pthread_mutex_unlock(&lock); 130f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnson 131c0745da4fb23eea23abac3c3cfd51cc7f1d38f6dSharvil Nanavati // Add the canary on both sides 132c0745da4fb23eea23abac3c3cfd51cc7f1d38f6dSharvil Nanavati memcpy(return_ptr - canary_size, canary, canary_size); 133c0745da4fb23eea23abac3c3cfd51cc7f1d38f6dSharvil Nanavati memcpy(return_ptr + requested_size, canary, canary_size); 134f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnson 135f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnson return return_ptr; 1363b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson} 1373b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson 1384ed68b407ee836df7780a00d6b50b081b334c3abZach Johnsonvoid *allocation_tracker_notify_free(uint8_t allocator_id, void *ptr) { 1393b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson if (!allocations || !ptr) 140f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnson return ptr; 1413b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson 1423b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson pthread_mutex_lock(&lock); 1433b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson 1443b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson allocation_t *allocation = (allocation_t *)hash_map_get(allocations, ptr); 1454ed68b407ee836df7780a00d6b50b081b334c3abZach Johnson assert(allocation); // Must have been tracked before 1464ed68b407ee836df7780a00d6b50b081b334c3abZach Johnson assert(!allocation->freed); // Must not be a double free 1474ed68b407ee836df7780a00d6b50b081b334c3abZach Johnson assert(allocation->allocator_id == allocator_id); // Must be from the same allocator 1483b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson allocation->freed = true; 1493b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson 150c0745da4fb23eea23abac3c3cfd51cc7f1d38f6dSharvil Nanavati const char *beginning_canary = ((char *)ptr) - canary_size; 151c0745da4fb23eea23abac3c3cfd51cc7f1d38f6dSharvil Nanavati const char *end_canary = ((char *)ptr) + allocation->size; 152f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnson 153c0745da4fb23eea23abac3c3cfd51cc7f1d38f6dSharvil Nanavati for (size_t i = 0; i < canary_size; i++) { 154c0745da4fb23eea23abac3c3cfd51cc7f1d38f6dSharvil Nanavati assert(beginning_canary[i] == canary[i]); 155c0745da4fb23eea23abac3c3cfd51cc7f1d38f6dSharvil Nanavati assert(end_canary[i] == canary[i]); 156f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnson } 157f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnson 1583b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson pthread_mutex_unlock(&lock); 159f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnson 160c0745da4fb23eea23abac3c3cfd51cc7f1d38f6dSharvil Nanavati return ((char *)ptr) - canary_size; 161f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnson} 162f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnson 163f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnsonsize_t allocation_tracker_resize_for_canary(size_t size) { 164c0745da4fb23eea23abac3c3cfd51cc7f1d38f6dSharvil Nanavati return (!allocations) ? size : size + (2 * canary_size); 1653b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson} 1663b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson 1673b72a14c2515c1169d5501ada5499cf232fc643bZach Johnsonstatic bool allocation_entry_freed_checker(hash_map_entry_t *entry, void *context) { 1683b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson allocation_t *allocation = (allocation_t *)entry->data; 1693b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson if (!allocation->freed) { 1703b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson *((size_t *)context) += allocation->size; // Report back the unfreed byte count 17144802768c447ab480d4227b3a852a97d923b816dSharvil Nanavati LOG_ERROR("%s found unfreed allocation. address: 0x%x size: %d bytes", __func__, (uintptr_t)allocation->ptr, allocation->size); 1723b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson } 1733b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson 1743b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson return true; 1753b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson} 17653f36a45bd5333db3b55f1d7fbcd7a3362027de0Zach Johnson 17753f36a45bd5333db3b55f1d7fbcd7a3362027de0Zach Johnsonstatic void *untracked_calloc(size_t size) { 17853f36a45bd5333db3b55f1d7fbcd7a3362027de0Zach Johnson return calloc(size, 1); 17953f36a45bd5333db3b55f1d7fbcd7a3362027de0Zach Johnson} 180