| OLD | NEW |
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "base/process/memory.h" | 5 #include "base/process/memory.h" |
| 6 | 6 |
| 7 #include <CoreFoundation/CoreFoundation.h> | 7 #include <CoreFoundation/CoreFoundation.h> |
| 8 #import <Foundation/Foundation.h> | 8 #import <Foundation/Foundation.h> |
| 9 #include <errno.h> | 9 #include <errno.h> |
| 10 #include <mach/mach.h> | 10 #include <mach/mach.h> |
| (...skipping 346 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 357 // MALLOC_ABSOLUTE_MAX_SIZE (currently SIZE_T_MAX - (2 * PAGE_SIZE)) will | 357 // MALLOC_ABSOLUTE_MAX_SIZE (currently SIZE_T_MAX - (2 * PAGE_SIZE)) will |
| 358 // still fail with a NULL rather than dying (see | 358 // still fail with a NULL rather than dying (see |
| 359 // http://opensource.apple.com/source/Libc/Libc-583/gen/malloc.c for details). | 359 // http://opensource.apple.com/source/Libc/Libc-583/gen/malloc.c for details). |
| 360 // Unfortunately, it's the best we can do. Also note that this does not affect | 360 // Unfortunately, it's the best we can do. Also note that this does not affect |
| 361 // allocations from non-default zones. | 361 // allocations from non-default zones. |
| 362 | 362 |
| 363 #if !defined(ADDRESS_SANITIZER) | 363 #if !defined(ADDRESS_SANITIZER) |
| 364 // Don't do anything special on OOM for the malloc zones replaced by | 364 // Don't do anything special on OOM for the malloc zones replaced by |
| 365 // AddressSanitizer, as modifying or protecting them may not work correctly. | 365 // AddressSanitizer, as modifying or protecting them may not work correctly. |
| 366 | 366 |
| 367 // Old allocators unexpectedly non-null |
| 367 CHECK(!g_old_malloc && !g_old_calloc && !g_old_valloc && !g_old_realloc && | 368 CHECK(!g_old_malloc && !g_old_calloc && !g_old_valloc && !g_old_realloc && |
| 368 !g_old_memalign) << "Old allocators unexpectedly non-null"; | 369 !g_old_memalign); |
| 369 | 370 |
| 371 // Old allocators unexpectedly non-null |
| 370 CHECK(!g_old_malloc_purgeable && !g_old_calloc_purgeable && | 372 CHECK(!g_old_malloc_purgeable && !g_old_calloc_purgeable && |
| 371 !g_old_valloc_purgeable && !g_old_realloc_purgeable && | 373 !g_old_valloc_purgeable && !g_old_realloc_purgeable && |
| 372 !g_old_memalign_purgeable) << "Old allocators unexpectedly non-null"; | 374 !g_old_memalign_purgeable); |
| 373 | 375 |
| 374 ChromeMallocZone* default_zone = | 376 ChromeMallocZone* default_zone = |
| 375 reinterpret_cast<ChromeMallocZone*>(malloc_default_zone()); | 377 reinterpret_cast<ChromeMallocZone*>(malloc_default_zone()); |
| 376 ChromeMallocZone* purgeable_zone = | 378 ChromeMallocZone* purgeable_zone = |
| 377 reinterpret_cast<ChromeMallocZone*>(malloc_default_purgeable_zone()); | 379 reinterpret_cast<ChromeMallocZone*>(malloc_default_purgeable_zone()); |
| 378 | 380 |
| 379 mach_vm_address_t default_reprotection_start = 0; | 381 mach_vm_address_t default_reprotection_start = 0; |
| 380 mach_vm_size_t default_reprotection_length = 0; | 382 mach_vm_size_t default_reprotection_length = 0; |
| 381 vm_prot_t default_reprotection_value = VM_PROT_NONE; | 383 vm_prot_t default_reprotection_value = VM_PROT_NONE; |
| 382 DeprotectMallocZone(default_zone, | 384 DeprotectMallocZone(default_zone, |
| (...skipping 11 matching lines...) Expand all Loading... |
| 394 &purgeable_reprotection_value); | 396 &purgeable_reprotection_value); |
| 395 } | 397 } |
| 396 | 398 |
| 397 // Default zone | 399 // Default zone |
| 398 | 400 |
| 399 g_old_malloc = default_zone->malloc; | 401 g_old_malloc = default_zone->malloc; |
| 400 g_old_calloc = default_zone->calloc; | 402 g_old_calloc = default_zone->calloc; |
| 401 g_old_valloc = default_zone->valloc; | 403 g_old_valloc = default_zone->valloc; |
| 402 g_old_free = default_zone->free; | 404 g_old_free = default_zone->free; |
| 403 g_old_realloc = default_zone->realloc; | 405 g_old_realloc = default_zone->realloc; |
| 406 // Failed to get system allocation functions. |
| 404 CHECK(g_old_malloc && g_old_calloc && g_old_valloc && g_old_free && | 407 CHECK(g_old_malloc && g_old_calloc && g_old_valloc && g_old_free && |
| 405 g_old_realloc) | 408 g_old_realloc); |
| 406 << "Failed to get system allocation functions."; | |
| 407 | 409 |
| 408 default_zone->malloc = oom_killer_malloc; | 410 default_zone->malloc = oom_killer_malloc; |
| 409 default_zone->calloc = oom_killer_calloc; | 411 default_zone->calloc = oom_killer_calloc; |
| 410 default_zone->valloc = oom_killer_valloc; | 412 default_zone->valloc = oom_killer_valloc; |
| 411 default_zone->free = oom_killer_free; | 413 default_zone->free = oom_killer_free; |
| 412 default_zone->realloc = oom_killer_realloc; | 414 default_zone->realloc = oom_killer_realloc; |
| 413 | 415 |
| 414 if (default_zone->version >= 5) { | 416 if (default_zone->version >= 5) { |
| 415 g_old_memalign = default_zone->memalign; | 417 g_old_memalign = default_zone->memalign; |
| 416 if (g_old_memalign) | 418 if (g_old_memalign) |
| 417 default_zone->memalign = oom_killer_memalign; | 419 default_zone->memalign = oom_killer_memalign; |
| 418 } | 420 } |
| 419 | 421 |
| 420 // Purgeable zone (if it exists) | 422 // Purgeable zone (if it exists) |
| 421 | 423 |
| 422 if (purgeable_zone) { | 424 if (purgeable_zone) { |
| 423 g_old_malloc_purgeable = purgeable_zone->malloc; | 425 g_old_malloc_purgeable = purgeable_zone->malloc; |
| 424 g_old_calloc_purgeable = purgeable_zone->calloc; | 426 g_old_calloc_purgeable = purgeable_zone->calloc; |
| 425 g_old_valloc_purgeable = purgeable_zone->valloc; | 427 g_old_valloc_purgeable = purgeable_zone->valloc; |
| 426 g_old_free_purgeable = purgeable_zone->free; | 428 g_old_free_purgeable = purgeable_zone->free; |
| 427 g_old_realloc_purgeable = purgeable_zone->realloc; | 429 g_old_realloc_purgeable = purgeable_zone->realloc; |
| 430 // Failed to get system allocation functions. |
| 428 CHECK(g_old_malloc_purgeable && g_old_calloc_purgeable && | 431 CHECK(g_old_malloc_purgeable && g_old_calloc_purgeable && |
| 429 g_old_valloc_purgeable && g_old_free_purgeable && | 432 g_old_valloc_purgeable && g_old_free_purgeable && |
| 430 g_old_realloc_purgeable) | 433 g_old_realloc_purgeable); |
| 431 << "Failed to get system allocation functions."; | |
| 432 | 434 |
| 433 purgeable_zone->malloc = oom_killer_malloc_purgeable; | 435 purgeable_zone->malloc = oom_killer_malloc_purgeable; |
| 434 purgeable_zone->calloc = oom_killer_calloc_purgeable; | 436 purgeable_zone->calloc = oom_killer_calloc_purgeable; |
| 435 purgeable_zone->valloc = oom_killer_valloc_purgeable; | 437 purgeable_zone->valloc = oom_killer_valloc_purgeable; |
| 436 purgeable_zone->free = oom_killer_free_purgeable; | 438 purgeable_zone->free = oom_killer_free_purgeable; |
| 437 purgeable_zone->realloc = oom_killer_realloc_purgeable; | 439 purgeable_zone->realloc = oom_killer_realloc_purgeable; |
| 438 | 440 |
| 439 if (purgeable_zone->version >= 5) { | 441 if (purgeable_zone->version >= 5) { |
| 440 g_old_memalign_purgeable = purgeable_zone->memalign; | 442 g_old_memalign_purgeable = purgeable_zone->memalign; |
| 441 if (g_old_memalign_purgeable) | 443 if (g_old_memalign_purgeable) |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 488 // that our imperfect handling of malloc cannot. | 490 // that our imperfect handling of malloc cannot. |
| 489 | 491 |
| 490 std::set_new_handler(oom_killer_new); | 492 std::set_new_handler(oom_killer_new); |
| 491 | 493 |
| 492 #ifndef ADDRESS_SANITIZER | 494 #ifndef ADDRESS_SANITIZER |
| 493 // === Core Foundation CFAllocators === | 495 // === Core Foundation CFAllocators === |
| 494 | 496 |
| 495 // This will not catch allocation done by custom allocators, but will catch | 497 // This will not catch allocation done by custom allocators, but will catch |
| 496 // all allocation done by system-provided ones. | 498 // all allocation done by system-provided ones. |
| 497 | 499 |
| 500 // Old allocators unexpectedly non-null |
| 498 CHECK(!g_old_cfallocator_system_default && !g_old_cfallocator_malloc && | 501 CHECK(!g_old_cfallocator_system_default && !g_old_cfallocator_malloc && |
| 499 !g_old_cfallocator_malloc_zone) | 502 !g_old_cfallocator_malloc_zone); |
| 500 << "Old allocators unexpectedly non-null"; | |
| 501 | 503 |
| 502 bool cf_allocator_internals_known = CanGetContextForCFAllocator(); | 504 bool cf_allocator_internals_known = CanGetContextForCFAllocator(); |
| 503 | 505 |
| 504 if (cf_allocator_internals_known) { | 506 if (cf_allocator_internals_known) { |
| 505 CFAllocatorContext* context = | 507 CFAllocatorContext* context = |
| 506 ContextForCFAllocator(kCFAllocatorSystemDefault); | 508 ContextForCFAllocator(kCFAllocatorSystemDefault); |
| 507 CHECK(context) << "Failed to get context for kCFAllocatorSystemDefault."; | 509 // Failed to get context for kCFAllocatorSystemDefault. |
| 510 CHECK(context); |
| 508 g_old_cfallocator_system_default = context->allocate; | 511 g_old_cfallocator_system_default = context->allocate; |
| 509 CHECK(g_old_cfallocator_system_default) | 512 // Failed to get kCFAllocatorSystemDefault allocation function. |
| 510 << "Failed to get kCFAllocatorSystemDefault allocation function."; | 513 CHECK(g_old_cfallocator_system_default); |
| 511 context->allocate = oom_killer_cfallocator_system_default; | 514 context->allocate = oom_killer_cfallocator_system_default; |
| 512 | 515 |
| 513 context = ContextForCFAllocator(kCFAllocatorMalloc); | 516 context = ContextForCFAllocator(kCFAllocatorMalloc); |
| 514 CHECK(context) << "Failed to get context for kCFAllocatorMalloc."; | 517 // Failed to get context for kCFAllocatorMalloc. |
| 518 CHECK(context); |
| 515 g_old_cfallocator_malloc = context->allocate; | 519 g_old_cfallocator_malloc = context->allocate; |
| 516 CHECK(g_old_cfallocator_malloc) | 520 // Failed to get kCFAllocatorMalloc allocation function. |
| 517 << "Failed to get kCFAllocatorMalloc allocation function."; | 521 CHECK(g_old_cfallocator_malloc); |
| 518 context->allocate = oom_killer_cfallocator_malloc; | 522 context->allocate = oom_killer_cfallocator_malloc; |
| 519 | 523 |
| 520 context = ContextForCFAllocator(kCFAllocatorMallocZone); | 524 context = ContextForCFAllocator(kCFAllocatorMallocZone); |
| 521 CHECK(context) << "Failed to get context for kCFAllocatorMallocZone."; | 525 // Failed to get context for kCFAllocatorMallocZone. |
| 526 CHECK(context); |
| 522 g_old_cfallocator_malloc_zone = context->allocate; | 527 g_old_cfallocator_malloc_zone = context->allocate; |
| 523 CHECK(g_old_cfallocator_malloc_zone) | 528 // Failed to get kCFAllocatorMallocZone allocation function. |
| 524 << "Failed to get kCFAllocatorMallocZone allocation function."; | 529 CHECK(g_old_cfallocator_malloc_zone); |
| 525 context->allocate = oom_killer_cfallocator_malloc_zone; | 530 context->allocate = oom_killer_cfallocator_malloc_zone; |
| 526 } else { | 531 } else { |
| 527 DLOG(WARNING) << "Internals of CFAllocator not known; out-of-memory " | 532 DLOG(WARNING) << "Internals of CFAllocator not known; out-of-memory " |
| 528 "failures via CFAllocator will not result in termination. " | 533 "failures via CFAllocator will not result in termination. " |
| 529 "http://crbug.com/45650"; | 534 "http://crbug.com/45650"; |
| 530 } | 535 } |
| 531 #endif | 536 #endif |
| 532 | 537 |
| 533 // === Cocoa NSObject allocation === | 538 // === Cocoa NSObject allocation === |
| 534 | 539 |
| 535 // Note that both +[NSObject new] and +[NSObject alloc] call through to | 540 // Note that both +[NSObject new] and +[NSObject alloc] call through to |
| 536 // +[NSObject allocWithZone:]. | 541 // +[NSObject allocWithZone:]. |
| 537 | 542 |
| 538 CHECK(!g_old_allocWithZone) | 543 // Old allocator unexpectedly non-null |
| 539 << "Old allocator unexpectedly non-null"; | 544 CHECK(!g_old_allocWithZone); |
| 540 | 545 |
| 541 Class nsobject_class = [NSObject class]; | 546 Class nsobject_class = [NSObject class]; |
| 542 Method orig_method = class_getClassMethod(nsobject_class, | 547 Method orig_method = class_getClassMethod(nsobject_class, |
| 543 @selector(allocWithZone:)); | 548 @selector(allocWithZone:)); |
| 544 g_old_allocWithZone = reinterpret_cast<allocWithZone_t>( | 549 g_old_allocWithZone = reinterpret_cast<allocWithZone_t>( |
| 545 method_getImplementation(orig_method)); | 550 method_getImplementation(orig_method)); |
| 546 CHECK(g_old_allocWithZone) | 551 // Failed to get allocWithZone allocation function. |
| 547 << "Failed to get allocWithZone allocation function."; | 552 CHECK(g_old_allocWithZone); |
| 548 method_setImplementation(orig_method, | 553 method_setImplementation(orig_method, |
| 549 reinterpret_cast<IMP>(oom_killer_allocWithZone)); | 554 reinterpret_cast<IMP>(oom_killer_allocWithZone)); |
| 550 } | 555 } |
| 551 | 556 |
| 552 } // namespace base | 557 } // namespace base |
| OLD | NEW |