summaryrefslogtreecommitdiffstats
path: root/base
diff options
context:
space:
mode:
authoravi@chromium.org <avi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-05-19 20:23:46 +0000
committeravi@chromium.org <avi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-05-19 20:23:46 +0000
commita1a82d5215198f9ed128f6fc0b1f14cdf3034867 (patch)
tree26e6d481fbcd1c45e1c58b50065dd7fb9c75eeb1 /base
parentde72a9ee38aff40738a6d46587760236d959c4f1 (diff)
downloadchromium_src-a1a82d5215198f9ed128f6fc0b1f14cdf3034867.zip
chromium_src-a1a82d5215198f9ed128f6fc0b1f14cdf3034867.tar.gz
chromium_src-a1a82d5215198f9ed128f6fc0b1f14cdf3034867.tar.bz2
Patch out posix_memalign in the out-of-memory killer.
BUG=http://crbug.com/44189 TEST=included in base_unittests Review URL: http://codereview.chromium.org/2110010 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@47714 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base')
-rw-r--r--base/process_util_mac.mm87
-rw-r--r--base/process_util_unittest.cc26
2 files changed, 97 insertions, 16 deletions
diff --git a/base/process_util_mac.mm b/base/process_util_mac.mm
index 602be56..136e650 100644
--- a/base/process_util_mac.mm
+++ b/base/process_util_mac.mm
@@ -357,7 +357,33 @@ namespace {
bool g_oom_killer_enabled;
-// === C malloc/calloc/valloc/realloc ===
+// === C malloc/calloc/valloc/realloc/posix_memalign ===
+
+// The extended version of malloc_zone_t from the 10.6 SDK's <malloc/malloc.h>,
+// included here to allow for compilation in 10.5. (10.5 has version 3 zone
+// allocators, while 10.6 has version 6 allocators.)
+struct ChromeMallocZone {
+ void* reserved1;
+ void* reserved2;
+ size_t (*size)(struct _malloc_zone_t* zone, const void* ptr);
+ void* (*malloc)(struct _malloc_zone_t* zone, size_t size);
+ void* (*calloc)(struct _malloc_zone_t* zone, size_t num_items, size_t size);
+ void* (*valloc)(struct _malloc_zone_t* zone, size_t size);
+ void (*free)(struct _malloc_zone_t* zone, void* ptr);
+ void* (*realloc)(struct _malloc_zone_t* zone, void* ptr, size_t size);
+ void (*destroy)(struct _malloc_zone_t* zone);
+ const char* zone_name;
+ unsigned (*batch_malloc)(struct _malloc_zone_t* zone, size_t size,
+ void** results, unsigned num_requested);
+ void (*batch_free)(struct _malloc_zone_t* zone, void** to_be_freed,
+ unsigned num_to_be_freed);
+ struct malloc_introspection_t* introspect;
+ unsigned version;
+ void* (*memalign)(struct _malloc_zone_t* zone, size_t alignment,
+ size_t size); // version >= 5
+ void (*free_definite_size)(struct _malloc_zone_t* zone, void* ptr,
+ size_t size); // version >= 6
+};
typedef void* (*malloc_type)(struct _malloc_zone_t* zone,
size_t size);
@@ -369,16 +395,20 @@ typedef void* (*valloc_type)(struct _malloc_zone_t* zone,
typedef void* (*realloc_type)(struct _malloc_zone_t* zone,
void* ptr,
size_t size);
+typedef void* (*memalign_type)(struct _malloc_zone_t* zone,
+ size_t alignment,
+ size_t size);
malloc_type g_old_malloc;
calloc_type g_old_calloc;
valloc_type g_old_valloc;
realloc_type g_old_realloc;
+memalign_type g_old_memalign;
void* oom_killer_malloc(struct _malloc_zone_t* zone,
size_t size) {
void* result = g_old_malloc(zone, size);
- if (size && !result)
+ if (!result && size)
DebugUtil::BreakDebugger();
return result;
}
@@ -387,7 +417,7 @@ void* oom_killer_calloc(struct _malloc_zone_t* zone,
size_t num_items,
size_t size) {
void* result = g_old_calloc(zone, num_items, size);
- if (num_items && size && !result)
+ if (!result && num_items && size)
DebugUtil::BreakDebugger();
return result;
}
@@ -395,7 +425,7 @@ void* oom_killer_calloc(struct _malloc_zone_t* zone,
void* oom_killer_valloc(struct _malloc_zone_t* zone,
size_t size) {
void* result = g_old_valloc(zone, size);
- if (size && !result)
+ if (!result && size)
DebugUtil::BreakDebugger();
return result;
}
@@ -404,11 +434,25 @@ void* oom_killer_realloc(struct _malloc_zone_t* zone,
void* ptr,
size_t size) {
void* result = g_old_realloc(zone, ptr, size);
- if (size && !result)
+ if (!result && size)
DebugUtil::BreakDebugger();
return result;
}
+void* oom_killer_memalign(struct _malloc_zone_t* zone,
+ size_t alignment,
+ size_t size) {
+ void* result = g_old_memalign(zone, alignment, size);
+ // Only die if posix_memalign would have returned ENOMEM, since there are
+ // other reasons why NULL might be returned (see
+ // http://opensource.apple.com/source/Libc/Libc-583/gen/malloc.c ).
+ if (!result && size && alignment >= sizeof(void*)
+ && (alignment & (alignment - 1)) == 0) {
+ DebugUtil::BreakDebugger();
+ }
+ return result;
+}
+
// === C++ operator new ===
void oom_killer_new() {
@@ -502,7 +546,7 @@ void EnableTerminationOnOutOfMemory() {
g_oom_killer_enabled = true;
- // === C malloc/calloc/valloc/realloc ===
+ // === C malloc/calloc/valloc/realloc/posix_memalign ===
// This approach is not perfect, as requests for amounts of memory larger than
// MALLOC_ABSOLUTE_MAX_SIZE (currently SIZE_T_MAX - (2 * PAGE_SIZE)) will
@@ -511,8 +555,8 @@ void EnableTerminationOnOutOfMemory() {
// Unfortunately, it's the best we can do. Also note that this does not affect
// allocations from non-default zones.
- CHECK(!g_old_malloc && !g_old_calloc && !g_old_valloc && !g_old_realloc)
- << "Old allocators unexpectedly non-null";
+ CHECK(!g_old_malloc && !g_old_calloc && !g_old_valloc && !g_old_realloc &&
+ !g_old_memalign) << "Old allocators unexpectedly non-null";
int32 major;
int32 minor;
@@ -520,7 +564,8 @@ void EnableTerminationOnOutOfMemory() {
SysInfo::OperatingSystemVersionNumbers(&major, &minor, &bugfix);
bool zone_allocators_protected = ((major == 10 && minor > 6) || major > 10);
- malloc_zone_t* default_zone = malloc_default_zone();
+ ChromeMallocZone* default_zone =
+ reinterpret_cast<ChromeMallocZone*>(malloc_default_zone());
vm_address_t page_start = NULL;
vm_size_t len = 0;
@@ -545,10 +590,34 @@ void EnableTerminationOnOutOfMemory() {
default_zone->valloc = oom_killer_valloc;
default_zone->realloc = oom_killer_realloc;
+ if (default_zone->version >= 5) {
+ g_old_memalign = default_zone->memalign;
+ if (g_old_memalign)
+ default_zone->memalign = oom_killer_memalign;
+ }
+
if (zone_allocators_protected) {
mprotect(reinterpret_cast<void*>(page_start), len, PROT_READ);
}
+ // === C malloc_zone_batch_malloc ===
+
+ // batch_malloc is omitted because the default malloc zone's implementation
+ // only supports batch_malloc for "tiny" allocations from the free list. It
+ // will fail for allocations larger than "tiny", and will only allocate as
+ // many blocks as it's able to from the free list. These factors mean that it
+ // can return less than the requested memory even in a non-out-of-memory
+ // situation. There's no good way to detect whether a batch_malloc failure is
+ // due to these other factors, or due to genuine memory or address space
+ // exhaustion. The fact that it only allocates space from the "tiny" free list
+ // means that it's likely that a failure will not be due to memory exhaustion.
+ // Similarly, these constraints on batch_malloc mean that callers must always
+ // be expecting to receive less memory than was requested, even in situations
+ // where memory pressure is not a concern. Finally, the only public interface
+ // to batch_malloc is malloc_zone_batch_malloc, which is specific to the
+ // system's malloc implementation. It's unlikely that anyone's even heard of
+ // it.
+
// === C++ operator new ===
// Yes, operator new does call through to malloc, but this will catch failures
diff --git a/base/process_util_unittest.cc b/base/process_util_unittest.cc
index d58db37..96dca2f 100644
--- a/base/process_util_unittest.cc
+++ b/base/process_util_unittest.cc
@@ -17,12 +17,12 @@
#include "testing/gtest/include/gtest/gtest.h"
#if defined(OS_LINUX)
-#include <dlfcn.h>
#include <errno.h>
#include <malloc.h>
#include <glib.h>
#endif
#if defined(OS_POSIX)
+#include <dlfcn.h>
#include <fcntl.h>
#include <sys/resource.h>
#include <sys/socket.h>
@@ -617,15 +617,27 @@ TEST_F(OutOfMemoryTest, ViaSharedLibraries) {
// libraries as well as for our code.
ASSERT_DEATH(value_ = g_try_malloc(test_size_), "");
}
+#endif // OS_LINUX
-
+#if defined(OS_POSIX)
TEST_F(OutOfMemoryTest, Posix_memalign) {
- // Grab the return value of posix_memalign to silence a compiler warning
- // about unused return values. We don't actually care about the return
- // value, since we're asserting death.
- ASSERT_DEATH(EXPECT_EQ(ENOMEM, posix_memalign(&value_, 8, test_size_)), "");
+ typedef int (*memalign_t)(void **, size_t, size_t);
+#if defined(OS_MACOSX)
+ // posix_memalign only exists on >= 10.6. Use dlsym to grab it at runtime
+ // because it may not be present in the SDK used for compilation.
+ memalign_t memalign =
+ reinterpret_cast<memalign_t>(dlsym(RTLD_DEFAULT, "posix_memalign"));
+#else
+ memalign_t memalign = posix_memalign;
+#endif // OS_*
+ if (memalign) {
+ // Grab the return value of posix_memalign to silence a compiler warning
+ // about unused return values. We don't actually care about the return
+ // value, since we're asserting death.
+ ASSERT_DEATH(EXPECT_EQ(ENOMEM, memalign(&value_, 8, test_size_)), "");
+ }
}
-#endif // OS_LINUX
+#endif // OS_POSIX
#if defined(OS_MACOSX)