| Index: base/security_unittest.cc
|
| diff --git a/base/security_unittest.cc b/base/security_unittest.cc
|
| index d786273c023aa1fbdf33c834f718d07eab057656..a7e3bc4bd6e72e95097fa198702337a7664fc7ac 100644
|
| --- a/base/security_unittest.cc
|
| +++ b/base/security_unittest.cc
|
| @@ -23,11 +23,46 @@
|
| #include <unistd.h>
|
| #endif
|
|
|
| +#if defined(OS_WIN)
|
| +#include <new.h>
|
| +#endif
|
| +
|
| using std::nothrow;
|
| using std::numeric_limits;
|
|
|
| namespace {
|
|
|
| +#if defined(OS_WIN)
|
| +// This is a permitted size but exhausts memory pretty quickly.
|
| +const size_t kLargePermittedAllocation = 0x7FFFE000;
|
| +
|
| +int OnNoMemory(size_t) {
|
| + _exit(1);
|
| +}
|
| +
|
| +void ExhaustMemoryWithMalloc() {
|
| + for (;;) {
|
| + void* buf = malloc(kLargePermittedAllocation);
|
| + if (!buf)
|
| + break;
|
| + }
|
| +}
|
| +
|
| +void ExhaustMemoryWithRealloc() {
|
| + size_t size = kLargePermittedAllocation;
|
| + void* buf = malloc(size);
|
| + if (!buf)
|
| + return;
|
| + for (;;) {
|
| + size += kLargePermittedAllocation;
|
| + void* new_buf = realloc(buf, size);
|
| + if (!buf)
|
| + break;
|
| + buf = new_buf;
|
| + }
|
| +}
|
| +#endif
|
| +
|
| // This function acts as a compiler optimization barrier. We use it to
|
| // prevent the compiler from making an expression a compile-time constant.
|
| // We also use it so that the compiler doesn't discard certain return values
|
| @@ -42,15 +77,18 @@ Type HideValueFromCompiler(volatile Type value) {
|
| return value;
|
| }
|
|
|
| +// Tcmalloc and Windows allocator shim support setting malloc limits.
|
| // - NO_TCMALLOC (should be defined if compiled with use_allocator!="tcmalloc")
|
| // - ADDRESS_SANITIZER and SYZYASAN because they have their own memory allocator
|
| // - IOS does not use tcmalloc
|
| // - OS_MACOSX does not use tcmalloc
|
| -#if !defined(NO_TCMALLOC) && !defined(ADDRESS_SANITIZER) && \
|
| - !defined(OS_IOS) && !defined(OS_MACOSX) && !defined(SYZYASAN)
|
| - #define TCMALLOC_TEST(function) function
|
| +// - Windows allocator shim defines ALLOCATOR_SHIM
|
| +#if (!defined(NO_TCMALLOC) || defined(ALLOCATOR_SHIM)) && \
|
| + !defined(ADDRESS_SANITIZER) && !defined(OS_IOS) && !defined(OS_MACOSX) && \
|
| + !defined(SYZYASAN)
|
| +#define MALLOC_OVERFLOW_TEST(function) function
|
| #else
|
| - #define TCMALLOC_TEST(function) DISABLED_##function
|
| +#define MALLOC_OVERFLOW_TEST(function) DISABLED_##function
|
| #endif
|
|
|
| // TODO(jln): switch to std::numeric_limits<int>::max() when we switch to
|
| @@ -64,12 +102,6 @@ bool IsTcMallocBypassed() {
|
| char* g_slice = getenv("G_SLICE");
|
| if (g_slice && !strcmp(g_slice, "always-malloc"))
|
| return true;
|
| -#elif defined(OS_WIN)
|
| - // This should detect a TCMalloc bypass from setting
|
| - // the CHROME_ALLOCATOR environment variable.
|
| - char* allocator = getenv("CHROME_ALLOCATOR");
|
| - if (allocator && strcmp(allocator, "tcmalloc"))
|
| - return true;
|
| #endif
|
| return false;
|
| }
|
| @@ -89,7 +121,7 @@ bool CallocDiesOnOOM() {
|
| }
|
|
|
| // Fake test that allow to know the state of TCMalloc by looking at bots.
|
| -TEST(SecurityTest, TCMALLOC_TEST(IsTCMallocDynamicallyBypassed)) {
|
| +TEST(SecurityTest, MALLOC_OVERFLOW_TEST(IsTCMallocDynamicallyBypassed)) {
|
| printf("Malloc is dynamically bypassed: %s\n",
|
| IsTcMallocBypassed() ? "yes." : "no.");
|
| }
|
| @@ -99,7 +131,7 @@ TEST(SecurityTest, TCMALLOC_TEST(IsTCMallocDynamicallyBypassed)) {
|
| // vulnerabilities in libraries that use int instead of size_t. See
|
| // crbug.com/169327.
|
|
|
| -TEST(SecurityTest, TCMALLOC_TEST(MemoryAllocationRestrictionsMalloc)) {
|
| +TEST(SecurityTest, MALLOC_OVERFLOW_TEST(MemoryAllocationRestrictionsMalloc)) {
|
| if (!IsTcMallocBypassed()) {
|
| scoped_ptr<char, base::FreeDeleter> ptr(static_cast<char*>(
|
| HideValueFromCompiler(malloc(kTooBigAllocSize))));
|
| @@ -107,7 +139,43 @@ TEST(SecurityTest, TCMALLOC_TEST(MemoryAllocationRestrictionsMalloc)) {
|
| }
|
| }
|
|
|
| -TEST(SecurityTest, TCMALLOC_TEST(MemoryAllocationRestrictionsCalloc)) {
|
| +#if defined(GTEST_HAS_DEATH_TEST) && defined(OS_WIN)
|
| +TEST(SecurityTest, MALLOC_OVERFLOW_TEST(MemoryAllocationMallocDeathTest)) {
|
| + _set_new_handler(&OnNoMemory);
|
| + _set_new_mode(1);
|
| + {
|
| + scoped_ptr<char, base::FreeDeleter> ptr;
|
| + EXPECT_DEATH(ptr.reset(static_cast<char*>(
|
| + HideValueFromCompiler(malloc(kTooBigAllocSize)))),
|
| + "");
|
| + ASSERT_TRUE(!ptr);
|
| + }
|
| + _set_new_handler(NULL);
|
| + _set_new_mode(0);
|
| +}
|
| +
|
| +TEST(SecurityTest, MALLOC_OVERFLOW_TEST(MemoryAllocationExhaustDeathTest)) {
|
| + _set_new_handler(&OnNoMemory);
|
| + _set_new_mode(1);
|
| + {
|
| + ASSERT_DEATH(ExhaustMemoryWithMalloc(), "");
|
| + }
|
| + _set_new_handler(NULL);
|
| + _set_new_mode(0);
|
| +}
|
| +
|
| +TEST(SecurityTest, MALLOC_OVERFLOW_TEST(MemoryReallocationExhaustDeathTest)) {
|
| + _set_new_handler(&OnNoMemory);
|
| + _set_new_mode(1);
|
| + {
|
| + ASSERT_DEATH(ExhaustMemoryWithRealloc(), "");
|
| + }
|
| + _set_new_handler(NULL);
|
| + _set_new_mode(0);
|
| +}
|
| +#endif
|
| +
|
| +TEST(SecurityTest, MALLOC_OVERFLOW_TEST(MemoryAllocationRestrictionsCalloc)) {
|
| if (!IsTcMallocBypassed()) {
|
| scoped_ptr<char, base::FreeDeleter> ptr(static_cast<char*>(
|
| HideValueFromCompiler(calloc(kTooBigAllocSize, 1))));
|
| @@ -115,7 +183,7 @@ TEST(SecurityTest, TCMALLOC_TEST(MemoryAllocationRestrictionsCalloc)) {
|
| }
|
| }
|
|
|
| -TEST(SecurityTest, TCMALLOC_TEST(MemoryAllocationRestrictionsRealloc)) {
|
| +TEST(SecurityTest, MALLOC_OVERFLOW_TEST(MemoryAllocationRestrictionsRealloc)) {
|
| if (!IsTcMallocBypassed()) {
|
| char* orig_ptr = static_cast<char*>(malloc(1));
|
| ASSERT_TRUE(orig_ptr);
|
| @@ -131,7 +199,7 @@ typedef struct {
|
| char large_array[kTooBigAllocSize];
|
| } VeryLargeStruct;
|
|
|
| -TEST(SecurityTest, TCMALLOC_TEST(MemoryAllocationRestrictionsNew)) {
|
| +TEST(SecurityTest, MALLOC_OVERFLOW_TEST(MemoryAllocationRestrictionsNew)) {
|
| if (!IsTcMallocBypassed()) {
|
| scoped_ptr<VeryLargeStruct> ptr(
|
| HideValueFromCompiler(new (nothrow) VeryLargeStruct));
|
| @@ -139,7 +207,20 @@ TEST(SecurityTest, TCMALLOC_TEST(MemoryAllocationRestrictionsNew)) {
|
| }
|
| }
|
|
|
| -TEST(SecurityTest, TCMALLOC_TEST(MemoryAllocationRestrictionsNewArray)) {
|
| +#if defined(GTEST_HAS_DEATH_TEST) && defined(OS_WIN)
|
| +TEST(SecurityTest, MALLOC_OVERFLOW_TEST(MemoryAllocationNewDeathTest)) {
|
| + _set_new_handler(&OnNoMemory);
|
| + {
|
| + scoped_ptr<VeryLargeStruct> ptr;
|
| + EXPECT_DEATH(
|
| + ptr.reset(HideValueFromCompiler(new (nothrow) VeryLargeStruct)), "");
|
| + ASSERT_TRUE(!ptr);
|
| + }
|
| + _set_new_handler(NULL);
|
| +}
|
| +#endif
|
| +
|
| +TEST(SecurityTest, MALLOC_OVERFLOW_TEST(MemoryAllocationRestrictionsNewArray)) {
|
| if (!IsTcMallocBypassed()) {
|
| scoped_ptr<char[]> ptr(
|
| HideValueFromCompiler(new (nothrow) char[kTooBigAllocSize]));
|
| @@ -242,7 +323,7 @@ bool ArePointersToSameArea(void* ptr1, void* ptr2, size_t size) {
|
| }
|
|
|
| // Check if TCMalloc uses an underlying random memory allocator.
|
| -TEST(SecurityTest, TCMALLOC_TEST(RandomMemoryAllocations)) {
|
| +TEST(SecurityTest, MALLOC_OVERFLOW_TEST(RandomMemoryAllocations)) {
|
| if (IsTcMallocBypassed())
|
| return;
|
| size_t kPageSize = 4096; // We support x86_64 only.
|
|
|