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 | |
42 #include <limits> | |
43 | |
44 #include "wtf/Assertions.h" | |
45 #include "wtf/CryptographicallyRandomNumber.h" | |
46 | |
47 #define ROUNDUP(x, y) ((((x)+((y)-1))/(y))*(y)) | |
48 | |
49 #ifdef NDEBUG | |
50 static void* MaskPtr(void* p, uintptr_t mask) | |
51 { | |
52 return reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(p) ^ mask); | |
53 } | |
54 #endif | |
55 | |
56 namespace WebCore { | |
57 | |
58 #ifndef NDEBUG | |
59 | |
60 const int signature = 0xDBA00AEA; | |
61 const int signatureDead = 0xDBA00AED; | |
62 | |
63 typedef struct { | |
64 RenderArena* arena; | |
65 size_t size; | |
66 int signature; | |
67 } RenderArenaDebugHeader; | |
68 | |
69 static const size_t debugHeaderSize = ARENA_ALIGN(sizeof(RenderArenaDebugHeader)
); | |
70 | |
71 #endif | |
72 | |
73 RenderArena::RenderArena(unsigned arenaSize) | |
74 : m_totalSize(0) | |
75 , m_totalAllocated(0) | |
76 { | |
77 ASSERT(arenaSize > sizeof(Arena) + ARENA_ALIGN_MASK); | |
78 // The underlying Arena class allocates some metadata on top of our | |
79 // requested size. Factor this in so that we can get perfect power-of-two | |
80 // allocation sizes passed to the underlying malloc() call. | |
81 arenaSize -= (sizeof(Arena) + ARENA_ALIGN_MASK); | |
82 // Initialize the arena pool | |
83 INIT_ARENA_POOL(&m_pool, "RenderArena", arenaSize); | |
84 | |
85 // Zero out the recyclers array | |
86 memset(m_recyclers, 0, sizeof(m_recyclers)); | |
87 | |
88 // Mask freelist pointers to detect corruption and stop freelist spraying. | |
89 // We use an arbitray function and rely on ASLR to randomize it. | |
90 // The first value in RenderObject (or any class) is a vtable pointer, which | |
91 // always overlaps with the next pointer. This change guarantees that the | |
92 // masked vtable/next pointer will never point to valid memory. So, we | |
93 // should immediately crash on the first invalid vtable access for a stale | |
94 // RenderObject pointer. | |
95 // See http://download.crowdstrike.com/papers/hes-exploiting-a-coalmine.pdf. | |
96 WTF::cryptographicallyRandomValues(&m_mask, sizeof(m_mask)); | |
97 m_mask |= (static_cast<uintptr_t>(3) << (std::numeric_limits<uintptr_t>::dig
its - 2)) | 1; | |
98 } | |
99 | |
100 RenderArena::~RenderArena() | |
101 { | |
102 FinishArenaPool(&m_pool); | |
103 } | |
104 | |
105 void* RenderArena::allocate(size_t size) | |
106 { | |
107 ASSERT(size <= gMaxRecycledSize - 32); | |
108 m_totalSize += size; | |
109 | |
110 #ifdef ADDRESS_SANITIZER | |
111 return ::malloc(size); | |
112 #elif !defined(NDEBUG) | |
113 // Use standard malloc so that memory debugging tools work. | |
114 ASSERT(this); | |
115 void* block = ::malloc(debugHeaderSize + size); | |
116 RenderArenaDebugHeader* header = static_cast<RenderArenaDebugHeader*>(block)
; | |
117 header->arena = this; | |
118 header->size = size; | |
119 header->signature = signature; | |
120 return static_cast<char*>(block) + debugHeaderSize; | |
121 #else | |
122 // Ensure we have correct alignment for pointers. Important for Tru64 | |
123 size = ROUNDUP(size, sizeof(void*)); | |
124 | |
125 const size_t index = size >> kRecyclerShift; | |
126 | |
127 void* result = m_recyclers[index]; | |
128 if (result) { | |
129 // Need to move to the next object | |
130 void* next = MaskPtr(*((void**)result), m_mask); | |
131 m_recyclers[index] = next; | |
132 } | |
133 | |
134 if (!result) { | |
135 // Allocate a new chunk from the arena | |
136 unsigned bytesAllocated = 0; | |
137 ARENA_ALLOCATE(result, &m_pool, size, &bytesAllocated); | |
138 m_totalAllocated += bytesAllocated; | |
139 } | |
140 | |
141 return result; | |
142 #endif | |
143 } | |
144 | |
145 void RenderArena::free(size_t size, void* ptr) | |
146 { | |
147 ASSERT(size <= gMaxRecycledSize - 32); | |
148 m_totalSize -= size; | |
149 | |
150 #ifdef ADDRESS_SANITIZER | |
151 ::free(ptr); | |
152 #elif !defined(NDEBUG) | |
153 // Use standard free so that memory debugging tools work. | |
154 void* block = static_cast<char*>(ptr) - debugHeaderSize; | |
155 RenderArenaDebugHeader* header = static_cast<RenderArenaDebugHeader*>(block)
; | |
156 ASSERT(header->signature == signature); | |
157 ASSERT_UNUSED(size, header->size == size); | |
158 ASSERT(header->arena == this); | |
159 header->signature = signatureDead; | |
160 ::free(block); | |
161 #else | |
162 // Ensure we have correct alignment for pointers. Important for Tru64 | |
163 size = ROUNDUP(size, sizeof(void*)); | |
164 | |
165 const size_t index = size >> kRecyclerShift; | |
166 void* currentTop = m_recyclers[index]; | |
167 m_recyclers[index] = ptr; | |
168 *((void**)ptr) = MaskPtr(currentTop, m_mask); | |
169 #endif | |
170 } | |
171 | |
172 } // namespace WebCore | |
OLD | NEW |