1 // Copyright 2014 The PDFium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7 #include "core/fxcrt/fx_memory.h"
8
9 #include <stdint.h> // For uintptr_t.
10 #include <stdlib.h> // For abort().
11
12 #include <iterator>
13 #include <limits>
14 #include <type_traits>
15
16 #include "build/build_config.h"
17 #include "core/fxcrt/check_op.h"
18 #include "core/fxcrt/debug/alias.h"
19
20 #if BUILDFLAG(IS_WIN)
21 #include <windows.h>
22 #endif
23
24 #if BUILDFLAG(IS_ANDROID)
25 #include <malloc.h>
26 #endif
27
28 namespace {
29
30 #if DCHECK_IS_ON()
31 // TODO(thestig): When C++20 is required, replace with std::has_single_bit().
32 // Returns true iff |value| is a power of 2.
33 template <typename T, typename = std::enable_if<std::is_integral<T>::value>>
IsPowerOfTwo(T value)34 constexpr inline bool IsPowerOfTwo(T value) {
35 // From "Hacker's Delight": Section 2.1 Manipulating Rightmost Bits.
36 //
37 // Only positive integers with a single bit set are powers of two. If only one
38 // bit is set in x (e.g. 0b00000100000000) then |x-1| will have that bit set
39 // to zero and all bits to its right set to 1 (e.g. 0b00000011111111). Hence
40 // |x & (x-1)| is 0 iff x is a power of two.
41 return value > 0 && (value & (value - 1)) == 0;
42 }
43
44 #ifdef __has_builtin
45 #define SUPPORTS_BUILTIN_IS_ALIGNED (__has_builtin(__builtin_is_aligned))
46 #else
47 #define SUPPORTS_BUILTIN_IS_ALIGNED 0
48 #endif
49
IsAligned(void * val,size_t alignment)50 inline bool IsAligned(void* val, size_t alignment) {
51 // If the compiler supports builtin alignment checks prefer them.
52 #if SUPPORTS_BUILTIN_IS_ALIGNED
53 return __builtin_is_aligned(reinterpret_cast<uintptr_t>(val), alignment);
54 #else
55 DCHECK(IsPowerOfTwo(alignment));
56 return (reinterpret_cast<uintptr_t>(val) & (alignment - 1)) == 0;
57 #endif
58 }
59
60 #undef SUPPORTS_BUILTIN_IS_ALIGNED
61
62 #endif // DCHECK_IS_ON()
63
64 } // namespace
65
FXMEM_DefaultAlloc(size_t byte_size)66 void* FXMEM_DefaultAlloc(size_t byte_size) {
67 return pdfium::internal::Alloc(byte_size, 1);
68 }
69
FXMEM_DefaultCalloc(size_t num_elems,size_t byte_size)70 void* FXMEM_DefaultCalloc(size_t num_elems, size_t byte_size) {
71 return pdfium::internal::Calloc(num_elems, byte_size);
72 }
73
FXMEM_DefaultRealloc(void * pointer,size_t new_size)74 void* FXMEM_DefaultRealloc(void* pointer, size_t new_size) {
75 return pdfium::internal::Realloc(pointer, new_size, 1);
76 }
77
FXMEM_DefaultFree(void * pointer)78 void FXMEM_DefaultFree(void* pointer) {
79 FX_Free(pointer);
80 }
81
FX_OutOfMemoryTerminate(size_t size)82 NOINLINE void FX_OutOfMemoryTerminate(size_t size) {
83 // Convince the linker this should not be folded with similar functions using
84 // Identical Code Folding.
85 static int make_this_function_aliased = 0xbd;
86 pdfium::Alias(&make_this_function_aliased);
87
88 #if BUILDFLAG(IS_WIN)
89 // The same custom Windows exception code used in Chromium and Breakpad.
90 constexpr DWORD kOomExceptionCode = 0xe0000008;
91 ULONG_PTR exception_args[] = {size};
92 ::RaiseException(kOomExceptionCode, EXCEPTION_NONCONTINUABLE,
93 std::size(exception_args), exception_args);
94 #endif
95
96 // Terminate cleanly.
97 abort();
98 }
99
FX_AlignedAlloc(size_t size,size_t alignment)100 void* FX_AlignedAlloc(size_t size, size_t alignment) {
101 DCHECK_GT(size, 0u);
102 DCHECK(IsPowerOfTwo(alignment));
103 DCHECK_EQ(alignment % sizeof(void*), 0u);
104 void* ptr = nullptr;
105 #if defined(COMPILER_MSVC)
106 ptr = _aligned_malloc(size, alignment);
107 #elif BUILDFLAG(IS_ANDROID)
108 // Android technically supports posix_memalign(), but does not expose it in
109 // the current version of the library headers used by Chrome. Luckily,
110 // memalign() on Android returns pointers which can safely be used with
111 // free(), so we can use it instead. Issue filed to document this:
112 // http://code.google.com/p/android/issues/detail?id=35391
113 ptr = memalign(alignment, size);
114 #else
115 int ret = posix_memalign(&ptr, alignment, size);
116 if (ret != 0) {
117 ptr = nullptr;
118 }
119 #endif
120
121 // Since aligned allocations may fail for non-memory related reasons, force a
122 // crash if we encounter a failed allocation; maintaining consistent behavior
123 // with a normal allocation failure in Chrome.
124 if (!ptr) {
125 CHECK(false);
126 }
127 // Sanity check alignment just to be safe.
128 DCHECK(IsAligned(ptr, alignment));
129 return ptr;
130 }
131
132 namespace pdfium::internal {
133
Alloc2D(size_t w,size_t h,size_t member_size)134 void* Alloc2D(size_t w, size_t h, size_t member_size) {
135 if (w >= std::numeric_limits<size_t>::max() / h) {
136 return nullptr;
137 }
138
139 return Alloc(w * h, member_size);
140 }
141
AllocOrDie(size_t num_members,size_t member_size)142 void* AllocOrDie(size_t num_members, size_t member_size) {
143 void* result = Alloc(num_members, member_size);
144 if (!result)
145 FX_OutOfMemoryTerminate(0); // Never returns.
146
147 return result;
148 }
149
AllocOrDie2D(size_t w,size_t h,size_t member_size)150 void* AllocOrDie2D(size_t w, size_t h, size_t member_size) {
151 if (w >= std::numeric_limits<size_t>::max() / h)
152 FX_OutOfMemoryTerminate(0); // Never returns.
153
154 return AllocOrDie(w * h, member_size);
155 }
CallocOrDie(size_t num_members,size_t member_size)156 void* CallocOrDie(size_t num_members, size_t member_size) {
157 void* result = Calloc(num_members, member_size);
158 if (!result)
159 FX_OutOfMemoryTerminate(0); // Never returns.
160
161 return result;
162 }
163
CallocOrDie2D(size_t w,size_t h,size_t member_size)164 void* CallocOrDie2D(size_t w, size_t h, size_t member_size) {
165 if (w >= std::numeric_limits<size_t>::max() / h)
166 FX_OutOfMemoryTerminate(0); // Never returns.
167
168 return CallocOrDie(w * h, member_size);
169 }
170
ReallocOrDie(void * ptr,size_t num_members,size_t member_size)171 void* ReallocOrDie(void* ptr, size_t num_members, size_t member_size) {
172 void* result = Realloc(ptr, num_members, member_size);
173 if (!result)
174 FX_OutOfMemoryTerminate(0); // Never returns.
175
176 return result;
177 }
178
StringAllocOrDie(size_t num_members,size_t member_size)179 void* StringAllocOrDie(size_t num_members, size_t member_size) {
180 void* result = StringAlloc(num_members, member_size);
181 if (!result)
182 FX_OutOfMemoryTerminate(0); // Never returns.
183
184 return result;
185 }
186
187 } // namespace pdfium::internal
188