1
/* Copyright (c) 2006, Google Inc.
4
* Redistribution and use in source and binary forms, with or without
5
* modification, are permitted provided that the following conditions are
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
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.
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.
31
* Author: Mike Burrows
34
// A test for low_level_alloc.cc
37
#include "base/low_level_alloc.h"
38
#include "base/logging.h"
39
#include <google/malloc_hook.h>
43
// a block of memory obtained from the allocator
45
char *ptr; // pointer to memory
46
int len; // number of bytes
47
int fill; // filled with data starting with this
50
// Check that the pattern placed in the block d
51
// by RandomizeBlockDesc is still there.
52
static void CheckBlockDesc(const BlockDesc &d) {
53
for (int i = 0; i != d.len; i++) {
54
CHECK((d.ptr[i] & 0xff) == ((d.fill + i) & 0xff));
58
// Fill the block "*d" with a pattern
59
// starting with a random byte.
60
static void RandomizeBlockDesc(BlockDesc *d) {
61
d->fill = rand() & 0xff;
62
for (int i = 0; i != d->len; i++) {
63
d->ptr[i] = (d->fill + i) & 0xff;
67
// Use to indicate to the malloc hooks that
68
// this calls is from LowLevelAlloc.
69
static bool using_low_level_alloc = false;
71
// n times, toss a coin, and based on the outcome
72
// either allocate a new block or deallocate an old block.
73
// New blocks are placed in a map with a random key
74
// and initialized with RandomizeBlockDesc().
75
// If keys conflict, the older block is freed.
76
// Old blocks are always checked with CheckBlockDesc()
77
// before being freed. At the end of the run,
78
// all remaining allocated blocks are freed.
79
// If use_new_arena is true, use a fresh arena, and then delete it.
80
// If call_malloc_hook is true and user_arena is true,
81
// allocations and deallocations are reported via the MallocHook
83
static void Test(bool use_new_arena, bool call_malloc_hook, int n) {
84
typedef map<int, BlockDesc> AllocMap;
86
AllocMap::iterator it;
89
LowLevelAlloc::Arena *arena = 0;
91
int32 flags = call_malloc_hook? LowLevelAlloc::kCallMallocHook : 0;
92
arena = LowLevelAlloc::NewArena(flags, LowLevelAlloc::DefaultArena());
94
for (int i = 0; i != n; i++) {
95
switch(rand() & 1) { // toss a coin
96
case 0: // coin came up heads: add a block
97
using_low_level_alloc = true;
98
block_desc.len = rand() & 0x3fff;
100
reinterpret_cast<char *>(
102
? LowLevelAlloc::Alloc(block_desc.len)
103
: LowLevelAlloc::AllocWithArena(block_desc.len, arena));
104
using_low_level_alloc = false;
105
RandomizeBlockDesc(&block_desc);
107
it = allocated.find(rnd);
108
if (it != allocated.end()) {
109
CheckBlockDesc(it->second);
110
using_low_level_alloc = true;
111
LowLevelAlloc::Free(it->second.ptr);
112
using_low_level_alloc = false;
113
it->second = block_desc;
115
allocated[rnd] = block_desc;
118
case 1: // coin came up tails: remove a block
119
it = allocated.begin();
120
if (it != allocated.end()) {
121
CheckBlockDesc(it->second);
122
using_low_level_alloc = true;
123
LowLevelAlloc::Free(it->second.ptr);
124
using_low_level_alloc = false;
130
// remove all remaniing blocks
131
while ((it = allocated.begin()) != allocated.end()) {
132
CheckBlockDesc(it->second);
133
using_low_level_alloc = true;
134
LowLevelAlloc::Free(it->second.ptr);
135
using_low_level_alloc = false;
139
CHECK(LowLevelAlloc::DeleteArena(arena));
143
// used for counting allocates and frees
144
static int32 allocates;
146
static MallocHook::NewHook old_alloc_hook;
147
static MallocHook::DeleteHook old_free_hook;
149
// called on each alloc if kCallMallocHook specified
150
static void AllocHook(const void *p, size_t size) {
151
if (using_low_level_alloc) {
154
if (old_alloc_hook != 0) {
155
(*old_alloc_hook)(p, size);
159
// called on each free if kCallMallocHook specified
160
static void FreeHook(const void *p) {
161
if (using_low_level_alloc) {
164
if (old_free_hook != 0) {
169
int main(int argc, char *argv[]) {
170
// This is needed by maybe_threads_unittest.sh, which parses argv[0]
171
// to figure out what directory low_level_alloc_unittest is in.
173
fprintf(stderr, "USAGE: %s\n", argv[0]);
177
old_alloc_hook = MallocHook::SetNewHook(AllocHook);
178
old_free_hook = MallocHook::SetDeleteHook(FreeHook);
179
CHECK_EQ(allocates, 0);
181
Test(false, false, 50000);
182
CHECK_NE(allocates, 0); // default arena calls hooks
184
for (int i = 0; i != 16; i++) {
185
bool call_hooks = ((i & 1) == 1);
188
Test(true, call_hooks, 15000);
190
CHECK_GT(allocates, 5000); // arena calls hooks
191
CHECK_GT(frees, 5000);
193
CHECK_EQ(allocates, 0); // arena doesn't call hooks
198
CHECK_EQ(MallocHook::SetNewHook(old_alloc_hook), AllocHook);
199
CHECK_EQ(MallocHook::SetDeleteHook(old_free_hook), FreeHook);