1// Copyright (c) 2007, Google Inc.
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions are
6// met:
7//
8//     * Redistributions of source code must retain the above copyright
9// notice, this list of conditions and the following disclaimer.
10//     * Redistributions in binary form must reproduce the above
11// copyright notice, this list of conditions and the following disclaimer
12// in the documentation and/or other materials provided with the
13// distribution.
14//     * Neither the name of Google Inc. nor the names of its
15// contributors may be used to endorse or promote products derived from
16// this software without specific prior written permission.
17//
18// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30// ---
31// Author: Fred Akalin
32
33#include <stdio.h>
34#include <stdlib.h>
35#include <vector>
36#include "gperftools/malloc_extension.h"
37#include "base/logging.h"
38
39using std::vector;
40
41vector<void (*)()> g_testlist;  // the tests to run
42
43#define TEST(a, b)                                      \
44  struct Test_##a##_##b {                               \
45    Test_##a##_##b() { g_testlist.push_back(&Run); }    \
46    static void Run();                                  \
47  };                                                    \
48  static Test_##a##_##b g_test_##a##_##b;               \
49  void Test_##a##_##b::Run()
50
51
52static int RUN_ALL_TESTS() {
53  vector<void (*)()>::const_iterator it;
54  for (it = g_testlist.begin(); it != g_testlist.end(); ++it) {
55    (*it)();   // The test will error-exit if there's a problem.
56  }
57  fprintf(stderr, "\nPassed %d tests\n\nPASS\n",
58          static_cast<int>(g_testlist.size()));
59  return 0;
60}
61
62// The death tests are meant to be run from a shell-script driver, which
63// passes in an integer saying which death test to run.  We store that
64// test-to-run here, and in the macro use a counter to see when we get
65// to that test, so we can run it.
66static int test_to_run = 0;     // set in main() based on argv
67static int test_counter = 0;    // incremented every time the macro is called
68#define IF_DEBUG_EXPECT_DEATH(statement, regex) do {    \
69  if (test_counter++ == test_to_run) {                  \
70    fprintf(stderr, "Expected regex:%s\n", regex);      \
71    statement;                                          \
72  }                                                     \
73} while (false)
74
75// This flag won't be compiled in in opt mode.
76DECLARE_int32(max_free_queue_size);
77
78// Test match as well as mismatch rules.  But do not test on OS X; on
79// OS X the OS converts new/new[] to malloc before it gets to us, so
80// we are unable to catch these mismatch errors.
81#ifndef __APPLE__
82TEST(DebugAllocationTest, DeallocMismatch) {
83  // malloc can be matched only by free
84  // new can be matched only by delete and delete(nothrow)
85  // new[] can be matched only by delete[] and delete[](nothrow)
86  // new(nothrow) can be matched only by delete and delete(nothrow)
87  // new(nothrow)[] can be matched only by delete[] and delete[](nothrow)
88
89  // Allocate with malloc.
90  {
91    int* x = static_cast<int*>(malloc(sizeof(*x)));
92    IF_DEBUG_EXPECT_DEATH(delete x, "mismatch.*being dealloc.*delete");
93    IF_DEBUG_EXPECT_DEATH(delete [] x, "mismatch.*being dealloc.*delete *[[]");
94    // Should work fine.
95    free(x);
96  }
97
98  // Allocate with new.
99  {
100    int* x = new int;
101    int* y = new int;
102    IF_DEBUG_EXPECT_DEATH(free(x), "mismatch.*being dealloc.*free");
103    IF_DEBUG_EXPECT_DEATH(delete [] x, "mismatch.*being dealloc.*delete *[[]");
104    delete x;
105    ::operator delete(y, std::nothrow);
106  }
107
108  // Allocate with new[].
109  {
110    int* x = new int[1];
111    int* y = new int[1];
112    IF_DEBUG_EXPECT_DEATH(free(x), "mismatch.*being dealloc.*free");
113    IF_DEBUG_EXPECT_DEATH(delete x, "mismatch.*being dealloc.*delete");
114    delete [] x;
115    ::operator delete[](y, std::nothrow);
116  }
117
118  // Allocate with new(nothrow).
119  {
120    int* x = new(std::nothrow) int;
121    int* y = new(std::nothrow) int;
122    IF_DEBUG_EXPECT_DEATH(free(x), "mismatch.*being dealloc.*free");
123    IF_DEBUG_EXPECT_DEATH(delete [] x, "mismatch.*being dealloc.*delete *[[]");
124    delete x;
125    ::operator delete(y, std::nothrow);
126  }
127
128  // Allocate with new(nothrow)[].
129  {
130    int* x = new(std::nothrow) int[1];
131    int* y = new(std::nothrow) int[1];
132    IF_DEBUG_EXPECT_DEATH(free(x), "mismatch.*being dealloc.*free");
133    IF_DEBUG_EXPECT_DEATH(delete x, "mismatch.*being dealloc.*delete");
134    delete [] x;
135    ::operator delete[](y, std::nothrow);
136  }
137}
138#endif  // #ifdef OS_MACOSX
139
140TEST(DebugAllocationTest, DoubleFree) {
141  int* pint = new int;
142  delete pint;
143  IF_DEBUG_EXPECT_DEATH(delete pint, "has been already deallocated");
144}
145
146TEST(DebugAllocationTest, StompBefore) {
147  int* pint = new int;
148#ifndef NDEBUG   // don't stomp memory if we're not in a position to detect it
149  pint[-1] = 5;
150  IF_DEBUG_EXPECT_DEATH(delete pint, "a word before object");
151#endif
152}
153
154TEST(DebugAllocationTest, StompAfter) {
155  int* pint = new int;
156#ifndef NDEBUG   // don't stomp memory if we're not in a position to detect it
157  pint[1] = 5;
158  IF_DEBUG_EXPECT_DEATH(delete pint, "a word after object");
159#endif
160}
161
162TEST(DebugAllocationTest, FreeQueueTest) {
163  // Verify that the allocator doesn't return blocks that were recently freed.
164  int* x = new int;
165  int* old_x = x;
166  delete x;
167  x = new int;
168  #if 1
169    // This check should not be read as a universal guarantee of behavior.  If
170    // other threads are executing, it would be theoretically possible for this
171    // check to fail despite the efforts of debugallocation.cc to the contrary.
172    // It should always hold under the controlled conditions of this unittest,
173    // however.
174    EXPECT_NE(x, old_x);  // Allocator shouldn't return recently freed blocks
175  #else
176    // The below check passes, but since it isn't *required* to pass, I've left
177    // it commented out.
178    // EXPECT_EQ(x, old_x);
179  #endif
180  old_x = NULL;  // avoid breaking opt build with an unused variable warning.
181  delete x;
182}
183
184TEST(DebugAllocationTest, DanglingPointerWriteTest) {
185  // This test can only be run if debugging.
186  //
187  // If not debugging, the 'new' following the dangling write might not be
188  // safe.  When debugging, we expect the (trashed) deleted block to be on the
189  // list of recently-freed blocks, so the following 'new' will be safe.
190#if 1
191  int* x = new int;
192  delete x;
193  int poisoned_x_value = *x;
194  *x = 1;  // a dangling write.
195
196  char* s = new char[FLAGS_max_free_queue_size];
197  // When we delete s, we push the storage that was previously allocated to x
198  // off the end of the free queue.  At that point, the write to that memory
199  // will be detected.
200  IF_DEBUG_EXPECT_DEATH(delete [] s, "Memory was written to after being freed.");
201
202  // restore the poisoned value of x so that we can delete s without causing a
203  // crash.
204  *x = poisoned_x_value;
205  delete [] s;
206#endif
207}
208
209TEST(DebugAllocationTest, DanglingWriteAtExitTest) {
210  int *x = new int;
211  delete x;
212  int old_x_value = *x;
213  *x = 1;
214  // verify that dangling writes are caught at program termination if the
215  // corrupted block never got pushed off of the end of the free queue.
216  IF_DEBUG_EXPECT_DEATH(exit(0), "Memory was written to after being freed.");
217  *x = old_x_value;  // restore x so that the test can exit successfully.
218}
219
220TEST(DebugAllocationTest, StackTraceWithDanglingWriteAtExitTest) {
221  int *x = new int;
222  delete x;
223  int old_x_value = *x;
224  *x = 1;
225  // verify that we also get a stack trace when we have a dangling write.
226  // The " @ " is part of the stack trace output.
227  IF_DEBUG_EXPECT_DEATH(exit(0), " @ .*main");
228  *x = old_x_value;  // restore x so that the test can exit successfully.
229}
230
231static size_t CurrentlyAllocatedBytes() {
232  size_t value;
233  CHECK(MallocExtension::instance()->GetNumericProperty(
234            "generic.current_allocated_bytes", &value));
235  return value;
236}
237
238TEST(DebugAllocationTest, CurrentlyAllocated) {
239  // Clear the free queue
240#if 1
241  FLAGS_max_free_queue_size = 0;
242  // Force a round-trip through the queue management code so that the
243  // new size is seen and the queue of recently-freed blocks is flushed.
244  free(malloc(1));
245  FLAGS_max_free_queue_size = 1048576;
246#endif
247
248  // Free something and check that it disappears from allocated bytes
249  // immediately.
250  char* p = new char[1000];
251  size_t after_malloc = CurrentlyAllocatedBytes();
252  delete[] p;
253  size_t after_free = CurrentlyAllocatedBytes();
254  EXPECT_LE(after_free, after_malloc - 1000);
255}
256
257TEST(DebugAllocationTest, GetAllocatedSizeTest) {
258#if 1
259  // When debug_allocation is in effect, GetAllocatedSize should return
260  // exactly requested size, since debug_allocation doesn't allow users
261  // to write more than that.
262  for (int i = 0; i < 10; ++i) {
263    void *p = malloc(i);
264    EXPECT_EQ(i, MallocExtension::instance()->GetAllocatedSize(p));
265    free(p);
266  }
267#endif
268  void* a = malloc(1000);
269  EXPECT_GE(MallocExtension::instance()->GetAllocatedSize(a), 1000);
270  // This is just a sanity check.  If we allocated too much, alloc is broken
271  EXPECT_LE(MallocExtension::instance()->GetAllocatedSize(a), 5000);
272  EXPECT_GE(MallocExtension::instance()->GetEstimatedAllocatedSize(1000), 1000);
273  free(a);
274}
275
276TEST(DebugAllocationTest, HugeAlloc) {
277  // This must not be a const variable so it doesn't form an
278  // integral-constant-expression which can be *statically* rejected by the
279  // compiler as too large for the allocation.
280  size_t kTooBig = ~static_cast<size_t>(0);
281  void* a = NULL;
282
283#ifndef NDEBUG
284
285  a = malloc(kTooBig);
286  EXPECT_EQ(NULL, a);
287
288  // kAlsoTooBig is small enough not to get caught by debugallocation's check,
289  // but will still fall through to tcmalloc's check. This must also be
290  // a non-const variable. See kTooBig for more details.
291  size_t kAlsoTooBig = kTooBig - 1024;
292
293  a = malloc(kAlsoTooBig);
294  EXPECT_EQ(NULL, a);
295#endif
296}
297
298int main(int argc, char** argv) {
299  // If you run without args, we run the non-death parts of the test.
300  // Otherwise, argv[1] should be a number saying which death-test
301  // to run.  We will output a regexp we expect the death-message
302  // to include, and then run the given death test (which hopefully
303  // will produce that error message).  If argv[1] > the number of
304  // death tests, we will run only the non-death parts.  One way to
305  // tell when you are done with all tests is when no 'expected
306  // regexp' message is printed for a given argv[1].
307  if (argc < 2) {
308    test_to_run = -1;   // will never match
309  } else {
310    test_to_run = atoi(argv[1]);
311  }
312  return RUN_ALL_TESTS();
313}
314