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 23f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He#include <base/logging.h> 243e59b5b6f2ce1295e3e2711afcd2cdf0dd7e22b6Etan Cohen#include <stdlib.h> 253e59b5b6f2ce1295e3e2711afcd2cdf0dd7e22b6Etan Cohen#include <string.h> 26a5764686f719d8d779d8a5ff8cc64010b7893e36Marie Janssen#include <mutex> 270d55d66da26c079669975becfc29675f6492a155Jakub Pawlowski#include <unordered_map> 283b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson 290f9b91e150e153229235c163861198e23600e636Sharvil Nanavati#include "osi/include/allocator.h" 3044802768c447ab480d4227b3a852a97d923b816dSharvil Nanavati#include "osi/include/log.h" 3149a86709488e5cfd5e23759da18bf9613e15b04dMarie Janssen#include "osi/include/osi.h" 323b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson 333b72a14c2515c1169d5501ada5499cf232fc643bZach Johnsontypedef struct { 344ed68b407ee836df7780a00d6b50b081b334c3abZach Johnson uint8_t allocator_id; 35b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson void* ptr; 363b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson size_t size; 373b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson bool freed; 383b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson} allocation_t; 393b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson 403387396e167819510c499b5a5486b499b3f4868fMarie Janssenstatic const size_t canary_size = 8; 413387396e167819510c499b5a5486b499b3f4868fMarie Janssenstatic char canary[canary_size]; 420d55d66da26c079669975becfc29675f6492a155Jakub Pawlowskistatic std::unordered_map<void*, allocation_t*> allocations; 43a5764686f719d8d779d8a5ff8cc64010b7893e36Marie Janssenstatic std::mutex tracker_lock; 440d55d66da26c079669975becfc29675f6492a155Jakub Pawlowskistatic bool enabled = false; 453b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson 460b4f3f7efb2b64e931cea7460c742628b8d0b8c0Pavlin Radoslavov// Memory allocation statistics 470b4f3f7efb2b64e931cea7460c742628b8d0b8c0Pavlin Radoslavovstatic size_t alloc_counter = 0; 480b4f3f7efb2b64e931cea7460c742628b8d0b8c0Pavlin Radoslavovstatic size_t free_counter = 0; 490b4f3f7efb2b64e931cea7460c742628b8d0b8c0Pavlin Radoslavovstatic size_t alloc_total_size = 0; 500b4f3f7efb2b64e931cea7460c742628b8d0b8c0Pavlin Radoslavovstatic size_t free_total_size = 0; 510b4f3f7efb2b64e931cea7460c742628b8d0b8c0Pavlin Radoslavov 52c0745da4fb23eea23abac3c3cfd51cc7f1d38f6dSharvil Nanavativoid allocation_tracker_init(void) { 53a5764686f719d8d779d8a5ff8cc64010b7893e36Marie Janssen std::unique_lock<std::mutex> lock(tracker_lock); 54b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson if (enabled) return; 553387396e167819510c499b5a5486b499b3f4868fMarie Janssen 563387396e167819510c499b5a5486b499b3f4868fMarie Janssen // randomize the canary contents 57b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson for (size_t i = 0; i < canary_size; i++) canary[i] = (char)osi_rand(); 583387396e167819510c499b5a5486b499b3f4868fMarie Janssen 593387396e167819510c499b5a5486b499b3f4868fMarie Janssen LOG_DEBUG(LOG_TAG, "canary initialized"); 60f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnson 610d55d66da26c079669975becfc29675f6492a155Jakub Pawlowski enabled = true; 623b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson} 633b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson 64ee2aa45def216a3c4d6a23481fa96f1b02a5de8cZach Johnson// Test function only. Do not call in the normal course of operations. 65c0745da4fb23eea23abac3c3cfd51cc7f1d38f6dSharvil Nanavativoid allocation_tracker_uninit(void) { 66a5764686f719d8d779d8a5ff8cc64010b7893e36Marie Janssen std::unique_lock<std::mutex> lock(tracker_lock); 67b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson if (!enabled) return; 685febd64b95260672d41964337377fb312ea2c07bPavlin Radoslavov 690d55d66da26c079669975becfc29675f6492a155Jakub Pawlowski allocations.clear(); 700d55d66da26c079669975becfc29675f6492a155Jakub Pawlowski enabled = false; 71ee2aa45def216a3c4d6a23481fa96f1b02a5de8cZach Johnson} 72ee2aa45def216a3c4d6a23481fa96f1b02a5de8cZach Johnson 733b72a14c2515c1169d5501ada5499cf232fc643bZach Johnsonvoid allocation_tracker_reset(void) { 74a5764686f719d8d779d8a5ff8cc64010b7893e36Marie Janssen std::unique_lock<std::mutex> lock(tracker_lock); 75b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson if (!enabled) return; 763b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson 770d55d66da26c079669975becfc29675f6492a155Jakub Pawlowski allocations.clear(); 783b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson} 793b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson 80c0745da4fb23eea23abac3c3cfd51cc7f1d38f6dSharvil Nanavatisize_t allocation_tracker_expect_no_allocations(void) { 81a5764686f719d8d779d8a5ff8cc64010b7893e36Marie Janssen std::unique_lock<std::mutex> lock(tracker_lock); 82b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson if (!enabled) return 0; 833b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson 843b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson size_t unfreed_memory_size = 0; 850d55d66da26c079669975becfc29675f6492a155Jakub Pawlowski 86b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson for (const auto& entry : allocations) { 87b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson allocation_t* allocation = entry.second; 880d55d66da26c079669975becfc29675f6492a155Jakub Pawlowski if (!allocation->freed) { 89b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson unfreed_memory_size += 90b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson allocation->size; // Report back the unfreed byte count 91b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson LOG_ERROR(LOG_TAG, 92b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson "%s found unfreed allocation. address: 0x%zx size: %zd bytes", 93b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson __func__, (uintptr_t)allocation->ptr, allocation->size); 940d55d66da26c079669975becfc29675f6492a155Jakub Pawlowski } 950d55d66da26c079669975becfc29675f6492a155Jakub Pawlowski } 963b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson 973b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson return unfreed_memory_size; 983b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson} 993b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson 100b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonvoid* allocation_tracker_notify_alloc(uint8_t allocator_id, void* ptr, 101b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson size_t requested_size) { 102b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson char* return_ptr; 103a5764686f719d8d779d8a5ff8cc64010b7893e36Marie Janssen { 104a5764686f719d8d779d8a5ff8cc64010b7893e36Marie Janssen std::unique_lock<std::mutex> lock(tracker_lock); 105b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson if (!enabled || !ptr) return ptr; 106a5764686f719d8d779d8a5ff8cc64010b7893e36Marie Janssen 1070b4f3f7efb2b64e931cea7460c742628b8d0b8c0Pavlin Radoslavov // Keep statistics 1080b4f3f7efb2b64e931cea7460c742628b8d0b8c0Pavlin Radoslavov alloc_counter++; 1090b4f3f7efb2b64e931cea7460c742628b8d0b8c0Pavlin Radoslavov alloc_total_size += allocation_tracker_resize_for_canary(requested_size); 1100b4f3f7efb2b64e931cea7460c742628b8d0b8c0Pavlin Radoslavov 111b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson return_ptr = ((char*)ptr) + canary_size; 112a5764686f719d8d779d8a5ff8cc64010b7893e36Marie Janssen 113a5764686f719d8d779d8a5ff8cc64010b7893e36Marie Janssen auto map_entry = allocations.find(return_ptr); 114b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson allocation_t* allocation; 115a5764686f719d8d779d8a5ff8cc64010b7893e36Marie Janssen if (map_entry != allocations.end()) { 116a5764686f719d8d779d8a5ff8cc64010b7893e36Marie Janssen allocation = map_entry->second; 117f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He CHECK(allocation->freed); // Must have been freed before 118a5764686f719d8d779d8a5ff8cc64010b7893e36Marie Janssen } else { 119b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson allocation = (allocation_t*)calloc(1, sizeof(allocation_t)); 120a5764686f719d8d779d8a5ff8cc64010b7893e36Marie Janssen allocations[return_ptr] = allocation; 121a5764686f719d8d779d8a5ff8cc64010b7893e36Marie Janssen } 1223b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson 123a5764686f719d8d779d8a5ff8cc64010b7893e36Marie Janssen allocation->allocator_id = allocator_id; 124a5764686f719d8d779d8a5ff8cc64010b7893e36Marie Janssen allocation->freed = false; 125a5764686f719d8d779d8a5ff8cc64010b7893e36Marie Janssen allocation->size = requested_size; 126a5764686f719d8d779d8a5ff8cc64010b7893e36Marie Janssen allocation->ptr = return_ptr; 1273b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson } 1283b72a14c2515c1169d5501ada5499cf232fc643bZach 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 136b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonvoid* allocation_tracker_notify_free(UNUSED_ATTR uint8_t allocator_id, 137b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson void* ptr) { 138a5764686f719d8d779d8a5ff8cc64010b7893e36Marie Janssen std::unique_lock<std::mutex> lock(tracker_lock); 1390b4f3f7efb2b64e931cea7460c742628b8d0b8c0Pavlin Radoslavov 140b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson if (!enabled || !ptr) return ptr; 1413b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson 1420d55d66da26c079669975becfc29675f6492a155Jakub Pawlowski auto map_entry = allocations.find(ptr); 143f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He CHECK(map_entry != allocations.end()); 144b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson allocation_t* allocation = map_entry->second; 145f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He CHECK(allocation); // Must have been tracked before 146f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He CHECK(!allocation->freed); // Must not be a double free 147f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He CHECK(allocation->allocator_id == 148f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He allocator_id); // Must be from the same allocator 1490b4f3f7efb2b64e931cea7460c742628b8d0b8c0Pavlin Radoslavov 1500b4f3f7efb2b64e931cea7460c742628b8d0b8c0Pavlin Radoslavov // Keep statistics 1510b4f3f7efb2b64e931cea7460c742628b8d0b8c0Pavlin Radoslavov free_counter++; 1520b4f3f7efb2b64e931cea7460c742628b8d0b8c0Pavlin Radoslavov free_total_size += allocation_tracker_resize_for_canary(allocation->size); 1530b4f3f7efb2b64e931cea7460c742628b8d0b8c0Pavlin Radoslavov 1543b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson allocation->freed = true; 1553b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson 156b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson UNUSED_ATTR const char* beginning_canary = ((char*)ptr) - canary_size; 157b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson UNUSED_ATTR const char* end_canary = ((char*)ptr) + allocation->size; 158f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnson 159c0745da4fb23eea23abac3c3cfd51cc7f1d38f6dSharvil Nanavati for (size_t i = 0; i < canary_size; i++) { 160f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He CHECK(beginning_canary[i] == canary[i]); 161f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He CHECK(end_canary[i] == canary[i]); 162f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnson } 163f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnson 164bb9148eda25d7d39399fd837d4b13be9b4ecccb4Srinu Jella // Free the hash map entry to avoid unlimited memory usage growth. 165bb9148eda25d7d39399fd837d4b13be9b4ecccb4Srinu Jella // Double-free of memory is detected with "assert(allocation)" above 166bb9148eda25d7d39399fd837d4b13be9b4ecccb4Srinu Jella // as the allocation entry will not be present. 1670d55d66da26c079669975becfc29675f6492a155Jakub Pawlowski allocations.erase(ptr); 1681aa40037fde7e57ae99468b9dd40e7788ed3978bPavlin Radoslavov free(allocation); 169bb9148eda25d7d39399fd837d4b13be9b4ecccb4Srinu Jella 170b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson return ((char*)ptr) - canary_size; 171f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnson} 172f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnson 173f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnsonsize_t allocation_tracker_resize_for_canary(size_t size) { 1740d55d66da26c079669975becfc29675f6492a155Jakub Pawlowski return (!enabled) ? size : size + (2 * canary_size); 17553f36a45bd5333db3b55f1d7fbcd7a3362027de0Zach Johnson} 1760b4f3f7efb2b64e931cea7460c742628b8d0b8c0Pavlin Radoslavov 1770b4f3f7efb2b64e931cea7460c742628b8d0b8c0Pavlin Radoslavovvoid osi_allocator_debug_dump(int fd) { 1780b4f3f7efb2b64e931cea7460c742628b8d0b8c0Pavlin Radoslavov dprintf(fd, "\nBluetooth Memory Allocation Statistics:\n"); 1790b4f3f7efb2b64e931cea7460c742628b8d0b8c0Pavlin Radoslavov 1800b4f3f7efb2b64e931cea7460c742628b8d0b8c0Pavlin Radoslavov std::unique_lock<std::mutex> lock(tracker_lock); 1810b4f3f7efb2b64e931cea7460c742628b8d0b8c0Pavlin Radoslavov 1820b4f3f7efb2b64e931cea7460c742628b8d0b8c0Pavlin Radoslavov dprintf(fd, " Total allocated/free/used counts : %zu / %zu / %zu\n", 1830b4f3f7efb2b64e931cea7460c742628b8d0b8c0Pavlin Radoslavov alloc_counter, free_counter, alloc_counter - free_counter); 1840b4f3f7efb2b64e931cea7460c742628b8d0b8c0Pavlin Radoslavov dprintf(fd, " Total allocated/free/used octets : %zu / %zu / %zu\n", 1850b4f3f7efb2b64e931cea7460c742628b8d0b8c0Pavlin Radoslavov alloc_total_size, free_total_size, 1860b4f3f7efb2b64e931cea7460c742628b8d0b8c0Pavlin Radoslavov alloc_total_size - free_total_size); 1870b4f3f7efb2b64e931cea7460c742628b8d0b8c0Pavlin Radoslavov} 188