| // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 | #include <stddef.h> | 
 | #include <stdio.h> | 
 |  | 
 | #include "testing/gtest/include/gtest/gtest.h" | 
 |  | 
 | // TCMalloc header files. | 
 | #include "common.h"  // For TCMalloc constants like page size, etc. | 
 |  | 
 | // TCMalloc implementation. | 
 | #include "debugallocation_shim.cc" | 
 |  | 
 | namespace { | 
 |  | 
 | void* TCMallocDoMallocForTest(size_t size) { | 
 |   return do_malloc(size); | 
 | } | 
 |  | 
 | void TCMallocDoFreeForTest(void* ptr) { | 
 |   do_free(ptr); | 
 | } | 
 |  | 
 | size_t ExcludeSpaceForMarkForTest(size_t size) { | 
 |   return ExcludeSpaceForMark(size); | 
 | } | 
 |  | 
 | }  // namespace | 
 |  | 
 | TEST(TCMallocFreeCheck, BadPointerInFirstPageOfTheLargeObject) { | 
 |   char* p = reinterpret_cast<char*>( | 
 |       TCMallocDoMallocForTest(ExcludeSpaceForMarkForTest(kMaxSize + 1))); | 
 |   for (int offset = 1; offset < kPageSize ; offset <<= 1) { | 
 |     ASSERT_DEATH(TCMallocDoFreeForTest(p + offset), | 
 |                  "Pointer is not pointing to the start of a span"); | 
 |   } | 
 | } | 
 |  | 
 | TEST(TCMallocFreeCheck, BadPageAlignedPointerInsideLargeObject) { | 
 |   char* p = reinterpret_cast<char*>( | 
 |       TCMallocDoMallocForTest(ExcludeSpaceForMarkForTest(kMaxSize + 1))); | 
 |  | 
 |   for (int offset = kPageSize; offset < kMaxSize; offset += kPageSize) { | 
 |     // Only the first and last page of a span are in heap map. So for others | 
 |     // tcmalloc will give a general error of invalid pointer. | 
 |     ASSERT_DEATH(TCMallocDoFreeForTest(p + offset), | 
 |                  "Attempt to free invalid pointer"); | 
 |   } | 
 |   ASSERT_DEATH(TCMallocDoFreeForTest(p + kMaxSize), | 
 |                "Pointer is not pointing to the start of a span"); | 
 | } | 
 |  | 
 | TEST(TCMallocFreeCheck, DoubleFreeLargeObject) { | 
 |   char* p = reinterpret_cast<char*>( | 
 |       TCMallocDoMallocForTest(ExcludeSpaceForMarkForTest(kMaxSize + 1))); | 
 |   ASSERT_DEATH(TCMallocDoFreeForTest(p); TCMallocDoFreeForTest(p), | 
 |                "Object was not in-use"); | 
 | } | 
 |  | 
 |  | 
 | #ifdef NDEBUG | 
 | TEST(TCMallocFreeCheck, DoubleFreeSmallObject) { | 
 |   for (size_t size = 1; | 
 |        size <= ExcludeSpaceForMarkForTest(kMaxSize); | 
 |        size <<= 1) { | 
 |     char* p = reinterpret_cast<char*>(TCMallocDoMallocForTest(size)); | 
 |     ASSERT_DEATH(TCMallocDoFreeForTest(p); TCMallocDoFreeForTest(p), | 
 |                  "Circular loop in list detected"); | 
 |   } | 
 | } | 
 | #else | 
 | TEST(TCMallocFreeCheck, DoubleFreeSmallObject) { | 
 |   size_t size = 1; | 
 |  | 
 |   // When the object is small, tcmalloc validation can not distinguish normal | 
 |   // memory corruption or double free, because there's not enough space in | 
 |   // freed objects to keep the mark. | 
 |   for (; size <= ExcludeSpaceForMarkForTest(kMinClassSize); size <<= 1) { | 
 |     char* p = reinterpret_cast<char*>(TCMallocDoMallocForTest(size)); | 
 |     ASSERT_DEATH(TCMallocDoFreeForTest(p); TCMallocDoFreeForTest(p), | 
 |                  "Memory corrupted"); | 
 |   } | 
 |  | 
 |   for (; size <= ExcludeSpaceForMarkForTest(kMaxSize); size <<= 1) { | 
 |     char* p = reinterpret_cast<char*>(TCMallocDoMallocForTest(size)); | 
 |     ASSERT_DEATH(TCMallocDoFreeForTest(p); TCMallocDoFreeForTest(p), | 
 |                  "Attempt to double free"); | 
 |   } | 
 | } | 
 | #endif | 
 |  | 
 | int main(int argc, char **argv) { | 
 |   testing::InitGoogleTest(&argc, argv); | 
 |   return RUN_ALL_TESTS(); | 
 | } |