ntdll: Fix a few memory leaks in tests.
[wine] / dlls / ntdll / exception.c
1 /*
2  * NT exception handling routines
3  *
4  * Copyright 1999 Turchanov Sergey
5  * Copyright 1999 Alexandre Julliard
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 St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include "config.h"
23 #include "wine/port.h"
24
25 #include <assert.h>
26 #include <errno.h>
27 #include <signal.h>
28 #include <stdarg.h>
29
30 #include "ntstatus.h"
31 #define WIN32_NO_STATUS
32 #include "windef.h"
33 #include "winternl.h"
34 #include "wine/exception.h"
35 #include "wine/server.h"
36 #include "wine/list.h"
37 #include "wine/debug.h"
38 #include "excpt.h"
39 #include "ntdll_misc.h"
40
41 WINE_DEFAULT_DEBUG_CHANNEL(seh);
42
43 typedef struct
44 {
45     struct list                 entry;
46     PVECTORED_EXCEPTION_HANDLER func;
47 } VECTORED_HANDLER;
48
49 static struct list vectored_handlers = LIST_INIT(vectored_handlers);
50
51 static RTL_CRITICAL_SECTION vectored_handlers_section;
52 static RTL_CRITICAL_SECTION_DEBUG critsect_debug =
53 {
54     0, 0, &vectored_handlers_section,
55     { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
56       0, 0, { (DWORD_PTR)(__FILE__ ": vectored_handlers_section") }
57 };
58 static RTL_CRITICAL_SECTION vectored_handlers_section = { &critsect_debug, -1, 0, 0, 0, 0 };
59
60 /**********************************************************************
61  *           wait_suspend
62  *
63  * Wait until the thread is no longer suspended.
64  */
65 void wait_suspend( CONTEXT *context )
66 {
67     LARGE_INTEGER timeout;
68     int saved_errno = errno;
69     context_t server_context;
70
71     context_to_server( &server_context, context );
72
73     /* store the context we got at suspend time */
74     SERVER_START_REQ( set_thread_context )
75     {
76         req->handle  = wine_server_obj_handle( GetCurrentThread() );
77         req->suspend = 1;
78         wine_server_add_data( req, &server_context, sizeof(server_context) );
79         wine_server_call( req );
80     }
81     SERVER_END_REQ;
82
83     /* wait with 0 timeout, will only return once the thread is no longer suspended */
84     timeout.QuadPart = 0;
85     NTDLL_wait_for_multiple_objects( 0, NULL, SELECT_INTERRUPTIBLE, &timeout, 0 );
86
87     /* retrieve the new context */
88     SERVER_START_REQ( get_thread_context )
89     {
90         req->handle  = wine_server_obj_handle( GetCurrentThread() );
91         req->suspend = 1;
92         wine_server_set_reply( req, &server_context, sizeof(server_context) );
93         wine_server_call( req );
94     }
95     SERVER_END_REQ;
96
97     context_from_server( context, &server_context );
98     errno = saved_errno;
99 }
100
101
102 /**********************************************************************
103  *           send_debug_event
104  *
105  * Send an EXCEPTION_DEBUG_EVENT event to the debugger.
106  */
107 NTSTATUS send_debug_event( EXCEPTION_RECORD *rec, int first_chance, CONTEXT *context )
108 {
109     NTSTATUS ret;
110     DWORD i;
111     HANDLE handle = 0;
112     client_ptr_t params[EXCEPTION_MAXIMUM_PARAMETERS];
113     context_t server_context;
114
115     if (!NtCurrentTeb()->Peb->BeingDebugged) return 0;  /* no debugger present */
116
117     for (i = 0; i < min( rec->NumberParameters, EXCEPTION_MAXIMUM_PARAMETERS ); i++)
118         params[i] = rec->ExceptionInformation[i];
119
120     context_to_server( &server_context, context );
121
122     SERVER_START_REQ( queue_exception_event )
123     {
124         req->first   = first_chance;
125         req->code    = rec->ExceptionCode;
126         req->flags   = rec->ExceptionFlags;
127         req->record  = wine_server_client_ptr( rec->ExceptionRecord );
128         req->address = wine_server_client_ptr( rec->ExceptionAddress );
129         req->len     = i * sizeof(params[0]);
130         wine_server_add_data( req, params, req->len );
131         wine_server_add_data( req, &server_context, sizeof(server_context) );
132         if (!wine_server_call( req )) handle = wine_server_ptr_handle( reply->handle );
133     }
134     SERVER_END_REQ;
135     if (!handle) return 0;
136
137     NTDLL_wait_for_multiple_objects( 1, &handle, SELECT_INTERRUPTIBLE, NULL, 0 );
138
139     SERVER_START_REQ( get_exception_status )
140     {
141         req->handle = wine_server_obj_handle( handle );
142         wine_server_set_reply( req, &server_context, sizeof(server_context) );
143         ret = wine_server_call( req );
144     }
145     SERVER_END_REQ;
146     if (ret >= 0) context_from_server( context, &server_context );
147     return ret;
148 }
149
150
151 /**********************************************************************
152  *           call_vectored_handlers
153  *
154  * Call the vectored handlers chain.
155  */
156 LONG call_vectored_handlers( EXCEPTION_RECORD *rec, CONTEXT *context )
157 {
158     struct list *ptr;
159     LONG ret = EXCEPTION_CONTINUE_SEARCH;
160     EXCEPTION_POINTERS except_ptrs;
161
162     except_ptrs.ExceptionRecord = rec;
163     except_ptrs.ContextRecord = context;
164
165     RtlEnterCriticalSection( &vectored_handlers_section );
166     LIST_FOR_EACH( ptr, &vectored_handlers )
167     {
168         VECTORED_HANDLER *handler = LIST_ENTRY( ptr, VECTORED_HANDLER, entry );
169         TRACE( "calling handler at %p code=%x flags=%x\n",
170                handler->func, rec->ExceptionCode, rec->ExceptionFlags );
171         ret = handler->func( &except_ptrs );
172         TRACE( "handler at %p returned %x\n", handler->func, ret );
173         if (ret == EXCEPTION_CONTINUE_EXECUTION) break;
174     }
175     RtlLeaveCriticalSection( &vectored_handlers_section );
176     return ret;
177 }
178
179
180 /*******************************************************************
181  *              raise_status
182  *
183  * Implementation of RtlRaiseStatus with a specific exception record.
184  */
185 void raise_status( NTSTATUS status, EXCEPTION_RECORD *rec )
186 {
187     EXCEPTION_RECORD ExceptionRec;
188
189     ExceptionRec.ExceptionCode    = status;
190     ExceptionRec.ExceptionFlags   = EH_NONCONTINUABLE;
191     ExceptionRec.ExceptionRecord  = rec;
192     ExceptionRec.NumberParameters = 0;
193     for (;;) RtlRaiseException( &ExceptionRec );  /* never returns */
194 }
195
196
197 /***********************************************************************
198  *            RtlRaiseStatus  (NTDLL.@)
199  *
200  * Raise an exception with ExceptionCode = status
201  */
202 void WINAPI RtlRaiseStatus( NTSTATUS status )
203 {
204     raise_status( status, NULL );
205 }
206
207
208 /*******************************************************************
209  *         RtlAddVectoredExceptionHandler   (NTDLL.@)
210  */
211 PVOID WINAPI RtlAddVectoredExceptionHandler( ULONG first, PVECTORED_EXCEPTION_HANDLER func )
212 {
213     VECTORED_HANDLER *handler = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*handler) );
214     if (handler)
215     {
216         handler->func = func;
217         RtlEnterCriticalSection( &vectored_handlers_section );
218         if (first) list_add_head( &vectored_handlers, &handler->entry );
219         else list_add_tail( &vectored_handlers, &handler->entry );
220         RtlLeaveCriticalSection( &vectored_handlers_section );
221     }
222     return handler;
223 }
224
225
226 /*******************************************************************
227  *         RtlRemoveVectoredExceptionHandler   (NTDLL.@)
228  */
229 ULONG WINAPI RtlRemoveVectoredExceptionHandler( PVOID handler )
230 {
231     struct list *ptr;
232     ULONG ret = FALSE;
233
234     RtlEnterCriticalSection( &vectored_handlers_section );
235     LIST_FOR_EACH( ptr, &vectored_handlers )
236     {
237         VECTORED_HANDLER *curr_handler = LIST_ENTRY( ptr, VECTORED_HANDLER, entry );
238         if (curr_handler == handler)
239         {
240             list_remove( ptr );
241             ret = TRUE;
242             break;
243         }
244     }
245     RtlLeaveCriticalSection( &vectored_handlers_section );
246     if (ret) RtlFreeHeap( GetProcessHeap(), 0, handler );
247     return ret;
248 }
249
250
251 /*************************************************************
252  *            __wine_spec_unimplemented_stub
253  *
254  * ntdll-specific implementation to avoid depending on kernel functions.
255  * Can be removed once ntdll.spec no longer contains stubs.
256  */
257 void __wine_spec_unimplemented_stub( const char *module, const char *function )
258 {
259     EXCEPTION_RECORD record;
260
261     record.ExceptionCode    = EXCEPTION_WINE_STUB;
262     record.ExceptionFlags   = EH_NONCONTINUABLE;
263     record.ExceptionRecord  = NULL;
264     record.ExceptionAddress = __wine_spec_unimplemented_stub;
265     record.NumberParameters = 2;
266     record.ExceptionInformation[0] = (ULONG_PTR)module;
267     record.ExceptionInformation[1] = (ULONG_PTR)function;
268     for (;;) RtlRaiseException( &record );
269 }