summaryrefslogtreecommitdiffstats
path: root/base/process_util_mac.mm
diff options
context:
space:
mode:
authorrsesek@chromium.org <rsesek@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-04-04 20:00:53 +0000
committerrsesek@chromium.org <rsesek@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-04-04 20:00:53 +0000
commit32799485eb13b8f617bac4b6a3b648d99ff7c196 (patch)
tree1cefbc94263b3d9a61df1022d07f7079b335e184 /base/process_util_mac.mm
parent2beea33feabb7eec84815ecd6fa3c2e2112f1d3e (diff)
downloadchromium_src-32799485eb13b8f617bac4b6a3b648d99ff7c196.zip
chromium_src-32799485eb13b8f617bac4b6a3b648d99ff7c196.tar.gz
chromium_src-32799485eb13b8f617bac4b6a3b648d99ff7c196.tar.bz2
In CrMallocErrorBreak, do not kill the process if errno is ENOMEM.
This is based on CL 9597031, but clears errno when calling through the overriden allocators. BUG=103980 TEST=Covered by ProcessUtilTest.MacTerminateOnHeapCorruption Review URL: https://chromiumcodereview.appspot.com/9965075 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@130712 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/process_util_mac.mm')
-rw-r--r--base/process_util_mac.mm62
1 files changed, 60 insertions, 2 deletions
diff --git a/base/process_util_mac.mm b/base/process_util_mac.mm
index e6ccd32..24f93ee 100644
--- a/base/process_util_mac.mm
+++ b/base/process_util_mac.mm
@@ -547,8 +547,34 @@ malloc_error_break_t LookUpMallocErrorBreak() {
return NULL;
}
+// Simple scoper that saves the current value of errno, resets it to 0, and on
+// destruction puts the old value back. This is so that CrMallocErrorBreak can
+// safely test errno free from the effects of other routines.
+class ScopedClearErrno {
+ public:
+ ScopedClearErrno() : old_errno_(errno) {
+ errno = 0;
+ }
+ ~ScopedClearErrno() {
+ if (errno == 0)
+ errno = old_errno_;
+ }
+
+ private:
+ int old_errno_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedClearErrno);
+};
+
void CrMallocErrorBreak() {
g_original_malloc_error_break();
+
+ // Out of memory is certainly not heap corruption, and not necessarily
+ // something for which the process should be terminated. Leave that decision
+ // to the OOM killer.
+ if (errno == ENOMEM)
+ return;
+
// A unit test checks this error message, so it needs to be in release builds.
LOG(ERROR) <<
"Terminating process due to a potential for future heap corruption";
@@ -594,6 +620,8 @@ typedef void* (*calloc_type)(struct _malloc_zone_t* zone,
size_t size);
typedef void* (*valloc_type)(struct _malloc_zone_t* zone,
size_t size);
+typedef void (*free_type)(struct _malloc_zone_t* zone,
+ void* ptr);
typedef void* (*realloc_type)(struct _malloc_zone_t* zone,
void* ptr,
size_t size);
@@ -604,17 +632,20 @@ typedef void* (*memalign_type)(struct _malloc_zone_t* zone,
malloc_type g_old_malloc;
calloc_type g_old_calloc;
valloc_type g_old_valloc;
+free_type g_old_free;
realloc_type g_old_realloc;
memalign_type g_old_memalign;
malloc_type g_old_malloc_purgeable;
calloc_type g_old_calloc_purgeable;
valloc_type g_old_valloc_purgeable;
+free_type g_old_free_purgeable;
realloc_type g_old_realloc_purgeable;
memalign_type g_old_memalign_purgeable;
void* oom_killer_malloc(struct _malloc_zone_t* zone,
size_t size) {
+ ScopedClearErrno clear_errno;
void* result = g_old_malloc(zone, size);
if (!result && size)
debug::BreakDebugger();
@@ -624,6 +655,7 @@ void* oom_killer_malloc(struct _malloc_zone_t* zone,
void* oom_killer_calloc(struct _malloc_zone_t* zone,
size_t num_items,
size_t size) {
+ ScopedClearErrno clear_errno;
void* result = g_old_calloc(zone, num_items, size);
if (!result && num_items && size)
debug::BreakDebugger();
@@ -632,15 +664,23 @@ void* oom_killer_calloc(struct _malloc_zone_t* zone,
void* oom_killer_valloc(struct _malloc_zone_t* zone,
size_t size) {
+ ScopedClearErrno clear_errno;
void* result = g_old_valloc(zone, size);
if (!result && size)
debug::BreakDebugger();
return result;
}
+void oom_killer_free(struct _malloc_zone_t* zone,
+ void* ptr) {
+ ScopedClearErrno clear_errno;
+ g_old_free(zone, ptr);
+}
+
void* oom_killer_realloc(struct _malloc_zone_t* zone,
void* ptr,
size_t size) {
+ ScopedClearErrno clear_errno;
void* result = g_old_realloc(zone, ptr, size);
if (!result && size)
debug::BreakDebugger();
@@ -650,6 +690,7 @@ void* oom_killer_realloc(struct _malloc_zone_t* zone,
void* oom_killer_memalign(struct _malloc_zone_t* zone,
size_t alignment,
size_t size) {
+ ScopedClearErrno clear_errno;
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
@@ -663,6 +704,7 @@ void* oom_killer_memalign(struct _malloc_zone_t* zone,
void* oom_killer_malloc_purgeable(struct _malloc_zone_t* zone,
size_t size) {
+ ScopedClearErrno clear_errno;
void* result = g_old_malloc_purgeable(zone, size);
if (!result && size)
debug::BreakDebugger();
@@ -672,6 +714,7 @@ void* oom_killer_malloc_purgeable(struct _malloc_zone_t* zone,
void* oom_killer_calloc_purgeable(struct _malloc_zone_t* zone,
size_t num_items,
size_t size) {
+ ScopedClearErrno clear_errno;
void* result = g_old_calloc_purgeable(zone, num_items, size);
if (!result && num_items && size)
debug::BreakDebugger();
@@ -680,15 +723,23 @@ void* oom_killer_calloc_purgeable(struct _malloc_zone_t* zone,
void* oom_killer_valloc_purgeable(struct _malloc_zone_t* zone,
size_t size) {
+ ScopedClearErrno clear_errno;
void* result = g_old_valloc_purgeable(zone, size);
if (!result && size)
debug::BreakDebugger();
return result;
}
+void oom_killer_free_purgeable(struct _malloc_zone_t* zone,
+ void* ptr) {
+ ScopedClearErrno clear_errno;
+ g_old_free_purgeable(zone, ptr);
+}
+
void* oom_killer_realloc_purgeable(struct _malloc_zone_t* zone,
void* ptr,
size_t size) {
+ ScopedClearErrno clear_errno;
void* result = g_old_realloc_purgeable(zone, ptr, size);
if (!result && size)
debug::BreakDebugger();
@@ -698,6 +749,7 @@ void* oom_killer_realloc_purgeable(struct _malloc_zone_t* zone,
void* oom_killer_memalign_purgeable(struct _malloc_zone_t* zone,
size_t alignment,
size_t size) {
+ ScopedClearErrno clear_errno;
void* result = g_old_memalign_purgeable(zone, alignment, size);
// Only die if posix_memalign would have returned ENOMEM, since there are
// other reasons why NULL might be returned (see
@@ -864,13 +916,16 @@ void EnableTerminationOnOutOfMemory() {
g_old_malloc = default_zone->malloc;
g_old_calloc = default_zone->calloc;
g_old_valloc = default_zone->valloc;
+ g_old_free = default_zone->free;
g_old_realloc = default_zone->realloc;
- CHECK(g_old_malloc && g_old_calloc && g_old_valloc && g_old_realloc)
+ CHECK(g_old_malloc && g_old_calloc && g_old_valloc && g_old_free &&
+ g_old_realloc)
<< "Failed to get system allocation functions.";
default_zone->malloc = oom_killer_malloc;
default_zone->calloc = oom_killer_calloc;
default_zone->valloc = oom_killer_valloc;
+ default_zone->free = oom_killer_free;
default_zone->realloc = oom_killer_realloc;
if (default_zone->version >= 5) {
@@ -885,14 +940,17 @@ void EnableTerminationOnOutOfMemory() {
g_old_malloc_purgeable = purgeable_zone->malloc;
g_old_calloc_purgeable = purgeable_zone->calloc;
g_old_valloc_purgeable = purgeable_zone->valloc;
+ g_old_free_purgeable = purgeable_zone->free;
g_old_realloc_purgeable = purgeable_zone->realloc;
CHECK(g_old_malloc_purgeable && g_old_calloc_purgeable &&
- g_old_valloc_purgeable && g_old_realloc_purgeable)
+ g_old_valloc_purgeable && g_old_free_purgeable &&
+ g_old_realloc_purgeable)
<< "Failed to get system allocation functions.";
purgeable_zone->malloc = oom_killer_malloc_purgeable;
purgeable_zone->calloc = oom_killer_calloc_purgeable;
purgeable_zone->valloc = oom_killer_valloc_purgeable;
+ purgeable_zone->free = oom_killer_free_purgeable;
purgeable_zone->realloc = oom_killer_realloc_purgeable;
if (purgeable_zone->version >= 5) {