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