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