[RTL] Add support for vectored continue handlers, complementing the vectored exceptio...
[reactos.git] / reactos / lib / rtl / vectoreh.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS sysem libraries
4 * PURPOSE: Vectored Exception Handling
5 * FILE: lib/rtl/vectoreh.c
6 * PROGRAMERS: Thomas Weidenmueller
7 */
8
9 /* INCLUDES *****************************************************************/
10
11 #include <rtl.h>
12
13 #define NDEBUG
14 #include <debug.h>
15
16 RTL_CRITICAL_SECTION RtlpVectoredHandlerLock;
17 LIST_ENTRY RtlpVectoredExceptionList, RtlpVectoredContinueList;
18
19 typedef struct _RTL_VECTORED_HANDLER_ENTRY
20 {
21 LIST_ENTRY ListEntry;
22 PVECTORED_EXCEPTION_HANDLER VectoredHandler;
23 ULONG Refs;
24 } RTL_VECTORED_HANDLER_ENTRY, *PRTL_VECTORED_HANDLER_ENTRY;
25
26 /* FUNCTIONS ***************************************************************/
27
28 VOID
29 NTAPI
30 RtlpInitializeVectoredExceptionHandling(VOID)
31 {
32 /* Initialize our two lists and the common lock */
33 RtlInitializeCriticalSection(&RtlpVectoredHandlerLock);
34 InitializeListHead(&RtlpVectoredExceptionList);
35 InitializeListHead(&RtlpVectoredContinueList);
36 }
37
38 BOOLEAN
39 NTAPI
40 RtlpCallVectoredHandlers(IN PEXCEPTION_RECORD ExceptionRecord,
41 IN PCONTEXT Context,
42 IN PLIST_ENTRY VectoredHandlerList)
43 {
44 PLIST_ENTRY CurrentEntry;
45 PRTL_VECTORED_HANDLER_ENTRY VectoredExceptionHandler;
46 PVECTORED_EXCEPTION_HANDLER VectoredHandler;
47 EXCEPTION_POINTERS ExceptionInfo;
48 BOOLEAN HandlerRemoved;
49 LONG HandlerReturn;
50
51 /*
52 * Initialize these in case there are no entries,
53 * or if no one handled the exception
54 */
55 HandlerRemoved = FALSE;
56 HandlerReturn = EXCEPTION_CONTINUE_SEARCH;
57
58 /* Set up the data to pass to the handler */
59 ExceptionInfo.ExceptionRecord = ExceptionRecord;
60 ExceptionInfo.ContextRecord = Context;
61
62 /* Grab the lock */
63 RtlEnterCriticalSection(&RtlpVectoredHandlerLock);
64
65 /* Loop entries */
66 CurrentEntry = VectoredHandlerList->Flink;
67 while (CurrentEntry != VectoredHandlerList)
68 {
69 /* Get the struct */
70 VectoredExceptionHandler = CONTAINING_RECORD(CurrentEntry,
71 RTL_VECTORED_HANDLER_ENTRY,
72 ListEntry);
73
74 /* Reference it so it doesn't go away while we are using it */
75 VectoredExceptionHandler->Refs++;
76
77 /* Drop the lock before calling the handler */
78 RtlLeaveCriticalSection(&RtlpVectoredHandlerLock);
79
80 /*
81 * Get the function pointer, decoding it so we will crash
82 * if malicious code has altered it. That is, if something has
83 * set VectoredHandler to a non-encoded pointer
84 */
85 VectoredHandler = RtlDecodePointer(VectoredExceptionHandler->VectoredHandler);
86
87 /* Call the handler */
88 HandlerReturn = VectoredHandler(&ExceptionInfo);
89
90 /* Handler called -- grab the lock to dereference */
91 RtlEnterCriticalSection(&RtlpVectoredHandlerLock);
92
93 /* Dereference and see if it got deleted */
94 VectoredExceptionHandler->Refs--;
95 if (VectoredExceptionHandler->Refs == 0)
96 {
97 /* It did -- do we have to free it now? */
98 if (HandlerReturn == EXCEPTION_CONTINUE_EXECUTION)
99 {
100 /* We don't, just remove it from the list and break out */
101 RemoveEntryList(&VectoredExceptionHandler->ListEntry);
102 HandlerRemoved = TRUE;
103 break;
104 }
105
106 /*
107 * Get the next entry before freeing,
108 * and remove the current one from the list
109 */
110 CurrentEntry = VectoredExceptionHandler->ListEntry.Flink;
111 RemoveEntryList(&VectoredExceptionHandler->ListEntry);
112
113 /* Free the entry outside of the lock, then reacquire it */
114 RtlLeaveCriticalSection(&RtlpVectoredHandlerLock);
115 RtlFreeHeap(RtlGetProcessHeap(),
116 0,
117 VectoredExceptionHandler);
118 RtlEnterCriticalSection(&RtlpVectoredHandlerLock);
119 }
120 else
121 {
122 /* No delete -- should we continue execution? */
123 if (HandlerReturn == EXCEPTION_CONTINUE_EXECUTION)
124 {
125 /* Break out */
126 break;
127 }
128 else
129 {
130 /* Continue searching the list */
131 CurrentEntry = CurrentEntry->Flink;
132 }
133 }
134 }
135
136 /* Let go of the lock now */
137 RtlLeaveCriticalSection(&RtlpVectoredHandlerLock);
138
139 /* Anything to free? */
140 if (HandlerRemoved)
141 {
142 /* Get rid of it */
143 RtlFreeHeap(RtlGetProcessHeap(),
144 0,
145 VectoredExceptionHandler);
146 }
147
148 /* Return whether to continue execution (ignored for continue handlers) */
149 return (HandlerReturn == EXCEPTION_CONTINUE_EXECUTION) ? TRUE : FALSE;
150 }
151
152 PVOID
153 NTAPI
154 RtlpAddVectoredHandler(IN ULONG FirstHandler,
155 IN PVECTORED_EXCEPTION_HANDLER VectoredHandler,
156 IN PLIST_ENTRY VectoredHandlerList)
157 {
158 PRTL_VECTORED_HANDLER_ENTRY VectoredHandlerEntry;
159
160 /* Allocate our structure */
161 VectoredHandlerEntry = RtlAllocateHeap(RtlGetProcessHeap(),
162 0,
163 sizeof(RTL_VECTORED_HANDLER_ENTRY));
164 if (!VectoredHandlerEntry) return NULL;
165
166 /* Set it up, encoding the pointer for security */
167 VectoredHandlerEntry->VectoredHandler = RtlEncodePointer(VectoredHandler);
168 VectoredHandlerEntry->Refs = 1;
169
170 /* Lock the list before modifying it */
171 RtlEnterCriticalSection(&RtlpVectoredHandlerLock);
172
173 /*
174 * While holding the list lock, insert the handler
175 * at beginning or end of list according to caller.
176 */
177 if (FirstHandler)
178 {
179 InsertHeadList(VectoredHandlerList,
180 &VectoredHandlerEntry->ListEntry);
181 }
182 else
183 {
184 InsertTailList(VectoredHandlerList,
185 &VectoredHandlerEntry->ListEntry);
186 }
187
188 /* Done with the list, unlock it */
189 RtlLeaveCriticalSection(&RtlpVectoredHandlerLock);
190
191 /* Return pointer to the structure as the handle */
192 return VectoredHandlerEntry;
193 }
194
195 ULONG
196 NTAPI
197 RtlpRemoveVectoredHandler(IN PVOID VectoredHandlerHandle,
198 IN PLIST_ENTRY VectoredHandlerList)
199 {
200 PLIST_ENTRY CurrentEntry;
201 PRTL_VECTORED_HANDLER_ENTRY VectoredExceptionHandler;
202 BOOLEAN HandlerRemoved;
203 BOOLEAN HandlerFound;
204
205 /* Initialize these in case we don't find anything */
206 HandlerRemoved = FALSE;
207 HandlerFound = FALSE;
208
209 /* Acquire list lock */
210 RtlEnterCriticalSection(&RtlpVectoredHandlerLock);
211
212 /* Loop the list */
213 CurrentEntry = VectoredHandlerList->Flink;
214 while (CurrentEntry != VectoredHandlerList)
215 {
216 /* Get the struct */
217 VectoredExceptionHandler = CONTAINING_RECORD(CurrentEntry,
218 RTL_VECTORED_HANDLER_ENTRY,
219 ListEntry);
220
221 /* Does it match? */
222 if (VectoredExceptionHandler == VectoredHandlerHandle)
223 {
224 /*
225 * Great, this means it is a valid entry.
226 * However, it may be in use by the exception
227 * dispatcher, so we have a ref count to respect.
228 * If we can't remove it now then it will be done
229 * right after it is not in use anymore.
230 *
231 * Caller is supposed to keep track of if it has deleted the
232 * entry and should not call us twice for the same entry.
233 * We could maybe throw in some kind of ASSERT to detect this
234 * if this was to become a problem.
235 */
236 VectoredExceptionHandler->Refs--;
237 if (VectoredExceptionHandler->Refs == 0)
238 {
239 /* Not in use, ok to remove and free */
240 RemoveEntryList(&VectoredExceptionHandler->ListEntry);
241 HandlerRemoved = TRUE;
242 }
243
244 /* Found what we are looking for, stop searching */
245 HandlerFound = TRUE;
246 break;
247 }
248 else
249 {
250 /* Get the next entry */
251 CurrentEntry = CurrentEntry->Flink;
252 }
253 }
254
255 /* Done with the list, let go of the lock */
256 RtlLeaveCriticalSection(&RtlpVectoredHandlerLock);
257
258 /* Can we free what we found? */
259 if (HandlerRemoved)
260 {
261 /* Do it */
262 RtlFreeHeap(RtlGetProcessHeap(),
263 0,
264 VectoredExceptionHandler);
265 }
266
267 /* Return whether we found it */
268 return (ULONG)HandlerFound;
269 }
270
271 BOOLEAN
272 NTAPI
273 RtlCallVectoredExceptionHandlers(IN PEXCEPTION_RECORD ExceptionRecord,
274 IN PCONTEXT Context)
275 {
276 /* Call the shared routine */
277 return RtlpCallVectoredHandlers(ExceptionRecord,
278 Context,
279 &RtlpVectoredExceptionList);
280 }
281
282 VOID
283 NTAPI
284 RtlCallVectoredContinueHandlers(IN PEXCEPTION_RECORD ExceptionRecord,
285 IN PCONTEXT Context)
286 {
287 /*
288 * Call the shared routine (ignoring result,
289 * execution always continues at this point)
290 */
291 (VOID)RtlpCallVectoredHandlers(ExceptionRecord,
292 Context,
293 &RtlpVectoredContinueList);
294 }
295
296 DECLSPEC_HOTPATCH
297 PVOID
298 NTAPI
299 RtlAddVectoredExceptionHandler(IN ULONG FirstHandler,
300 IN PVECTORED_EXCEPTION_HANDLER VectoredHandler)
301 {
302 /* Call the shared routine */
303 return RtlpAddVectoredHandler(FirstHandler,
304 VectoredHandler,
305 &RtlpVectoredExceptionList);
306 }
307
308 DECLSPEC_HOTPATCH
309 PVOID
310 NTAPI
311 RtlAddVectoredContinueHandler(IN ULONG FirstHandler,
312 IN PVECTORED_EXCEPTION_HANDLER VectoredHandler)
313 {
314 /* Call the shared routine */
315 return RtlpAddVectoredHandler(FirstHandler,
316 VectoredHandler,
317 &RtlpVectoredContinueList);
318 }
319
320 //DECLSPEC_HOTPATCH
321 ULONG
322 NTAPI
323 RtlRemoveVectoredExceptionHandler(IN PVOID VectoredHandlerHandle)
324 {
325 /* Call the shared routine */
326 return RtlpRemoveVectoredHandler(VectoredHandlerHandle,
327 &RtlpVectoredExceptionList);
328 }
329
330 //DECLSPEC_HOTPATCH
331 ULONG
332 NTAPI
333 RtlRemoveVectoredContinueHandler(IN PVOID VectoredHandlerHandle)
334 {
335 /* Call the shared routine */
336 return RtlpRemoveVectoredHandler(VectoredHandlerHandle,
337 &RtlpVectoredContinueList);
338 }
339
340 /* EOF */