Index: base/security_unittest.cc |
diff --git a/base/security_unittest.cc b/base/security_unittest.cc |
index 59a3ddd6ca51bc00452c98cc426436ec167050aa..14540032f9dbf425ffb0d8ef57ce1a5d0beabc4a 100644 |
--- a/base/security_unittest.cc |
+++ b/base/security_unittest.cc |
@@ -37,20 +37,15 @@ Type HideValueFromCompiler(volatile Type value) { |
return value; |
} |
-// Check that we can not allocate a memory range that cannot be indexed |
-// via an int. This is used to mitigate vulnerabilities in libraries that use |
-// int instead of size_t. |
-// See crbug.com/169327. |
- |
-// - NO_TCMALLOC because we only patched tcmalloc |
+// - NO_TCMALLOC (should be defined if we compile with linux_use_tcmalloc=0) |
// - ADDRESS_SANITIZER because it has its own memory allocator |
-// - IOS does not seem to honor nothrow in new properly |
+// - IOS does not use tcmalloc |
// - OS_MACOSX does not use tcmalloc |
#if !defined(NO_TCMALLOC) && !defined(ADDRESS_SANITIZER) && \ |
!defined(OS_IOS) && !defined(OS_MACOSX) |
- #define ALLOC_TEST(function) function |
+ #define TCMALLOC_TEST(function) function |
#else |
- #define ALLOC_TEST(function) DISABLED_##function |
+ #define TCMALLOC_TEST(function) DISABLED_##function |
#endif |
// TODO(jln): switch to std::numeric_limits<int>::max() when we switch to |
@@ -68,13 +63,28 @@ bool IsTcMallocBypassed() { |
return false; |
} |
+bool CallocDiesOnOOM() { |
+// The wrapper function in base/process_util_linux.cc that is used when we |
+// compile without TCMalloc will just die on OOM instead of returning NULL. |
+#if defined(OS_LINUX) && defined(NO_TCMALLOC) |
+ return true; |
+#else |
+ return false; |
+#endif |
+} |
+ |
// Fake test that allow to know the state of TCMalloc by looking at bots. |
-TEST(SecurityTest, ALLOC_TEST(IsTCMallocDynamicallyBypassed)) { |
+TEST(SecurityTest, TCMALLOC_TEST(IsTCMallocDynamicallyBypassed)) { |
printf("Malloc is dynamically bypassed: %s\n", |
IsTcMallocBypassed() ? "yes." : "no."); |
} |
-TEST(SecurityTest, ALLOC_TEST(MemoryAllocationRestrictionsMalloc)) { |
+// The MemoryAllocationRestrictions* tests test that we can not allocate a |
+// memory range that cannot be indexed via an int. This is used to mitigate |
+// vulnerabilities in libraries that use int instead of size_t. See |
+// crbug.com/169327. |
+ |
+TEST(SecurityTest, TCMALLOC_TEST(MemoryAllocationRestrictionsMalloc)) { |
if (!IsTcMallocBypassed()) { |
scoped_ptr<char, base::FreeDeleter> ptr(static_cast<char*>( |
HideValueFromCompiler(malloc(kTooBigAllocSize)))); |
@@ -82,7 +92,7 @@ TEST(SecurityTest, ALLOC_TEST(MemoryAllocationRestrictionsMalloc)) { |
} |
} |
-TEST(SecurityTest, ALLOC_TEST(MemoryAllocationRestrictionsCalloc)) { |
+TEST(SecurityTest, TCMALLOC_TEST(MemoryAllocationRestrictionsCalloc)) { |
if (!IsTcMallocBypassed()) { |
scoped_ptr<char, base::FreeDeleter> ptr(static_cast<char*>( |
HideValueFromCompiler(calloc(kTooBigAllocSize, 1)))); |
@@ -90,7 +100,7 @@ TEST(SecurityTest, ALLOC_TEST(MemoryAllocationRestrictionsCalloc)) { |
} |
} |
-TEST(SecurityTest, ALLOC_TEST(MemoryAllocationRestrictionsRealloc)) { |
+TEST(SecurityTest, TCMALLOC_TEST(MemoryAllocationRestrictionsRealloc)) { |
if (!IsTcMallocBypassed()) { |
char* orig_ptr = static_cast<char*>(malloc(1)); |
ASSERT_TRUE(orig_ptr); |
@@ -106,7 +116,7 @@ typedef struct { |
char large_array[kTooBigAllocSize]; |
} VeryLargeStruct; |
-TEST(SecurityTest, ALLOC_TEST(MemoryAllocationRestrictionsNew)) { |
+TEST(SecurityTest, TCMALLOC_TEST(MemoryAllocationRestrictionsNew)) { |
if (!IsTcMallocBypassed()) { |
scoped_ptr<VeryLargeStruct> ptr( |
HideValueFromCompiler(new (nothrow) VeryLargeStruct)); |
@@ -114,7 +124,7 @@ TEST(SecurityTest, ALLOC_TEST(MemoryAllocationRestrictionsNew)) { |
} |
} |
-TEST(SecurityTest, ALLOC_TEST(MemoryAllocationRestrictionsNewArray)) { |
+TEST(SecurityTest, TCMALLOC_TEST(MemoryAllocationRestrictionsNewArray)) { |
if (!IsTcMallocBypassed()) { |
scoped_ptr<char[]> ptr( |
HideValueFromCompiler(new (nothrow) char[kTooBigAllocSize])); |
@@ -184,27 +194,32 @@ TEST(SecurityTest, DISABLE_ON_IOS_AND_WIN(NewOverflow)) { |
} |
#endif |
+// Call calloc(), eventually free the memory and return whether or not |
+// calloc() did succeed. |
+bool CallocReturnsNull(size_t nmemb, size_t size) { |
+ scoped_ptr<char, base::FreeDeleter> array_pointer( |
+ static_cast<char*>(calloc(nmemb, size))); |
+ // We need the call to HideValueFromCompiler(): we have seen LLVM |
+ // optimize away the call to calloc() entirely and assume |
+ // the pointer to not be NULL. |
+ return HideValueFromCompiler(array_pointer.get()) == NULL; |
+} |
+ |
// Test if calloc() can overflow. Disable on ASAN for now since the |
-// overflow seems present there. |
+// overflow seems present there (crbug.com/175554). |
TEST(SecurityTest, DISABLE_ON_ASAN(CallocOverflow)) { |
const size_t kArraySize = 4096; |
const size_t kMaxSizeT = numeric_limits<size_t>::max(); |
const size_t kArraySize2 = kMaxSizeT / kArraySize + 10; |
- { |
- scoped_ptr<char> array_pointer( |
- static_cast<char*>(calloc(kArraySize, kArraySize2))); |
- // We need the call to HideValueFromCompiler(): we have seen LLVM |
- // optimize away the call to calloc() entirely and assume |
- // the pointer to not be NULL. |
- EXPECT_TRUE(HideValueFromCompiler(array_pointer.get()) == NULL); |
- } |
- { |
- scoped_ptr<char> array_pointer( |
- static_cast<char*>(calloc(kArraySize2, kArraySize))); |
- // We need the call to HideValueFromCompiler(): we have seen LLVM |
- // optimize away the call to calloc() entirely and assume |
- // the pointer to not be NULL. |
- EXPECT_TRUE(HideValueFromCompiler(array_pointer.get()) == NULL); |
+ if (!CallocDiesOnOOM()) { |
+ EXPECT_TRUE(CallocReturnsNull(kArraySize, kArraySize2)); |
+ EXPECT_TRUE(CallocReturnsNull(kArraySize2, kArraySize)); |
+ } else { |
+ // It's also ok for calloc to just terminate the process. |
+#if defined(GTEST_HAS_DEATH_TEST) |
+ EXPECT_DEATH(CallocReturnsNull(kArraySize, kArraySize2), ""); |
+ EXPECT_DEATH(CallocReturnsNull(kArraySize2, kArraySize), ""); |
+#endif // GTEST_HAS_DEATH_TEST |
} |
} |
@@ -230,7 +245,7 @@ bool ArePointersToSameArea(void* ptr1, void* ptr2, size_t size) { |
} |
// Check if TCMalloc uses an underlying random memory allocator. |
-TEST(SecurityTest, ALLOC_TEST(RandomMemoryAllocations)) { |
+TEST(SecurityTest, TCMALLOC_TEST(RandomMemoryAllocations)) { |
if (IsTcMallocBypassed()) |
return; |
size_t kPageSize = 4096; // We support x86_64 only. |