1 // Copyright 2022 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 "core/fxcrt/compiler_specific.h"
10 #include "core/fxcrt/fx_safe_types.h"
11
12 #if defined(PDF_USE_PARTITION_ALLOC)
13 #include "partition_alloc/partition_alloc.h"
14 #else
15 #error "File compiled under wrong build option."
16 #endif
17
18 namespace {
19
20 constexpr partition_alloc::PartitionOptions kOptions = {};
21
22 struct Allocators {
23 #ifndef V8_ENABLE_SANDBOX
24 partition_alloc::PartitionAllocator array_buffer_allocator{kOptions};
25 #endif
26
27 partition_alloc::PartitionAllocator general_allocator{kOptions};
28 partition_alloc::PartitionAllocator string_allocator{kOptions};
29 };
30
31 Allocators* g_allocators = nullptr;
32
33 #ifndef V8_ENABLE_SANDBOX
GetArrayBufferPartitionAllocator()34 partition_alloc::PartitionAllocator& GetArrayBufferPartitionAllocator() {
35 return g_allocators->array_buffer_allocator;
36 }
37 #endif
38
GetGeneralPartitionAllocator()39 partition_alloc::PartitionAllocator& GetGeneralPartitionAllocator() {
40 return g_allocators->general_allocator;
41 }
42
GetStringPartitionAllocator()43 partition_alloc::PartitionAllocator& GetStringPartitionAllocator() {
44 return g_allocators->string_allocator;
45 }
46
47 } // namespace
48
49 namespace pdfium::internal {
50
Alloc(size_t num_members,size_t member_size)51 void* Alloc(size_t num_members, size_t member_size) {
52 FX_SAFE_SIZE_T total = member_size;
53 total *= num_members;
54 if (!total.IsValid())
55 return nullptr;
56
57 return GetGeneralPartitionAllocator()
58 .root()
59 ->AllocInline<partition_alloc::AllocFlags::kReturnNull>(
60 total.ValueOrDie(), "GeneralPartition");
61 }
62
Calloc(size_t num_members,size_t member_size)63 void* Calloc(size_t num_members, size_t member_size) {
64 FX_SAFE_SIZE_T total = member_size;
65 total *= num_members;
66 if (!total.IsValid())
67 return nullptr;
68
69 return GetGeneralPartitionAllocator()
70 .root()
71 ->AllocInline<partition_alloc::AllocFlags::kReturnNull |
72 partition_alloc::AllocFlags::kZeroFill>(total.ValueOrDie(),
73 "GeneralPartition");
74 }
75
Realloc(void * ptr,size_t num_members,size_t member_size)76 void* Realloc(void* ptr, size_t num_members, size_t member_size) {
77 FX_SAFE_SIZE_T size = num_members;
78 size *= member_size;
79 if (!size.IsValid())
80 return nullptr;
81
82 return GetGeneralPartitionAllocator()
83 .root()
84 ->Realloc<partition_alloc::AllocFlags::kReturnNull>(
85 ptr, size.ValueOrDie(), "GeneralPartition");
86 }
87
Dealloc(void * ptr)88 void Dealloc(void* ptr) {
89 // TODO(palmer): Removing this check exposes crashes when PDFium callers
90 // attempt to free |nullptr|. Although libc's |free| allows freeing |NULL|, no
91 // other Partition Alloc callers need this tolerant behavior. Additionally,
92 // checking for |nullptr| adds a branch to |PartitionFree|, and it's nice to
93 // not have to have that.
94 //
95 // So this check is hiding (what I consider to be) bugs, and we should try to
96 // fix them. https://bugs.chromium.org/p/pdfium/issues/detail?id=690
97 if (ptr) {
98 GetGeneralPartitionAllocator().root()->Free(ptr);
99 }
100 }
101
StringAlloc(size_t num_members,size_t member_size)102 void* StringAlloc(size_t num_members, size_t member_size) {
103 FX_SAFE_SIZE_T total = member_size;
104 total *= num_members;
105 if (!total.IsValid())
106 return nullptr;
107
108 return GetStringPartitionAllocator()
109 .root()
110 ->AllocInline<partition_alloc::AllocFlags::kReturnNull>(
111 total.ValueOrDie(), "StringPartition");
112 }
113
StringDealloc(void * ptr)114 void StringDealloc(void* ptr) {
115 // TODO(palmer): Removing this check exposes crashes when PDFium callers
116 // attempt to free |nullptr|. Although libc's |free| allows freeing |NULL|, no
117 // other Partition Alloc callers need this tolerant behavior. Additionally,
118 // checking for |nullptr| adds a branch to |PartitionFree|, and it's nice to
119 // not have to have that.
120 //
121 // So this check is hiding (what I consider to be) bugs, and we should try to
122 // fix them. https://bugs.chromium.org/p/pdfium/issues/detail?id=690
123 if (ptr) {
124 GetStringPartitionAllocator().root()->Free(ptr);
125 }
126 }
127
128 } // namespace pdfium::internal
129
FX_InitializeMemoryAllocators()130 void FX_InitializeMemoryAllocators() {
131 if (!g_allocators) {
132 g_allocators = new Allocators();
133 }
134 }
135
FX_DestroyMemoryAllocators()136 void FX_DestroyMemoryAllocators() {
137 delete g_allocators;
138 g_allocators = nullptr;
139 }
140
141 #ifndef V8_ENABLE_SANDBOX
FX_ArrayBufferAllocate(size_t length)142 void* FX_ArrayBufferAllocate(size_t length) {
143 return GetArrayBufferPartitionAllocator()
144 .root()
145 ->AllocInline<partition_alloc::AllocFlags::kZeroFill>(length,
146 "FXArrayBuffer");
147 }
148
FX_ArrayBufferAllocateUninitialized(size_t length)149 void* FX_ArrayBufferAllocateUninitialized(size_t length) {
150 return GetArrayBufferPartitionAllocator().root()->Alloc(length,
151 "FXArrayBuffer");
152 }
153
FX_ArrayBufferFree(void * data)154 void FX_ArrayBufferFree(void* data) {
155 GetArrayBufferPartitionAllocator().root()->Free(data);
156 }
157 #endif // V8_ENABLE_SANDBOX
158