We should be OK with the gigacage being disabled on gmalloc
[WebKit-https.git] / Source / bmalloc / bmalloc / Gigacage.cpp
1 /*
2  * Copyright (C) 2017 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #include "Gigacage.h"
27
28 #include "Environment.h"
29 #include "PerProcess.h"
30 #include "VMAllocate.h"
31 #include "Vector.h"
32 #include "bmalloc.h"
33 #include <mutex>
34
35 // FIXME: Ask dyld to put this in its own page, and mprotect the page after we ensure the gigacage.
36 // https://bugs.webkit.org/show_bug.cgi?id=174972
37 void* g_gigacageBasePtr;
38
39 using namespace bmalloc;
40
41 namespace Gigacage {
42
43 struct Callback {
44     Callback() { }
45     
46     Callback(void (*function)(void*), void *argument)
47         : function(function)
48         , argument(argument)
49     {
50     }
51     
52     void (*function)(void*) { nullptr };
53     void* argument { nullptr };
54 };
55
56 struct Callbacks {
57     Callbacks(std::lock_guard<StaticMutex>&) { }
58     
59     Vector<Callback> callbacks;
60 };
61
62 void ensureGigacage()
63 {
64 #if GIGACAGE_ENABLED
65     static std::once_flag onceFlag;
66     std::call_once(
67         onceFlag,
68         [] {
69             if (!shouldBeEnabled())
70                 return;
71             
72             void* basePtr = tryVMAllocate(GIGACAGE_SIZE, GIGACAGE_SIZE + GIGACAGE_RUNWAY);
73             if (!basePtr)
74                 return;
75             
76             vmDeallocatePhysicalPages(basePtr, GIGACAGE_SIZE + GIGACAGE_RUNWAY);
77             
78             g_gigacageBasePtr = basePtr;
79         });
80 #endif // GIGACAGE_ENABLED
81 }
82
83 void disableGigacage()
84 {
85     ensureGigacage();
86     if (!g_gigacageBasePtr) {
87         // It was never enabled. That means that we never even saved any callbacks. Or, we had already disabled
88         // it before, and already called the callbacks.
89         return;
90     }
91     
92     Callbacks& callbacks = *PerProcess<Callbacks>::get();
93     std::unique_lock<StaticMutex> lock(PerProcess<Callbacks>::mutex());
94     for (Callback& callback : callbacks.callbacks)
95         callback.function(callback.argument);
96     callbacks.callbacks.shrink(0);
97     g_gigacageBasePtr = nullptr;
98 }
99
100 void addDisableCallback(void (*function)(void*), void* argument)
101 {
102     ensureGigacage();
103     if (!g_gigacageBasePtr) {
104         // It was already disabled or we were never able to enable it.
105         function(argument);
106         return;
107     }
108     
109     Callbacks& callbacks = *PerProcess<Callbacks>::get();
110     std::unique_lock<StaticMutex> lock(PerProcess<Callbacks>::mutex());
111     callbacks.callbacks.push(Callback(function, argument));
112 }
113
114 void removeDisableCallback(void (*function)(void*), void* argument)
115 {
116     Callbacks& callbacks = *PerProcess<Callbacks>::get();
117     std::unique_lock<StaticMutex> lock(PerProcess<Callbacks>::mutex());
118     for (size_t i = 0; i < callbacks.callbacks.size(); ++i) {
119         if (callbacks.callbacks[i].function == function
120             && callbacks.callbacks[i].argument == argument) {
121             callbacks.callbacks[i] = callbacks.callbacks.last();
122             callbacks.callbacks.pop();
123             return;
124         }
125     }
126 }
127
128 bool shouldBeEnabled()
129 {
130     return GIGACAGE_ENABLED && !PerProcess<Environment>::get()->isDebugHeapEnabled();
131 }
132
133 } // namespace Gigacage
134
135
136