1/*
2 * Copyright 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <stdio.h>
18#include <stdlib.h>
19#include <string.h>
20
21#include <map>
22
23#include <base/debug/stack_trace.h>
24
25#include <libatap/libatap.h>
26
27void* atap_memcpy(void* dest, const void* src, size_t n) {
28  return memcpy(dest, src, n);
29}
30
31void* atap_memset(void* dest, const int c, size_t n) {
32  return memset(dest, c, n);
33}
34
35void atap_abort(void) {
36  abort();
37}
38
39void atap_print(const char* message) {
40  fprintf(stderr, "%s", message);
41}
42
43void atap_printv(const char* message, ...) {
44  va_list ap;
45  const char* m;
46
47  va_start(ap, message);
48  for (m = message; m != NULL; m = va_arg(ap, const char*)) {
49    fprintf(stderr, "%s", m);
50  }
51  va_end(ap);
52}
53
54size_t atap_strlen(const char* str) {
55  return strlen(str);
56}
57
58typedef struct {
59  size_t size;
60  base::debug::StackTrace stack_trace;
61} AtapAllocatedBlock;
62
63static std::map<void*, AtapAllocatedBlock> allocated_blocks;
64
65void* atap_malloc(size_t size) {
66  void* ptr = malloc(size);
67  atap_assert(ptr != nullptr);
68  AtapAllocatedBlock block;
69  block.size = size;
70  allocated_blocks[ptr] = block;
71  return ptr;
72}
73
74void atap_free(void* ptr) {
75  auto block_it = allocated_blocks.find(ptr);
76  if (block_it == allocated_blocks.end()) {
77    atap_fatal("Tried to free pointer to non-allocated block.\n");
78    return;
79  }
80  allocated_blocks.erase(block_it);
81  free(ptr);
82}
83
84namespace atap {
85
86void testing_memory_reset() {
87  allocated_blocks.clear();
88}
89
90bool testing_memory_all_freed() {
91  if (allocated_blocks.size() == 0) {
92    return true;
93  }
94
95  size_t sum = 0;
96  for (const auto& block_it : allocated_blocks) {
97    sum += block_it.second.size;
98  }
99  fprintf(stderr,
100          "%zd bytes still allocated in %zd blocks:\n",
101          sum,
102          allocated_blocks.size());
103  size_t n = 0;
104  for (const auto& block_it : allocated_blocks) {
105    fprintf(stderr,
106            "--\nAllocation %zd/%zd of %zd bytes:\n",
107            1 + n++,
108            allocated_blocks.size(),
109            block_it.second.size);
110    block_it.second.stack_trace.Print();
111  }
112  return false;
113}
114
115// Also check leaks at process exit.
116__attribute__((destructor)) static void ensure_all_memory_freed_at_exit() {
117  if (!testing_memory_all_freed()) {
118    atap_fatal("libatap memory leaks at process exit.\n");
119  }
120}
121
122}  // namespace atap
123