summaryrefslogtreecommitdiffstats
path: root/base/process_util_mac.mm
diff options
context:
space:
mode:
Diffstat (limited to 'base/process_util_mac.mm')
-rw-r--r--base/process_util_mac.mm87
1 files changed, 78 insertions, 9 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