1 /*
2 * Copyright 2011 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "include/private/base/SkAssert.h"
9 #include "include/private/base/SkDebug.h"
10 #include "include/private/base/SkFeatures.h"
11 #include "include/private/base/SkMalloc.h"
12
13 #include <algorithm>
14 #include <cstdlib>
15
16 #if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS)
17 #include <malloc/malloc.h>
18 #elif defined(SK_BUILD_FOR_ANDROID) || defined(SK_BUILD_FOR_UNIX)
19 #include <malloc.h>
20 #elif defined(SK_BUILD_FOR_WIN)
21 #include <malloc.h>
22 #endif
23
24 #if defined(SK_DEBUG) && defined(SK_BUILD_FOR_WIN)
25 #include <intrin.h>
26 // This is a super stable value and setting it here avoids pulling in all of windows.h.
27 #ifndef FAST_FAIL_FATAL_APP_EXIT
28 #define FAST_FAIL_FATAL_APP_EXIT 7
29 #endif
30 #endif
31
32 #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
33 #define SK_DEBUGFAILF(fmt, ...) SK_ABORT(fmt"\n", __VA_ARGS__)
34 #else
35 #define SK_DEBUGFAILF(fmt, ...) SkASSERT((SkDebugf(fmt"\n", __VA_ARGS__), false))
36 #endif
37
sk_out_of_memory(size_t size)38 static inline void sk_out_of_memory(size_t size) {
39 SK_DEBUGFAILF("sk_out_of_memory (asked for %zu bytes)",
40 size);
41 #if defined(SK_BUILD_FOR_AFL_FUZZ)
42 exit(1);
43 #else
44 abort();
45 #endif
46 }
47
throw_on_failure(size_t size,void * p)48 static inline void* throw_on_failure(size_t size, void* p) {
49 if (size > 0 && p == nullptr) {
50 // If we've got a nullptr here, the only reason we should have failed is running out of RAM.
51 sk_out_of_memory(size);
52 }
53 return p;
54 }
55
sk_abort_no_print()56 void sk_abort_no_print() {
57 #if defined(SK_DEBUG) && defined(SK_BUILD_FOR_WIN)
58 __fastfail(FAST_FAIL_FATAL_APP_EXIT);
59 #elif defined(__clang__)
60 __builtin_trap();
61 #else
62 abort();
63 #endif
64 }
65
sk_out_of_memory(void)66 void sk_out_of_memory(void) {
67 SkDEBUGFAIL("sk_out_of_memory");
68 #if defined(SK_BUILD_FOR_AFL_FUZZ)
69 exit(1);
70 #else
71 abort();
72 #endif
73 }
74
sk_realloc_throw(void * addr,size_t size)75 void* sk_realloc_throw(void* addr, size_t size) {
76 if (size == 0) {
77 sk_free(addr);
78 return nullptr;
79 }
80 return throw_on_failure(size, realloc(addr, size));
81 }
82
sk_free(void * p)83 void sk_free(void* p) {
84 // The guard here produces a performance improvement across many tests, and many platforms.
85 // Removing the check was tried in skia cl 588037.
86 if (p != nullptr) {
87 free(p);
88 }
89 }
90
sk_malloc_flags(size_t size,unsigned flags)91 void* sk_malloc_flags(size_t size, unsigned flags) {
92 void* p;
93 if (flags & SK_MALLOC_ZERO_INITIALIZE) {
94 p = calloc(size, 1);
95 } else {
96 #if defined(SK_BUILD_FOR_ANDROID_FRAMEWORK) && defined(__BIONIC__)
97 /* TODO: After b/169449588 is fixed, we will want to change this to restore
98 * original behavior instead of always disabling the flag.
99 * TODO: After b/158870657 is fixed and scudo is used globally, we can assert when an
100 * an error is returned.
101 */
102 // malloc() generally doesn't initialize its memory and that's a huge security hole,
103 // so Android has replaced its malloc() with one that zeros memory,
104 // but that's a huge performance hit for HWUI, so turn it back off again.
105 (void)mallopt(M_THREAD_DISABLE_MEM_INIT, 1);
106 #endif
107 p = malloc(size);
108 #if defined(SK_BUILD_FOR_ANDROID_FRAMEWORK) && defined(__BIONIC__)
109 (void)mallopt(M_THREAD_DISABLE_MEM_INIT, 0);
110 #endif
111 }
112 if (flags & SK_MALLOC_THROW) {
113 return throw_on_failure(size, p);
114 } else {
115 return p;
116 }
117 }
118
sk_malloc_size(void * addr,size_t size)119 size_t sk_malloc_size(void* addr, size_t size) {
120 size_t completeSize = size;
121
122 // Use the OS specific calls to find the actual capacity.
123 #if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS)
124 // TODO: remove the max, when the chrome implementation of malloc_size doesn't return 0.
125 completeSize = std::max(malloc_size(addr), size);
126 #elif defined(SK_BUILD_FOR_ANDROID) && __ANDROID_API__ >= 17
127 completeSize = malloc_usable_size(addr);
128 SkASSERT(completeSize >= size);
129 #elif defined(SK_BUILD_FOR_UNIX)
130 completeSize = malloc_usable_size(addr);
131 SkASSERT(completeSize >= size);
132 #elif defined(SK_BUILD_FOR_WIN)
133 completeSize = _msize(addr);
134 SkASSERT(completeSize >= size);
135 #endif
136
137 return completeSize;
138 }
139