• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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