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