OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 <stdio.h> | 5 #include <stdio.h> |
6 #include <stdlib.h> | 6 #include <stdlib.h> |
7 #include <new> | 7 #include <new> |
8 | 8 |
9 #include "base/process/memory.h" | 9 #include "base/process/memory.h" |
10 | 10 |
11 #include "third_party/skia/include/core/SkTypes.h" | 11 #include "third_party/skia/include/core/SkTypes.h" |
12 #include "third_party/skia/include/core/SkThread.h" | 12 #include "third_party/skia/include/core/SkThread.h" |
13 | 13 |
14 // This implementation of sk_malloc_flags() and friends is identical | 14 // This implementation of sk_malloc_flags() and friends is identical to |
15 // to SkMemory_malloc.c, except that it disables the CRT's new_handler | 15 // SkMemory_malloc.cpp, except that it disables the CRT's new_handler during |
16 // during malloc(), when SK_MALLOC_THROW is not set (ie., when | 16 // malloc() and calloc() when SK_MALLOC_THROW is not set (because our normal |
17 // sk_malloc_flags() would not abort on NULL). | 17 // new_handler itself will crash on failure when using tcmalloc). |
18 | 18 |
19 SK_DECLARE_STATIC_MUTEX(gSkNewHandlerMutex); | 19 SK_DECLARE_STATIC_MUTEX(gSkNewHandlerMutex); |
20 | 20 |
| 21 static inline void* throw_on_failure(size_t size, void* p) { |
| 22 if (size > 0 && p == NULL) { |
| 23 // If we've got a NULL here, the only reason we should have failed is ru
nning out of RAM. |
| 24 sk_out_of_memory(); |
| 25 } |
| 26 return p; |
| 27 } |
| 28 |
21 void sk_throw() { | 29 void sk_throw() { |
22 SkASSERT(!"sk_throw"); | 30 SkASSERT(!"sk_throw"); |
23 abort(); | 31 abort(); |
24 } | 32 } |
25 | 33 |
26 void sk_out_of_memory(void) { | 34 void sk_out_of_memory(void) { |
27 SkASSERT(!"sk_out_of_memory"); | 35 SkASSERT(!"sk_out_of_memory"); |
28 abort(); | 36 abort(); |
29 } | 37 } |
30 | 38 |
31 void* sk_malloc_throw(size_t size) { | |
32 return sk_malloc_flags(size, SK_MALLOC_THROW); | |
33 } | |
34 | |
35 void* sk_realloc_throw(void* addr, size_t size) { | 39 void* sk_realloc_throw(void* addr, size_t size) { |
36 void* p = realloc(addr, size); | 40 return throw_on_failure(size, realloc(addr, size)); |
37 if (size == 0) { | |
38 return p; | |
39 } | |
40 if (p == NULL) { | |
41 sk_throw(); | |
42 } | |
43 return p; | |
44 } | 41 } |
45 | 42 |
46 void sk_free(void* p) { | 43 void sk_free(void* p) { |
47 if (p) { | 44 if (p) { |
48 free(p); | 45 free(p); |
49 } | 46 } |
50 } | 47 } |
51 | 48 |
| 49 void* sk_malloc_throw(size_t size) { |
| 50 return throw_on_failure(size, malloc(size)); |
| 51 } |
| 52 |
| 53 // Platform specific ways to try really hard to get a malloc that won't crash on
failure. |
| 54 static void* sk_malloc_nothrow(size_t size) { |
| 55 #if defined(ANDROID) |
| 56 // Android doesn't have std::set_new_handler, so we just call malloc. |
| 57 return malloc(size); |
| 58 #elif defined(OS_MACOSX) && !defined(OS_IOS) |
| 59 return base::UncheckedMalloc(size); |
| 60 #else |
| 61 // This is not really thread safe. It only won't collide with itself, but w
e're totally |
| 62 // unprotected from races with other code that calls set_new_handler. |
| 63 SkAutoMutexAcquire lock(gSkNewHandlerMutex); |
| 64 std::new_handler old_handler = std::set_new_handler(NULL); |
| 65 void* p = malloc(size); |
| 66 std::set_new_handler(old_handler); |
| 67 return p; |
| 68 #endif |
| 69 } |
| 70 |
52 void* sk_malloc_flags(size_t size, unsigned flags) { | 71 void* sk_malloc_flags(size_t size, unsigned flags) { |
53 void* p; | 72 if (flags & SK_MALLOC_THROW) { |
| 73 return sk_malloc_throw(size); |
| 74 } |
| 75 return sk_malloc_nothrow(size); |
| 76 } |
| 77 |
| 78 void* sk_calloc_throw(size_t size) { |
| 79 return throw_on_failure(size, calloc(size, 1)); |
| 80 } |
| 81 |
| 82 // Jump through the same hoops as sk_malloc_nothrow to avoid a crash, but for ca
lloc. |
| 83 void* sk_calloc(size_t size) { |
54 #if defined(ANDROID) | 84 #if defined(ANDROID) |
55 // Android doesn't have std::set_new_handler. | 85 return calloc(size, 1); |
56 p = malloc(size); | 86 #elif defined(OS_MACOSX) && !defined(OS_IOS) |
| 87 return base::UncheckedCalloc(size, 1); |
57 #else | 88 #else |
58 if (!(flags & SK_MALLOC_THROW)) { | 89 SkAutoMutexAcquire lock(gSkNewHandlerMutex); |
59 #if defined(OS_MACOSX) && !defined(OS_IOS) | 90 std::new_handler old_handler = std::set_new_handler(NULL); |
60 p = base::UncheckedMalloc(size); | 91 void* p = calloc(size, 1); |
61 #else | 92 std::set_new_handler(old_handler); |
62 SkAutoMutexAcquire lock(gSkNewHandlerMutex); | 93 return p; |
63 std::new_handler old_handler = std::set_new_handler(NULL); | |
64 p = malloc(size); | |
65 std::set_new_handler(old_handler); | |
66 #endif | 94 #endif |
67 } else { | |
68 p = malloc(size); | |
69 } | |
70 #endif | |
71 if (p == NULL) { | |
72 if (flags & SK_MALLOC_THROW) { | |
73 sk_throw(); | |
74 } | |
75 } | |
76 return p; | |
77 } | 95 } |
OLD | NEW |