allocator_unittests.cc revision c7f5f8508d98d5952d42ed7648c2a8f30a4da156
1// Copyright (c) 2009 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <stdio.h>
6#include <stdlib.h>
7#include <algorithm>   // for min()
8#include "base/atomicops.h"
9#include "base/logging.h"
10#include "testing/gtest/include/gtest/gtest.h"
11
12// Number of bits in a size_t.
13static const int kSizeBits = 8 * sizeof(size_t);
14// The maximum size of a size_t.
15static const size_t kMaxSize = ~static_cast<size_t>(0);
16// Maximum positive size of a size_t if it were signed.
17static const size_t kMaxSignedSize = ((size_t(1) << (kSizeBits-1)) - 1);
18// An allocation size which is not too big to be reasonable.
19static const size_t kNotTooBig = 100000;
20// An allocation size which is just too big.
21static const size_t kTooBig = ~static_cast<size_t>(0);
22
23namespace {
24
25using std::min;
26
27// Fill a buffer of the specified size with a predetermined pattern
28static void Fill(unsigned char* buffer, int n) {
29  for (int i = 0; i < n; i++) {
30    buffer[i] = (i & 0xff);
31  }
32}
33
34// Check that the specified buffer has the predetermined pattern
35// generated by Fill()
36static bool Valid(unsigned char* buffer, int n) {
37  for (int i = 0; i < n; i++) {
38    if (buffer[i] != (i & 0xff)) {
39      return false;
40    }
41  }
42  return true;
43}
44
45// Check that a buffer is completely zeroed.
46static bool IsZeroed(unsigned char* buffer, int n) {
47  for (int i = 0; i < n; i++) {
48    if (buffer[i] != 0) {
49      return false;
50    }
51  }
52  return true;
53}
54
55// Check alignment
56static void CheckAlignment(void* p, int align) {
57  EXPECT_EQ(0, reinterpret_cast<uintptr_t>(p) & (align-1));
58}
59
60// Return the next interesting size/delta to check.  Returns -1 if no more.
61static int NextSize(int size) {
62  if (size < 100)
63    return size+1;
64
65  if (size < 100000) {
66    // Find next power of two
67    int power = 1;
68    while (power < size)
69      power <<= 1;
70
71    // Yield (power-1, power, power+1)
72    if (size < power-1)
73      return power-1;
74
75    if (size == power-1)
76      return power;
77
78    assert(size == power);
79    return power+1;
80  } else {
81    return -1;
82  }
83}
84
85#define GG_ULONGLONG(x)  static_cast<uint64>(x)
86
87template <class AtomicType>
88static void TestAtomicIncrement() {
89  // For now, we just test single threaded execution
90
91  // use a guard value to make sure the NoBarrier_AtomicIncrement doesn't go
92  // outside the expected address bounds.  This is in particular to
93  // test that some future change to the asm code doesn't cause the
94  // 32-bit NoBarrier_AtomicIncrement to do the wrong thing on 64-bit machines.
95  struct {
96    AtomicType prev_word;
97    AtomicType count;
98    AtomicType next_word;
99  } s;
100
101  AtomicType prev_word_value, next_word_value;
102  memset(&prev_word_value, 0xFF, sizeof(AtomicType));
103  memset(&next_word_value, 0xEE, sizeof(AtomicType));
104
105  s.prev_word = prev_word_value;
106  s.count = 0;
107  s.next_word = next_word_value;
108
109  EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, 1), 1);
110  EXPECT_EQ(s.count, 1);
111  EXPECT_EQ(s.prev_word, prev_word_value);
112  EXPECT_EQ(s.next_word, next_word_value);
113
114  EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, 2), 3);
115  EXPECT_EQ(s.count, 3);
116  EXPECT_EQ(s.prev_word, prev_word_value);
117  EXPECT_EQ(s.next_word, next_word_value);
118
119  EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, 3), 6);
120  EXPECT_EQ(s.count, 6);
121  EXPECT_EQ(s.prev_word, prev_word_value);
122  EXPECT_EQ(s.next_word, next_word_value);
123
124  EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, -3), 3);
125  EXPECT_EQ(s.count, 3);
126  EXPECT_EQ(s.prev_word, prev_word_value);
127  EXPECT_EQ(s.next_word, next_word_value);
128
129  EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, -2), 1);
130  EXPECT_EQ(s.count, 1);
131  EXPECT_EQ(s.prev_word, prev_word_value);
132  EXPECT_EQ(s.next_word, next_word_value);
133
134  EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, -1), 0);
135  EXPECT_EQ(s.count, 0);
136  EXPECT_EQ(s.prev_word, prev_word_value);
137  EXPECT_EQ(s.next_word, next_word_value);
138
139  EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, -1), -1);
140  EXPECT_EQ(s.count, -1);
141  EXPECT_EQ(s.prev_word, prev_word_value);
142  EXPECT_EQ(s.next_word, next_word_value);
143
144  EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, -4), -5);
145  EXPECT_EQ(s.count, -5);
146  EXPECT_EQ(s.prev_word, prev_word_value);
147  EXPECT_EQ(s.next_word, next_word_value);
148
149  EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, 5), 0);
150  EXPECT_EQ(s.count, 0);
151  EXPECT_EQ(s.prev_word, prev_word_value);
152  EXPECT_EQ(s.next_word, next_word_value);
153}
154
155
156#define NUM_BITS(T) (sizeof(T) * 8)
157
158
159template <class AtomicType>
160static void TestCompareAndSwap() {
161  AtomicType value = 0;
162  AtomicType prev = base::subtle::NoBarrier_CompareAndSwap(&value, 0, 1);
163  EXPECT_EQ(1, value);
164  EXPECT_EQ(0, prev);
165
166  // Use test value that has non-zero bits in both halves, more for testing
167  // 64-bit implementation on 32-bit platforms.
168  const AtomicType k_test_val = (GG_ULONGLONG(1) <<
169                                 (NUM_BITS(AtomicType) - 2)) + 11;
170  value = k_test_val;
171  prev = base::subtle::NoBarrier_CompareAndSwap(&value, 0, 5);
172  EXPECT_EQ(k_test_val, value);
173  EXPECT_EQ(k_test_val, prev);
174
175  value = k_test_val;
176  prev = base::subtle::NoBarrier_CompareAndSwap(&value, k_test_val, 5);
177  EXPECT_EQ(5, value);
178  EXPECT_EQ(k_test_val, prev);
179}
180
181
182template <class AtomicType>
183static void TestAtomicExchange() {
184  AtomicType value = 0;
185  AtomicType new_value = base::subtle::NoBarrier_AtomicExchange(&value, 1);
186  EXPECT_EQ(1, value);
187  EXPECT_EQ(0, new_value);
188
189  // Use test value that has non-zero bits in both halves, more for testing
190  // 64-bit implementation on 32-bit platforms.
191  const AtomicType k_test_val = (GG_ULONGLONG(1) <<
192                                 (NUM_BITS(AtomicType) - 2)) + 11;
193  value = k_test_val;
194  new_value = base::subtle::NoBarrier_AtomicExchange(&value, k_test_val);
195  EXPECT_EQ(k_test_val, value);
196  EXPECT_EQ(k_test_val, new_value);
197
198  value = k_test_val;
199  new_value = base::subtle::NoBarrier_AtomicExchange(&value, 5);
200  EXPECT_EQ(5, value);
201  EXPECT_EQ(k_test_val, new_value);
202}
203
204
205template <class AtomicType>
206static void TestAtomicIncrementBounds() {
207  // Test increment at the half-width boundary of the atomic type.
208  // It is primarily for testing at the 32-bit boundary for 64-bit atomic type.
209  AtomicType test_val = GG_ULONGLONG(1) << (NUM_BITS(AtomicType) / 2);
210  AtomicType value = test_val - 1;
211  AtomicType new_value = base::subtle::NoBarrier_AtomicIncrement(&value, 1);
212  EXPECT_EQ(test_val, value);
213  EXPECT_EQ(value, new_value);
214
215  base::subtle::NoBarrier_AtomicIncrement(&value, -1);
216  EXPECT_EQ(test_val - 1, value);
217}
218
219// This is a simple sanity check that values are correct. Not testing
220// atomicity
221template <class AtomicType>
222static void TestStore() {
223  const AtomicType kVal1 = static_cast<AtomicType>(0xa5a5a5a5a5a5a5a5LL);
224  const AtomicType kVal2 = static_cast<AtomicType>(-1);
225
226  AtomicType value;
227
228  base::subtle::NoBarrier_Store(&value, kVal1);
229  EXPECT_EQ(kVal1, value);
230  base::subtle::NoBarrier_Store(&value, kVal2);
231  EXPECT_EQ(kVal2, value);
232
233  base::subtle::Acquire_Store(&value, kVal1);
234  EXPECT_EQ(kVal1, value);
235  base::subtle::Acquire_Store(&value, kVal2);
236  EXPECT_EQ(kVal2, value);
237
238  base::subtle::Release_Store(&value, kVal1);
239  EXPECT_EQ(kVal1, value);
240  base::subtle::Release_Store(&value, kVal2);
241  EXPECT_EQ(kVal2, value);
242}
243
244// This is a simple sanity check that values are correct. Not testing
245// atomicity
246template <class AtomicType>
247static void TestLoad() {
248  const AtomicType kVal1 = static_cast<AtomicType>(0xa5a5a5a5a5a5a5a5LL);
249  const AtomicType kVal2 = static_cast<AtomicType>(-1);
250
251  AtomicType value;
252
253  value = kVal1;
254  EXPECT_EQ(kVal1, base::subtle::NoBarrier_Load(&value));
255  value = kVal2;
256  EXPECT_EQ(kVal2, base::subtle::NoBarrier_Load(&value));
257
258  value = kVal1;
259  EXPECT_EQ(kVal1, base::subtle::Acquire_Load(&value));
260  value = kVal2;
261  EXPECT_EQ(kVal2, base::subtle::Acquire_Load(&value));
262
263  value = kVal1;
264  EXPECT_EQ(kVal1, base::subtle::Release_Load(&value));
265  value = kVal2;
266  EXPECT_EQ(kVal2, base::subtle::Release_Load(&value));
267}
268
269template <class AtomicType>
270static void TestAtomicOps() {
271  TestCompareAndSwap<AtomicType>();
272  TestAtomicExchange<AtomicType>();
273  TestAtomicIncrementBounds<AtomicType>();
274  TestStore<AtomicType>();
275  TestLoad<AtomicType>();
276}
277
278static void TestCalloc(size_t n, size_t s, bool ok) {
279  char* p = reinterpret_cast<char*>(calloc(n, s));
280  if (!ok) {
281    EXPECT_EQ(NULL, p) << "calloc(n, s) should not succeed";
282  } else {
283    EXPECT_NE(reinterpret_cast<void*>(NULL), p) <<
284        "calloc(n, s) should succeed";
285    for (int i = 0; i < n*s; i++) {
286      EXPECT_EQ('\0', p[i]);
287    }
288    free(p);
289  }
290}
291
292
293// A global test counter for number of times the NewHandler is called.
294static int news_handled = 0;
295static void TestNewHandler() {
296  ++news_handled;
297  throw std::bad_alloc();
298}
299
300// Because we compile without exceptions, we expect these will not throw.
301static void TestOneNewWithoutExceptions(void* (*func)(size_t),
302                                        bool should_throw) {
303  // success test
304  try {
305    void* ptr = (*func)(kNotTooBig);
306    EXPECT_NE(reinterpret_cast<void*>(NULL), ptr) <<
307        "allocation should not have failed.";
308  } catch(...) {
309    EXPECT_EQ(0, 1) << "allocation threw unexpected exception.";
310  }
311
312  // failure test
313  try {
314    void* rv = (*func)(kTooBig);
315    EXPECT_EQ(NULL, rv);
316    EXPECT_EQ(false, should_throw) << "allocation should have thrown.";
317  } catch(...) {
318    EXPECT_EQ(true, should_throw) << "allocation threw unexpected exception.";
319  }
320}
321
322static void TestNothrowNew(void* (*func)(size_t)) {
323  news_handled = 0;
324
325  // test without new_handler:
326  std::new_handler saved_handler = std::set_new_handler(0);
327  TestOneNewWithoutExceptions(func, false);
328
329  // test with new_handler:
330  std::set_new_handler(TestNewHandler);
331  TestOneNewWithoutExceptions(func, true);
332  EXPECT_EQ(news_handled, 1) << "nothrow new_handler was not called.";
333  std::set_new_handler(saved_handler);
334}
335
336}  // namespace
337
338//-----------------------------------------------------------------------------
339
340TEST(Atomics, AtomicIncrementWord) {
341  TestAtomicIncrement<AtomicWord>();
342}
343
344TEST(Atomics, AtomicIncrement32) {
345  TestAtomicIncrement<Atomic32>();
346}
347
348TEST(Atomics, AtomicOpsWord) {
349  TestAtomicIncrement<AtomicWord>();
350}
351
352TEST(Atomics, AtomicOps32) {
353  TestAtomicIncrement<Atomic32>();
354}
355
356TEST(Allocators, Malloc) {
357  // Try allocating data with a bunch of alignments and sizes
358  for (int size = 1; size < 1048576; size *= 2) {
359    unsigned char* ptr = reinterpret_cast<unsigned char*>(malloc(size));
360    CheckAlignment(ptr, 2);  // Should be 2 byte aligned
361    Fill(ptr, size);
362    EXPECT_EQ(true, Valid(ptr, size));
363    free(ptr);
364  }
365}
366
367TEST(Allocators, Calloc) {
368  TestCalloc(0, 0, true);
369  TestCalloc(0, 1, true);
370  TestCalloc(1, 1, true);
371  TestCalloc(1<<10, 0, true);
372  TestCalloc(1<<20, 0, true);
373  TestCalloc(0, 1<<10, true);
374  TestCalloc(0, 1<<20, true);
375  TestCalloc(1<<20, 2, true);
376  TestCalloc(2, 1<<20, true);
377  TestCalloc(1000, 1000, true);
378
379  TestCalloc(kMaxSize, 2, false);
380  TestCalloc(2, kMaxSize, false);
381  TestCalloc(kMaxSize, kMaxSize, false);
382
383  TestCalloc(kMaxSignedSize, 3, false);
384  TestCalloc(3, kMaxSignedSize, false);
385  TestCalloc(kMaxSignedSize, kMaxSignedSize, false);
386}
387
388TEST(Allocators, New) {
389  TestNothrowNew(&::operator new);
390  TestNothrowNew(&::operator new[]);
391}
392
393// This makes sure that reallocing a small number of bytes in either
394// direction doesn't cause us to allocate new memory.
395TEST(Allocators, Realloc1) {
396  int start_sizes[] = { 100, 1000, 10000, 100000 };
397  int deltas[] = { 1, -2, 4, -8, 16, -32, 64, -128 };
398
399  for (int s = 0; s < sizeof(start_sizes)/sizeof(*start_sizes); ++s) {
400    void* p = malloc(start_sizes[s]);
401    CHECK(p);
402    // The larger the start-size, the larger the non-reallocing delta.
403    for (int d = 0; d < s*2; ++d) {
404      void* new_p = realloc(p, start_sizes[s] + deltas[d]);
405      CHECK(p == new_p);  // realloc should not allocate new memory
406    }
407    // Test again, but this time reallocing smaller first.
408    for (int d = 0; d < s*2; ++d) {
409      void* new_p = realloc(p, start_sizes[s] - deltas[d]);
410      CHECK(p == new_p);  // realloc should not allocate new memory
411    }
412    free(p);
413  }
414}
415
416TEST(Allocators, Realloc2) {
417  for (int src_size = 0; src_size >= 0; src_size = NextSize(src_size)) {
418    for (int dst_size = 0; dst_size >= 0; dst_size = NextSize(dst_size)) {
419      unsigned char* src = reinterpret_cast<unsigned char*>(malloc(src_size));
420      Fill(src, src_size);
421      unsigned char* dst =
422          reinterpret_cast<unsigned char*>(realloc(src, dst_size));
423      EXPECT_EQ(true, Valid(dst, min(src_size, dst_size)));
424      Fill(dst, dst_size);
425      EXPECT_EQ(true, Valid(dst, dst_size));
426      if (dst != NULL) free(dst);
427    }
428  }
429
430  // Now make sure realloc works correctly even when we overflow the
431  // packed cache, so some entries are evicted from the cache.
432  // The cache has 2^12 entries, keyed by page number.
433  const int kNumEntries = 1 << 14;
434  int** p = reinterpret_cast<int**>(malloc(sizeof(*p) * kNumEntries));
435  int sum = 0;
436  for (int i = 0; i < kNumEntries; i++) {
437    // no page size is likely to be bigger than 8192?
438    p[i] = reinterpret_cast<int*>(malloc(8192));
439    p[i][1000] = i;              // use memory deep in the heart of p
440  }
441  for (int i = 0; i < kNumEntries; i++) {
442    p[i] = reinterpret_cast<int*>(realloc(p[i], 9000));
443  }
444  for (int i = 0; i < kNumEntries; i++) {
445    sum += p[i][1000];
446    free(p[i]);
447  }
448  EXPECT_EQ(kNumEntries/2 * (kNumEntries - 1), sum);  // assume kNE is even
449  free(p);
450}
451
452TEST(Allocators, ReallocZero) {
453  // Test that realloc to zero does not return NULL.
454  for (int size = 0; size >= 0; size = NextSize(size)) {
455    char* ptr = reinterpret_cast<char*>(malloc(size));
456    EXPECT_NE(static_cast<char*>(NULL), ptr);
457    ptr = reinterpret_cast<char*>(realloc(ptr, 0));
458    EXPECT_NE(static_cast<char*>(NULL), ptr);
459    if (ptr)
460      free(ptr);
461  }
462}
463
464#ifdef WIN32
465// Test recalloc
466TEST(Allocators, Recalloc) {
467  for (int src_size = 0; src_size >= 0; src_size = NextSize(src_size)) {
468    for (int dst_size = 0; dst_size >= 0; dst_size = NextSize(dst_size)) {
469      unsigned char* src =
470          reinterpret_cast<unsigned char*>(_recalloc(NULL, 1, src_size));
471      EXPECT_EQ(true, IsZeroed(src, src_size));
472      Fill(src, src_size);
473      unsigned char* dst =
474          reinterpret_cast<unsigned char*>(_recalloc(src, 1, dst_size));
475      EXPECT_EQ(true, Valid(dst, min(src_size, dst_size)));
476      Fill(dst, dst_size);
477      EXPECT_EQ(true, Valid(dst, dst_size));
478      if (dst != NULL)
479        free(dst);
480    }
481  }
482}
483#endif
484
485
486int main(int argc, char** argv) {
487  testing::InitGoogleTest(&argc, argv);
488  return RUN_ALL_TESTS();
489}
490
491