OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (C) 2003 Apple Computer, Inc. | |
3 * Copyright (C) Research In Motion Limited 2010. All rights reserved. | |
4 * | |
5 * Portions are Copyright (C) 1998 Netscape Communications Corporation. | |
6 * | |
7 * This library is free software; you can redistribute it and/or | |
8 * modify it under the terms of the GNU Lesser General Public | |
9 * License as published by the Free Software Foundation; either | |
10 * version 2.1 of the License, or (at your option) any later version. | |
11 * | |
12 * This library is distributed in the hope that it will be useful, | |
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 * Lesser General Public License for more details. | |
16 * | |
17 * You should have received a copy of the GNU Lesser General Public | |
18 * License along with this library; if not, write to the Free Software | |
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 US
A | |
20 * | |
21 * Alternatively, the contents of this file may be used under the terms | |
22 * of either the Mozilla Public License Version 1.1, found at | |
23 * http://www.mozilla.org/MPL/ (the "MPL") or the GNU General Public | |
24 * License Version 2.0, found at http://www.fsf.org/copyleft/gpl.html | |
25 * (the "GPL"), in which case the provisions of the MPL or the GPL are | |
26 * applicable instead of those above. If you wish to allow use of your | |
27 * version of this file only under the terms of one of those two | |
28 * licenses (the MPL or the GPL) and not to allow others to use your | |
29 * version of this file under the LGPL, indicate your decision by | |
30 * deletingthe provisions above and replace them with the notice and | |
31 * other provisions required by the MPL or the GPL, as the case may be. | |
32 * If you do not delete the provisions above, a recipient may use your | |
33 * version of this file under any of the LGPL, the MPL or the GPL. | |
34 */ | |
35 | |
36 #include "config.h" | |
37 #include "core/rendering/RenderArena.h" | |
38 | |
39 #include <stdlib.h> | |
40 #include <string.h> | |
41 #include <limits> | |
42 #include <wtf/Assertions.h> | |
43 #include <wtf/CryptographicallyRandomNumber.h> | |
44 | |
45 #define ROUNDUP(x, y) ((((x)+((y)-1))/(y))*(y)) | |
46 | |
47 #ifdef NDEBUG | |
48 static void* MaskPtr(void* p, uintptr_t mask) | |
49 { | |
50 return reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(p) ^ mask); | |
51 } | |
52 #endif | |
53 | |
54 namespace WebCore { | |
55 | |
56 #ifndef NDEBUG | |
57 | |
58 const int signature = 0xDBA00AEA; | |
59 const int signatureDead = 0xDBA00AED; | |
60 | |
61 typedef struct { | |
62 RenderArena* arena; | |
63 size_t size; | |
64 int signature; | |
65 } RenderArenaDebugHeader; | |
66 | |
67 static const size_t debugHeaderSize = ARENA_ALIGN(sizeof(RenderArenaDebugHeader)
); | |
68 | |
69 #endif | |
70 | |
71 RenderArena::RenderArena(unsigned arenaSize) | |
72 : m_totalSize(0) | |
73 , m_totalAllocated(0) | |
74 { | |
75 ASSERT(arenaSize > sizeof(Arena) + ARENA_ALIGN_MASK); | |
76 // The underlying Arena class allocates some metadata on top of our | |
77 // requested size. Factor this in so that we can get perfect power-of-two | |
78 // allocation sizes passed to the underlying malloc() call. | |
79 arenaSize -= (sizeof(Arena) + ARENA_ALIGN_MASK); | |
80 // Initialize the arena pool | |
81 INIT_ARENA_POOL(&m_pool, "RenderArena", arenaSize); | |
82 | |
83 // Zero out the recyclers array | |
84 memset(m_recyclers, 0, sizeof(m_recyclers)); | |
85 | |
86 // Mask freelist pointers to detect corruption and stop freelist spraying. | |
87 // We use an arbitray function and rely on ASLR to randomize it. | |
88 // The first value in RenderObject (or any class) is a vtable pointer, which | |
89 // always overlaps with the next pointer. This change guarantees that the | |
90 // masked vtable/next pointer will never point to valid memory. So, we | |
91 // should immediately crash on the first invalid vtable access for a stale | |
92 // RenderObject pointer. | |
93 // See http://download.crowdstrike.com/papers/hes-exploiting-a-coalmine.pdf. | |
94 WTF::cryptographicallyRandomValues(&m_mask, sizeof(m_mask)); | |
95 m_mask |= (static_cast<uintptr_t>(3) << (std::numeric_limits<uintptr_t>::dig
its - 2)) | 1; | |
96 } | |
97 | |
98 RenderArena::~RenderArena() | |
99 { | |
100 FinishArenaPool(&m_pool); | |
101 } | |
102 | |
103 void* RenderArena::allocate(size_t size) | |
104 { | |
105 ASSERT(size <= gMaxRecycledSize - 32); | |
106 m_totalSize += size; | |
107 | |
108 #ifdef ADDRESS_SANITIZER | |
109 return ::malloc(size); | |
110 #elif !defined(NDEBUG) | |
111 // Use standard malloc so that memory debugging tools work. | |
112 ASSERT(this); | |
113 void* block = ::malloc(debugHeaderSize + size); | |
114 RenderArenaDebugHeader* header = static_cast<RenderArenaDebugHeader*>(block)
; | |
115 header->arena = this; | |
116 header->size = size; | |
117 header->signature = signature; | |
118 return static_cast<char*>(block) + debugHeaderSize; | |
119 #else | |
120 // Ensure we have correct alignment for pointers. Important for Tru64 | |
121 size = ROUNDUP(size, sizeof(void*)); | |
122 | |
123 const size_t index = size >> kRecyclerShift; | |
124 | |
125 void* result = m_recyclers[index]; | |
126 if (result) { | |
127 // Need to move to the next object | |
128 void* next = MaskPtr(*((void**)result), m_mask); | |
129 m_recyclers[index] = next; | |
130 } | |
131 | |
132 if (!result) { | |
133 // Allocate a new chunk from the arena | |
134 unsigned bytesAllocated = 0; | |
135 ARENA_ALLOCATE(result, &m_pool, size, &bytesAllocated); | |
136 m_totalAllocated += bytesAllocated; | |
137 } | |
138 | |
139 return result; | |
140 #endif | |
141 } | |
142 | |
143 void RenderArena::free(size_t size, void* ptr) | |
144 { | |
145 ASSERT(size <= gMaxRecycledSize - 32); | |
146 m_totalSize -= size; | |
147 | |
148 #ifdef ADDRESS_SANITIZER | |
149 ::free(ptr); | |
150 #elif !defined(NDEBUG) | |
151 // Use standard free so that memory debugging tools work. | |
152 void* block = static_cast<char*>(ptr) - debugHeaderSize; | |
153 RenderArenaDebugHeader* header = static_cast<RenderArenaDebugHeader*>(block)
; | |
154 ASSERT(header->signature == signature); | |
155 ASSERT_UNUSED(size, header->size == size); | |
156 ASSERT(header->arena == this); | |
157 header->signature = signatureDead; | |
158 ::free(block); | |
159 #else | |
160 // Ensure we have correct alignment for pointers. Important for Tru64 | |
161 size = ROUNDUP(size, sizeof(void*)); | |
162 | |
163 const size_t index = size >> kRecyclerShift; | |
164 void* currentTop = m_recyclers[index]; | |
165 m_recyclers[index] = ptr; | |
166 *((void**)ptr) = MaskPtr(currentTop, m_mask); | |
167 #endif | |
168 } | |
169 | |
170 } // namespace WebCore | |
OLD | NEW |