allocation_tracker.cc revision f2af1c42ccb2f642b241c2261b42d0be61d45438
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 46c0745da4fb23eea23abac3c3cfd51cc7f1d38f6dSharvil Nanavativoid allocation_tracker_init(void) { 47a5764686f719d8d779d8a5ff8cc64010b7893e36Marie Janssen std::unique_lock<std::mutex> lock(tracker_lock); 48b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson if (enabled) return; 493387396e167819510c499b5a5486b499b3f4868fMarie Janssen 503387396e167819510c499b5a5486b499b3f4868fMarie Janssen // randomize the canary contents 51b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson for (size_t i = 0; i < canary_size; i++) canary[i] = (char)osi_rand(); 523387396e167819510c499b5a5486b499b3f4868fMarie Janssen 533387396e167819510c499b5a5486b499b3f4868fMarie Janssen LOG_DEBUG(LOG_TAG, "canary initialized"); 54f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnson 550d55d66da26c079669975becfc29675f6492a155Jakub Pawlowski enabled = true; 563b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson} 573b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson 58ee2aa45def216a3c4d6a23481fa96f1b02a5de8cZach Johnson// Test function only. Do not call in the normal course of operations. 59c0745da4fb23eea23abac3c3cfd51cc7f1d38f6dSharvil Nanavativoid allocation_tracker_uninit(void) { 60a5764686f719d8d779d8a5ff8cc64010b7893e36Marie Janssen std::unique_lock<std::mutex> lock(tracker_lock); 61b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson if (!enabled) return; 625febd64b95260672d41964337377fb312ea2c07bPavlin Radoslavov 630d55d66da26c079669975becfc29675f6492a155Jakub Pawlowski allocations.clear(); 640d55d66da26c079669975becfc29675f6492a155Jakub Pawlowski enabled = false; 65ee2aa45def216a3c4d6a23481fa96f1b02a5de8cZach Johnson} 66ee2aa45def216a3c4d6a23481fa96f1b02a5de8cZach Johnson 673b72a14c2515c1169d5501ada5499cf232fc643bZach Johnsonvoid allocation_tracker_reset(void) { 68a5764686f719d8d779d8a5ff8cc64010b7893e36Marie Janssen std::unique_lock<std::mutex> lock(tracker_lock); 69b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson if (!enabled) return; 703b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson 710d55d66da26c079669975becfc29675f6492a155Jakub Pawlowski allocations.clear(); 723b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson} 733b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson 74c0745da4fb23eea23abac3c3cfd51cc7f1d38f6dSharvil Nanavatisize_t allocation_tracker_expect_no_allocations(void) { 75a5764686f719d8d779d8a5ff8cc64010b7893e36Marie Janssen std::unique_lock<std::mutex> lock(tracker_lock); 76b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson if (!enabled) return 0; 773b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson 783b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson size_t unfreed_memory_size = 0; 790d55d66da26c079669975becfc29675f6492a155Jakub Pawlowski 80b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson for (const auto& entry : allocations) { 81b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson allocation_t* allocation = entry.second; 820d55d66da26c079669975becfc29675f6492a155Jakub Pawlowski if (!allocation->freed) { 83b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson unfreed_memory_size += 84b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson allocation->size; // Report back the unfreed byte count 85b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson LOG_ERROR(LOG_TAG, 86b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson "%s found unfreed allocation. address: 0x%zx size: %zd bytes", 87b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson __func__, (uintptr_t)allocation->ptr, allocation->size); 880d55d66da26c079669975becfc29675f6492a155Jakub Pawlowski } 890d55d66da26c079669975becfc29675f6492a155Jakub Pawlowski } 903b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson 913b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson return unfreed_memory_size; 923b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson} 933b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson 94b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonvoid* allocation_tracker_notify_alloc(uint8_t allocator_id, void* ptr, 95b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson size_t requested_size) { 96b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson char* return_ptr; 97a5764686f719d8d779d8a5ff8cc64010b7893e36Marie Janssen { 98a5764686f719d8d779d8a5ff8cc64010b7893e36Marie Janssen std::unique_lock<std::mutex> lock(tracker_lock); 99b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson if (!enabled || !ptr) return ptr; 100a5764686f719d8d779d8a5ff8cc64010b7893e36Marie Janssen 101b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson return_ptr = ((char*)ptr) + canary_size; 102a5764686f719d8d779d8a5ff8cc64010b7893e36Marie Janssen 103a5764686f719d8d779d8a5ff8cc64010b7893e36Marie Janssen auto map_entry = allocations.find(return_ptr); 104b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson allocation_t* allocation; 105a5764686f719d8d779d8a5ff8cc64010b7893e36Marie Janssen if (map_entry != allocations.end()) { 106a5764686f719d8d779d8a5ff8cc64010b7893e36Marie Janssen allocation = map_entry->second; 107f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He CHECK(allocation->freed); // Must have been freed before 108a5764686f719d8d779d8a5ff8cc64010b7893e36Marie Janssen } else { 109b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson allocation = (allocation_t*)calloc(1, sizeof(allocation_t)); 110a5764686f719d8d779d8a5ff8cc64010b7893e36Marie Janssen allocations[return_ptr] = allocation; 111a5764686f719d8d779d8a5ff8cc64010b7893e36Marie Janssen } 1123b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson 113a5764686f719d8d779d8a5ff8cc64010b7893e36Marie Janssen allocation->allocator_id = allocator_id; 114a5764686f719d8d779d8a5ff8cc64010b7893e36Marie Janssen allocation->freed = false; 115a5764686f719d8d779d8a5ff8cc64010b7893e36Marie Janssen allocation->size = requested_size; 116a5764686f719d8d779d8a5ff8cc64010b7893e36Marie Janssen allocation->ptr = return_ptr; 1173b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson } 1183b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson 119c0745da4fb23eea23abac3c3cfd51cc7f1d38f6dSharvil Nanavati // Add the canary on both sides 120c0745da4fb23eea23abac3c3cfd51cc7f1d38f6dSharvil Nanavati memcpy(return_ptr - canary_size, canary, canary_size); 121c0745da4fb23eea23abac3c3cfd51cc7f1d38f6dSharvil Nanavati memcpy(return_ptr + requested_size, canary, canary_size); 122f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnson 123f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnson return return_ptr; 1243b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson} 1253b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson 126b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonvoid* allocation_tracker_notify_free(UNUSED_ATTR uint8_t allocator_id, 127b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson void* ptr) { 128a5764686f719d8d779d8a5ff8cc64010b7893e36Marie Janssen std::unique_lock<std::mutex> lock(tracker_lock); 129b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson if (!enabled || !ptr) return ptr; 1303b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson 1310d55d66da26c079669975becfc29675f6492a155Jakub Pawlowski auto map_entry = allocations.find(ptr); 132f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He CHECK(map_entry != allocations.end()); 133b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson allocation_t* allocation = map_entry->second; 134f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He CHECK(allocation); // Must have been tracked before 135f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He CHECK(!allocation->freed); // Must not be a double free 136f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He CHECK(allocation->allocator_id == 137f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He allocator_id); // Must be from the same allocator 1383b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson allocation->freed = true; 1393b72a14c2515c1169d5501ada5499cf232fc643bZach Johnson 140b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson UNUSED_ATTR const char* beginning_canary = ((char*)ptr) - canary_size; 141b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson UNUSED_ATTR const char* end_canary = ((char*)ptr) + allocation->size; 142f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnson 143c0745da4fb23eea23abac3c3cfd51cc7f1d38f6dSharvil Nanavati for (size_t i = 0; i < canary_size; i++) { 144f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He CHECK(beginning_canary[i] == canary[i]); 145f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He CHECK(end_canary[i] == canary[i]); 146f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnson } 147f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnson 148bb9148eda25d7d39399fd837d4b13be9b4ecccb4Srinu Jella // Free the hash map entry to avoid unlimited memory usage growth. 149bb9148eda25d7d39399fd837d4b13be9b4ecccb4Srinu Jella // Double-free of memory is detected with "assert(allocation)" above 150bb9148eda25d7d39399fd837d4b13be9b4ecccb4Srinu Jella // as the allocation entry will not be present. 1510d55d66da26c079669975becfc29675f6492a155Jakub Pawlowski allocations.erase(ptr); 152bb9148eda25d7d39399fd837d4b13be9b4ecccb4Srinu Jella 153b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson return ((char*)ptr) - canary_size; 154f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnson} 155f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnson 156f947fdddf5de6bd30886688a2b399460a3d95eccZach Johnsonsize_t allocation_tracker_resize_for_canary(size_t size) { 1570d55d66da26c079669975becfc29675f6492a155Jakub Pawlowski return (!enabled) ? size : size + (2 * canary_size); 15853f36a45bd5333db3b55f1d7fbcd7a3362027de0Zach Johnson} 159