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 19f8027005333c88a2f097cfd70d15c3d54c7764aeChris Manton#define LOG_TAG "bt_osi_allocation_tracker" 20c0745da4fb23eea23abac3c3cfd51cc7f1d38f6dSharvil Nanavati 2149a86709488e5cfd5e23759da18bf9613e15b04dMarie Janssen#include "osi/include/allocation_tracker.h" 2249a86709488e5cfd5e23759da18bf9613e15b04dMarie Janssen 233b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson#include <assert.h> 243b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson#include <pthread.h> 253e59b5b6f2ce1295e3e2711afcd2cdf0dd7e22b6Etan Cohen#include <stdlib.h> 263e59b5b6f2ce1295e3e2711afcd2cdf0dd7e22b6Etan Cohen#include <string.h> 273b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson 280f9b91e150e153229235c163861198e23600e636Sharvil Nanavati#include "osi/include/allocator.h" 290f9b91e150e153229235c163861198e23600e636Sharvil Nanavati#include "osi/include/hash_functions.h" 300f9b91e150e153229235c163861198e23600e636Sharvil Nanavati#include "osi/include/hash_map.h" 3144802768c447ab480d4227b3a852a97d923b816dSharvil Nanavati#include "osi/include/log.h" 3249a86709488e5cfd5e23759da18bf9613e15b04dMarie Janssen#include "osi/include/osi.h" 333b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson 343b72a14c2515c1169d5501ada5499cf232fc643bZach Johnsontypedef struct { 354ed68b407ee836df7780a00d6b50b081b334c3abZach Johnson uint8_t allocator_id; 363b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson void *ptr; 373b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson size_t size; 383b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson bool freed; 393b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson} allocation_t; 403b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson 4153f36a45bd5333db3b55f1d7fbcd7a3362027de0Zach Johnson// Hidden constructor for hash map for our use only. Everything else should use the 4253f36a45bd5333db3b55f1d7fbcd7a3362027de0Zach Johnson// normal interface. 4353f36a45bd5333db3b55f1d7fbcd7a3362027de0Zach Johnsonhash_map_t *hash_map_new_internal( 4453f36a45bd5333db3b55f1d7fbcd7a3362027de0Zach Johnson size_t size, 4553f36a45bd5333db3b55f1d7fbcd7a3362027de0Zach Johnson hash_index_fn hash_fn, 4653f36a45bd5333db3b55f1d7fbcd7a3362027de0Zach Johnson key_free_fn key_fn, 4753f36a45bd5333db3b55f1d7fbcd7a3362027de0Zach Johnson data_free_fn, 48aa3a0114b6f018d0dd296d5bdb113d2f881cbc51Zach Johnson key_equality_fn equality_fn, 4953f36a45bd5333db3b55f1d7fbcd7a3362027de0Zach Johnson const allocator_t *zeroed_allocator); 5053f36a45bd5333db3b55f1d7fbcd7a3362027de0Zach Johnson 513b72a14c2515c1169d5501ada5499cf232fc643bZach Johnsonstatic bool allocation_entry_freed_checker(hash_map_entry_t *entry, void *context); 5253f36a45bd5333db3b55f1d7fbcd7a3362027de0Zach Johnsonstatic void *untracked_calloc(size_t size); 5353f36a45bd5333db3b55f1d7fbcd7a3362027de0Zach Johnson 54c0e2f9927b8d60123b388c3d117e8f82c90d46e3Zach Johnsonstatic const size_t allocation_hash_map_size = 1024; 55f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnsonstatic const char *canary = "tinybird"; 5653f36a45bd5333db3b55f1d7fbcd7a3362027de0Zach Johnsonstatic const allocator_t untracked_calloc_allocator = { 5753f36a45bd5333db3b55f1d7fbcd7a3362027de0Zach Johnson untracked_calloc, 5853f36a45bd5333db3b55f1d7fbcd7a3362027de0Zach Johnson free 5953f36a45bd5333db3b55f1d7fbcd7a3362027de0Zach Johnson}; 603b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson 61f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnsonstatic size_t canary_size; 623b72a14c2515c1169d5501ada5499cf232fc643bZach Johnsonstatic hash_map_t *allocations; 633b72a14c2515c1169d5501ada5499cf232fc643bZach Johnsonstatic pthread_mutex_t lock; 643b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson 65c0745da4fb23eea23abac3c3cfd51cc7f1d38f6dSharvil Nanavativoid allocation_tracker_init(void) { 663b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson if (allocations) 673b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson return; 683b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson 69f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnson canary_size = strlen(canary); 70f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnson 713b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson pthread_mutex_init(&lock, NULL); 725febd64b95260672d41964337377fb312ea2c07bPavlin Radoslavov 735febd64b95260672d41964337377fb312ea2c07bPavlin Radoslavov pthread_mutex_lock(&lock); 7453f36a45bd5333db3b55f1d7fbcd7a3362027de0Zach Johnson allocations = hash_map_new_internal( 75c0e2f9927b8d60123b388c3d117e8f82c90d46e3Zach Johnson allocation_hash_map_size, 76c0e2f9927b8d60123b388c3d117e8f82c90d46e3Zach Johnson hash_function_pointer, 7753f36a45bd5333db3b55f1d7fbcd7a3362027de0Zach Johnson NULL, 7853f36a45bd5333db3b55f1d7fbcd7a3362027de0Zach Johnson free, 79aa3a0114b6f018d0dd296d5bdb113d2f881cbc51Zach Johnson NULL, 8053f36a45bd5333db3b55f1d7fbcd7a3362027de0Zach Johnson &untracked_calloc_allocator); 815febd64b95260672d41964337377fb312ea2c07bPavlin Radoslavov pthread_mutex_unlock(&lock); 823b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson} 833b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson 84ee2aa45def216a3c4d6a23481fa96f1b02a5de8cZach Johnson// Test function only. Do not call in the normal course of operations. 85c0745da4fb23eea23abac3c3cfd51cc7f1d38f6dSharvil Nanavativoid allocation_tracker_uninit(void) { 865febd64b95260672d41964337377fb312ea2c07bPavlin Radoslavov if (!allocations) 875febd64b95260672d41964337377fb312ea2c07bPavlin Radoslavov return; 885febd64b95260672d41964337377fb312ea2c07bPavlin Radoslavov 895febd64b95260672d41964337377fb312ea2c07bPavlin Radoslavov pthread_mutex_lock(&lock); 90ee2aa45def216a3c4d6a23481fa96f1b02a5de8cZach Johnson hash_map_free(allocations); 91ee2aa45def216a3c4d6a23481fa96f1b02a5de8cZach Johnson allocations = NULL; 925febd64b95260672d41964337377fb312ea2c07bPavlin Radoslavov pthread_mutex_unlock(&lock); 93ee2aa45def216a3c4d6a23481fa96f1b02a5de8cZach Johnson} 94ee2aa45def216a3c4d6a23481fa96f1b02a5de8cZach Johnson 953b72a14c2515c1169d5501ada5499cf232fc643bZach Johnsonvoid allocation_tracker_reset(void) { 963b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson if (!allocations) 973b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson return; 983b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson 995febd64b95260672d41964337377fb312ea2c07bPavlin Radoslavov pthread_mutex_lock(&lock); 1003b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson hash_map_clear(allocations); 1015febd64b95260672d41964337377fb312ea2c07bPavlin Radoslavov pthread_mutex_unlock(&lock); 1023b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson} 1033b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson 104c0745da4fb23eea23abac3c3cfd51cc7f1d38f6dSharvil Nanavatisize_t allocation_tracker_expect_no_allocations(void) { 1053b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson if (!allocations) 1063b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson return 0; 1073b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson 1083b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson pthread_mutex_lock(&lock); 1093b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson 1103b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson size_t unfreed_memory_size = 0; 1113b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson hash_map_foreach(allocations, allocation_entry_freed_checker, &unfreed_memory_size); 1123b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson 1133b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson pthread_mutex_unlock(&lock); 1143b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson 1153b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson return unfreed_memory_size; 1163b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson} 1173b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson 118c0745da4fb23eea23abac3c3cfd51cc7f1d38f6dSharvil Nanavativoid *allocation_tracker_notify_alloc(uint8_t allocator_id, void *ptr, size_t requested_size) { 1193b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson if (!allocations || !ptr) 120f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnson return ptr; 121f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnson 122f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnson char *return_ptr = (char *)ptr; 123f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnson 124c0745da4fb23eea23abac3c3cfd51cc7f1d38f6dSharvil Nanavati return_ptr += canary_size; 1253b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson 1263b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson pthread_mutex_lock(&lock); 1273b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson 128f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnson allocation_t *allocation = (allocation_t *)hash_map_get(allocations, return_ptr); 1293b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson if (allocation) { 1303b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson assert(allocation->freed); // Must have been freed before 1313b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson } else { 1323b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson allocation = (allocation_t *)calloc(1, sizeof(allocation_t)); 133f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnson hash_map_set(allocations, return_ptr, allocation); 1343b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson } 1353b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson 1364ed68b407ee836df7780a00d6b50b081b334c3abZach Johnson allocation->allocator_id = allocator_id; 1373b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson allocation->freed = false; 138f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnson allocation->size = requested_size; 139f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnson allocation->ptr = return_ptr; 1403b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson 1413b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson pthread_mutex_unlock(&lock); 142f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnson 143c0745da4fb23eea23abac3c3cfd51cc7f1d38f6dSharvil Nanavati // Add the canary on both sides 144c0745da4fb23eea23abac3c3cfd51cc7f1d38f6dSharvil Nanavati memcpy(return_ptr - canary_size, canary, canary_size); 145c0745da4fb23eea23abac3c3cfd51cc7f1d38f6dSharvil Nanavati memcpy(return_ptr + requested_size, canary, canary_size); 146f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnson 147f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnson return return_ptr; 1483b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson} 1493b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson 150918e5a6832fa22bfe1e53e501af8f53ffc55b454Chih-Hung Hsiehvoid *allocation_tracker_notify_free(UNUSED_ATTR uint8_t allocator_id, void *ptr) { 1513b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson if (!allocations || !ptr) 152f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnson return ptr; 1533b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson 1543b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson pthread_mutex_lock(&lock); 1553b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson 1563b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson allocation_t *allocation = (allocation_t *)hash_map_get(allocations, ptr); 1574ed68b407ee836df7780a00d6b50b081b334c3abZach Johnson assert(allocation); // Must have been tracked before 1584ed68b407ee836df7780a00d6b50b081b334c3abZach Johnson assert(!allocation->freed); // Must not be a double free 1594ed68b407ee836df7780a00d6b50b081b334c3abZach Johnson assert(allocation->allocator_id == allocator_id); // Must be from the same allocator 1603b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson allocation->freed = true; 1613b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson 162918e5a6832fa22bfe1e53e501af8f53ffc55b454Chih-Hung Hsieh UNUSED_ATTR const char *beginning_canary = ((char *)ptr) - canary_size; 163918e5a6832fa22bfe1e53e501af8f53ffc55b454Chih-Hung Hsieh UNUSED_ATTR const char *end_canary = ((char *)ptr) + allocation->size; 164f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnson 165c0745da4fb23eea23abac3c3cfd51cc7f1d38f6dSharvil Nanavati for (size_t i = 0; i < canary_size; i++) { 166c0745da4fb23eea23abac3c3cfd51cc7f1d38f6dSharvil Nanavati assert(beginning_canary[i] == canary[i]); 167c0745da4fb23eea23abac3c3cfd51cc7f1d38f6dSharvil Nanavati assert(end_canary[i] == canary[i]); 168f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnson } 169f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnson 1702bea757aba0d0d84865d7d0d675d8bcf31f90b22Srinu Jella // Free the hash map entry to avoid unlimited memory usage growth. 1712bea757aba0d0d84865d7d0d675d8bcf31f90b22Srinu Jella // Double-free of memory is detected with "assert(allocation)" above 1722bea757aba0d0d84865d7d0d675d8bcf31f90b22Srinu Jella // as the allocation entry will not be present. 1732bea757aba0d0d84865d7d0d675d8bcf31f90b22Srinu Jella hash_map_erase(allocations, ptr); 1742bea757aba0d0d84865d7d0d675d8bcf31f90b22Srinu Jella 1753b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson pthread_mutex_unlock(&lock); 176f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnson 177c0745da4fb23eea23abac3c3cfd51cc7f1d38f6dSharvil Nanavati return ((char *)ptr) - canary_size; 178f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnson} 179f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnson 180f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnsonsize_t allocation_tracker_resize_for_canary(size_t size) { 181c0745da4fb23eea23abac3c3cfd51cc7f1d38f6dSharvil Nanavati return (!allocations) ? size : size + (2 * canary_size); 1823b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson} 1833b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson 1843b72a14c2515c1169d5501ada5499cf232fc643bZach Johnsonstatic bool allocation_entry_freed_checker(hash_map_entry_t *entry, void *context) { 1853b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson allocation_t *allocation = (allocation_t *)entry->data; 1863b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson if (!allocation->freed) { 1873b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson *((size_t *)context) += allocation->size; // Report back the unfreed byte count 188db554581079863974af8e1289646f5deea6fc044Marie Janssen LOG_ERROR(LOG_TAG, "%s found unfreed allocation. address: 0x%zx size: %zd bytes", __func__, (uintptr_t)allocation->ptr, allocation->size); 1893b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson } 1903b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson 1913b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson return true; 1923b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson} 19353f36a45bd5333db3b55f1d7fbcd7a3362027de0Zach Johnson 19453f36a45bd5333db3b55f1d7fbcd7a3362027de0Zach Johnsonstatic void *untracked_calloc(size_t size) { 19553f36a45bd5333db3b55f1d7fbcd7a3362027de0Zach Johnson return calloc(size, 1); 19653f36a45bd5333db3b55f1d7fbcd7a3362027de0Zach Johnson} 197