wined3d: Correctly destroy the adapter on format initialization failure in no3d mode.
[wine/zf.git] / dlls / ntdll / exception.c
blobb32665611f1827172237a795353e9371bc061fa2
1 /*
2 * NT exception handling routines
4 * Copyright 1999 Turchanov Sergey
5 * Copyright 1999 Alexandre Julliard
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.
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.
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
22 #include <assert.h>
23 #include <errno.h>
24 #include <signal.h>
25 #include <stdarg.h>
27 #define NONAMELESSUNION
28 #define NONAMELESSSTRUCT
29 #include "ntstatus.h"
30 #define WIN32_NO_STATUS
31 #include "windef.h"
32 #include "winternl.h"
33 #include "wine/exception.h"
34 #include "wine/server.h"
35 #include "wine/list.h"
36 #include "wine/debug.h"
37 #include "excpt.h"
38 #include "ntdll_misc.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(seh);
42 typedef struct
44 struct list entry;
45 PVECTORED_EXCEPTION_HANDLER func;
46 ULONG count;
47 } VECTORED_HANDLER;
49 static struct list vectored_exception_handlers = LIST_INIT(vectored_exception_handlers);
50 static struct list vectored_continue_handlers = LIST_INIT(vectored_continue_handlers);
52 static RTL_CRITICAL_SECTION vectored_handlers_section;
53 static RTL_CRITICAL_SECTION_DEBUG critsect_debug =
55 0, 0, &vectored_handlers_section,
56 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
57 0, 0, { (DWORD_PTR)(__FILE__ ": vectored_handlers_section") }
59 static RTL_CRITICAL_SECTION vectored_handlers_section = { &critsect_debug, -1, 0, 0, 0, 0 };
61 static PRTL_EXCEPTION_FILTER unhandled_exception_filter;
64 static VECTORED_HANDLER *add_vectored_handler( struct list *handler_list, ULONG first,
65 PVECTORED_EXCEPTION_HANDLER func )
67 VECTORED_HANDLER *handler = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*handler) );
68 if (handler)
70 handler->func = RtlEncodePointer( func );
71 handler->count = 1;
72 RtlEnterCriticalSection( &vectored_handlers_section );
73 if (first) list_add_head( handler_list, &handler->entry );
74 else list_add_tail( handler_list, &handler->entry );
75 RtlLeaveCriticalSection( &vectored_handlers_section );
77 return handler;
81 static ULONG remove_vectored_handler( struct list *handler_list, VECTORED_HANDLER *handler )
83 struct list *ptr;
84 ULONG ret = FALSE;
86 RtlEnterCriticalSection( &vectored_handlers_section );
87 LIST_FOR_EACH( ptr, handler_list )
89 VECTORED_HANDLER *curr_handler = LIST_ENTRY( ptr, VECTORED_HANDLER, entry );
90 if (curr_handler == handler)
92 if (!--curr_handler->count) list_remove( ptr );
93 else handler = NULL; /* don't free it yet */
94 ret = TRUE;
95 break;
98 RtlLeaveCriticalSection( &vectored_handlers_section );
99 if (ret) RtlFreeHeap( GetProcessHeap(), 0, handler );
100 return ret;
104 /**********************************************************************
105 * call_vectored_handlers
107 * Call the vectored handlers chain.
109 LONG call_vectored_handlers( EXCEPTION_RECORD *rec, CONTEXT *context )
111 struct list *ptr;
112 LONG ret = EXCEPTION_CONTINUE_SEARCH;
113 EXCEPTION_POINTERS except_ptrs;
114 PVECTORED_EXCEPTION_HANDLER func;
115 VECTORED_HANDLER *handler, *to_free = NULL;
117 except_ptrs.ExceptionRecord = rec;
118 except_ptrs.ContextRecord = context;
120 RtlEnterCriticalSection( &vectored_handlers_section );
121 ptr = list_head( &vectored_exception_handlers );
122 while (ptr)
124 handler = LIST_ENTRY( ptr, VECTORED_HANDLER, entry );
125 handler->count++;
126 func = RtlDecodePointer( handler->func );
127 RtlLeaveCriticalSection( &vectored_handlers_section );
128 RtlFreeHeap( GetProcessHeap(), 0, to_free );
129 to_free = NULL;
131 TRACE( "calling handler at %p code=%x flags=%x\n",
132 func, rec->ExceptionCode, rec->ExceptionFlags );
133 ret = func( &except_ptrs );
134 TRACE( "handler at %p returned %x\n", func, ret );
136 RtlEnterCriticalSection( &vectored_handlers_section );
137 ptr = list_next( &vectored_exception_handlers, ptr );
138 if (!--handler->count) /* removed during execution */
140 list_remove( &handler->entry );
141 to_free = handler;
143 if (ret == EXCEPTION_CONTINUE_EXECUTION) break;
145 RtlLeaveCriticalSection( &vectored_handlers_section );
146 RtlFreeHeap( GetProcessHeap(), 0, to_free );
147 return ret;
151 /*******************************************************************
152 * raise_status
154 * Implementation of RtlRaiseStatus with a specific exception record.
156 void raise_status( NTSTATUS status, EXCEPTION_RECORD *rec )
158 EXCEPTION_RECORD ExceptionRec;
160 ExceptionRec.ExceptionCode = status;
161 ExceptionRec.ExceptionFlags = EH_NONCONTINUABLE;
162 ExceptionRec.ExceptionRecord = rec;
163 ExceptionRec.NumberParameters = 0;
164 for (;;) RtlRaiseException( &ExceptionRec ); /* never returns */
168 /***********************************************************************
169 * RtlRaiseStatus (NTDLL.@)
171 * Raise an exception with ExceptionCode = status
173 void WINAPI RtlRaiseStatus( NTSTATUS status )
175 raise_status( status, NULL );
179 /*******************************************************************
180 * KiRaiseUserExceptionDispatcher (NTDLL.@)
182 void WINAPI KiRaiseUserExceptionDispatcher(void)
184 EXCEPTION_RECORD rec = { NtCurrentTeb()->ExceptionCode };
185 RtlRaiseException( &rec );
189 /*******************************************************************
190 * RtlAddVectoredContinueHandler (NTDLL.@)
192 PVOID WINAPI RtlAddVectoredContinueHandler( ULONG first, PVECTORED_EXCEPTION_HANDLER func )
194 return add_vectored_handler( &vectored_continue_handlers, first, func );
198 /*******************************************************************
199 * RtlRemoveVectoredContinueHandler (NTDLL.@)
201 ULONG WINAPI RtlRemoveVectoredContinueHandler( PVOID handler )
203 return remove_vectored_handler( &vectored_continue_handlers, handler );
207 /*******************************************************************
208 * RtlAddVectoredExceptionHandler (NTDLL.@)
210 PVOID WINAPI DECLSPEC_HOTPATCH RtlAddVectoredExceptionHandler( ULONG first, PVECTORED_EXCEPTION_HANDLER func )
212 return add_vectored_handler( &vectored_exception_handlers, first, func );
216 /*******************************************************************
217 * RtlRemoveVectoredExceptionHandler (NTDLL.@)
219 ULONG WINAPI RtlRemoveVectoredExceptionHandler( PVOID handler )
221 return remove_vectored_handler( &vectored_exception_handlers, handler );
225 /*******************************************************************
226 * RtlSetUnhandledExceptionFilter (NTDLL.@)
228 void WINAPI RtlSetUnhandledExceptionFilter( PRTL_EXCEPTION_FILTER filter )
230 unhandled_exception_filter = filter;
234 /*******************************************************************
235 * call_unhandled_exception_filter
237 LONG WINAPI call_unhandled_exception_filter( PEXCEPTION_POINTERS eptr )
239 if (!unhandled_exception_filter) return EXCEPTION_CONTINUE_SEARCH;
240 return unhandled_exception_filter( eptr );
244 #if defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)
246 struct dynamic_unwind_entry
248 struct list entry;
249 ULONG_PTR base;
250 ULONG_PTR end;
251 RUNTIME_FUNCTION *table;
252 DWORD count;
253 DWORD max_count;
254 PGET_RUNTIME_FUNCTION_CALLBACK callback;
255 PVOID context;
258 static struct list dynamic_unwind_list = LIST_INIT(dynamic_unwind_list);
260 static RTL_CRITICAL_SECTION dynamic_unwind_section;
261 static RTL_CRITICAL_SECTION_DEBUG dynamic_unwind_debug =
263 0, 0, &dynamic_unwind_section,
264 { &dynamic_unwind_debug.ProcessLocksList, &dynamic_unwind_debug.ProcessLocksList },
265 0, 0, { (DWORD_PTR)(__FILE__ ": dynamic_unwind_section") }
267 static RTL_CRITICAL_SECTION dynamic_unwind_section = { &dynamic_unwind_debug, -1, 0, 0, 0, 0 };
269 static ULONG_PTR get_runtime_function_end( RUNTIME_FUNCTION *func, ULONG_PTR addr )
271 #ifdef __x86_64__
272 return func->EndAddress;
273 #elif defined(__arm__)
274 if (func->u.s.Flag) return func->BeginAddress + func->u.s.FunctionLength * 2;
275 else
277 struct unwind_info
279 DWORD function_length : 18;
280 DWORD version : 2;
281 DWORD x : 1;
282 DWORD e : 1;
283 DWORD f : 1;
284 DWORD count : 5;
285 DWORD words : 4;
286 } *info = (struct unwind_info *)(addr + func->u.UnwindData);
287 return func->BeginAddress + info->function_length * 2;
289 #else /* __aarch64__ */
290 if (func->u.s.Flag) return func->BeginAddress + func->u.s.FunctionLength * 4;
291 else
293 struct unwind_info
295 DWORD function_length : 18;
296 DWORD version : 2;
297 DWORD x : 1;
298 DWORD e : 1;
299 DWORD epilog : 5;
300 DWORD codes : 5;
301 } *info = (struct unwind_info *)(addr + func->u.UnwindData);
302 return func->BeginAddress + info->function_length * 4;
304 #endif
307 /**********************************************************************
308 * RtlAddFunctionTable (NTDLL.@)
310 BOOLEAN CDECL RtlAddFunctionTable( RUNTIME_FUNCTION *table, DWORD count, ULONG_PTR addr )
312 struct dynamic_unwind_entry *entry;
314 TRACE( "%p %u %lx\n", table, count, addr );
316 /* NOTE: Windows doesn't check if table is aligned or a NULL pointer */
318 entry = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*entry) );
319 if (!entry)
320 return FALSE;
322 entry->base = addr;
323 entry->end = addr + (count ? get_runtime_function_end( &table[count - 1], addr ) : 0);
324 entry->table = table;
325 entry->count = count;
326 entry->max_count = 0;
327 entry->callback = NULL;
328 entry->context = NULL;
330 RtlEnterCriticalSection( &dynamic_unwind_section );
331 list_add_tail( &dynamic_unwind_list, &entry->entry );
332 RtlLeaveCriticalSection( &dynamic_unwind_section );
333 return TRUE;
337 /**********************************************************************
338 * RtlInstallFunctionTableCallback (NTDLL.@)
340 BOOLEAN CDECL RtlInstallFunctionTableCallback( ULONG_PTR table, ULONG_PTR base, DWORD length,
341 PGET_RUNTIME_FUNCTION_CALLBACK callback, PVOID context,
342 PCWSTR dll )
344 struct dynamic_unwind_entry *entry;
346 TRACE( "%lx %lx %d %p %p %s\n", table, base, length, callback, context, wine_dbgstr_w(dll) );
348 /* NOTE: Windows doesn't check if the provided callback is a NULL pointer */
350 /* both low-order bits must be set */
351 if ((table & 0x3) != 0x3)
352 return FALSE;
354 entry = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*entry) );
355 if (!entry)
356 return FALSE;
358 entry->base = base;
359 entry->end = base + length;
360 entry->table = (RUNTIME_FUNCTION *)table;
361 entry->count = 0;
362 entry->max_count = 0;
363 entry->callback = callback;
364 entry->context = context;
366 RtlEnterCriticalSection( &dynamic_unwind_section );
367 list_add_tail( &dynamic_unwind_list, &entry->entry );
368 RtlLeaveCriticalSection( &dynamic_unwind_section );
370 return TRUE;
374 /*************************************************************************
375 * RtlAddGrowableFunctionTable (NTDLL.@)
377 DWORD WINAPI RtlAddGrowableFunctionTable( void **table, RUNTIME_FUNCTION *functions, DWORD count,
378 DWORD max_count, ULONG_PTR base, ULONG_PTR end )
380 struct dynamic_unwind_entry *entry;
382 TRACE( "%p, %p, %u, %u, %lx, %lx\n", table, functions, count, max_count, base, end );
384 entry = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*entry) );
385 if (!entry)
386 return STATUS_NO_MEMORY;
388 entry->base = base;
389 entry->end = end;
390 entry->table = functions;
391 entry->count = count;
392 entry->max_count = max_count;
393 entry->callback = NULL;
394 entry->context = NULL;
396 RtlEnterCriticalSection( &dynamic_unwind_section );
397 list_add_tail( &dynamic_unwind_list, &entry->entry );
398 RtlLeaveCriticalSection( &dynamic_unwind_section );
400 *table = entry;
402 return STATUS_SUCCESS;
406 /*************************************************************************
407 * RtlGrowFunctionTable (NTDLL.@)
409 void WINAPI RtlGrowFunctionTable( void *table, DWORD count )
411 struct dynamic_unwind_entry *entry;
413 TRACE( "%p, %u\n", table, count );
415 RtlEnterCriticalSection( &dynamic_unwind_section );
416 LIST_FOR_EACH_ENTRY( entry, &dynamic_unwind_list, struct dynamic_unwind_entry, entry )
418 if (entry == table)
420 if (count > entry->count && count <= entry->max_count)
421 entry->count = count;
422 break;
425 RtlLeaveCriticalSection( &dynamic_unwind_section );
429 /*************************************************************************
430 * RtlDeleteGrowableFunctionTable (NTDLL.@)
432 void WINAPI RtlDeleteGrowableFunctionTable( void *table )
434 struct dynamic_unwind_entry *entry, *to_free = NULL;
436 TRACE( "%p\n", table );
438 RtlEnterCriticalSection( &dynamic_unwind_section );
439 LIST_FOR_EACH_ENTRY( entry, &dynamic_unwind_list, struct dynamic_unwind_entry, entry )
441 if (entry == table)
443 to_free = entry;
444 list_remove( &entry->entry );
445 break;
448 RtlLeaveCriticalSection( &dynamic_unwind_section );
450 RtlFreeHeap( GetProcessHeap(), 0, to_free );
454 /**********************************************************************
455 * RtlDeleteFunctionTable (NTDLL.@)
457 BOOLEAN CDECL RtlDeleteFunctionTable( RUNTIME_FUNCTION *table )
459 struct dynamic_unwind_entry *entry, *to_free = NULL;
461 TRACE( "%p\n", table );
463 RtlEnterCriticalSection( &dynamic_unwind_section );
464 LIST_FOR_EACH_ENTRY( entry, &dynamic_unwind_list, struct dynamic_unwind_entry, entry )
466 if (entry->table == table)
468 to_free = entry;
469 list_remove( &entry->entry );
470 break;
473 RtlLeaveCriticalSection( &dynamic_unwind_section );
475 if (!to_free) return FALSE;
477 RtlFreeHeap( GetProcessHeap(), 0, to_free );
478 return TRUE;
482 /* helper for lookup_function_info() */
483 static RUNTIME_FUNCTION *find_function_info( ULONG_PTR pc, ULONG_PTR base,
484 RUNTIME_FUNCTION *func, ULONG size )
486 int min = 0;
487 int max = size - 1;
489 while (min <= max)
491 #ifdef __x86_64__
492 int pos = (min + max) / 2;
493 if (pc < base + func[pos].BeginAddress) max = pos - 1;
494 else if (pc >= base + func[pos].EndAddress) min = pos + 1;
495 else
497 func += pos;
498 while (func->UnwindData & 1) /* follow chained entry */
499 func = (RUNTIME_FUNCTION *)(base + (func->UnwindData & ~1));
500 return func;
502 #elif defined(__arm__)
503 int pos = (min + max) / 2;
504 if (pc < base + (func[pos].BeginAddress & ~1)) max = pos - 1;
505 else if (pc >= base + get_runtime_function_end( &func[pos], base )) min = pos + 1;
506 else return func + pos;
507 #else /* __aarch64__ */
508 int pos = (min + max) / 2;
509 if (pc < base + func[pos].BeginAddress) max = pos - 1;
510 else if (pc >= base + get_runtime_function_end( &func[pos], base )) min = pos + 1;
511 else return func + pos;
512 #endif
514 return NULL;
517 /**********************************************************************
518 * lookup_function_info
520 RUNTIME_FUNCTION *lookup_function_info( ULONG_PTR pc, ULONG_PTR *base, LDR_DATA_TABLE_ENTRY **module )
522 RUNTIME_FUNCTION *func = NULL;
523 struct dynamic_unwind_entry *entry;
524 ULONG size;
526 /* PE module or wine module */
527 if (!LdrFindEntryForAddress( (void *)pc, module ))
529 *base = (ULONG_PTR)(*module)->DllBase;
530 if ((func = RtlImageDirectoryEntryToData( (*module)->DllBase, TRUE,
531 IMAGE_DIRECTORY_ENTRY_EXCEPTION, &size )))
533 /* lookup in function table */
534 func = find_function_info( pc, (ULONG_PTR)(*module)->DllBase, func, size/sizeof(*func) );
537 else
539 *module = NULL;
541 RtlEnterCriticalSection( &dynamic_unwind_section );
542 LIST_FOR_EACH_ENTRY( entry, &dynamic_unwind_list, struct dynamic_unwind_entry, entry )
544 if (pc >= entry->base && pc < entry->end)
546 *base = entry->base;
547 /* use callback or lookup in function table */
548 if (entry->callback)
549 func = entry->callback( pc, entry->context );
550 else
551 func = find_function_info( pc, entry->base, entry->table, entry->count );
552 break;
555 RtlLeaveCriticalSection( &dynamic_unwind_section );
558 return func;
561 /**********************************************************************
562 * RtlLookupFunctionEntry (NTDLL.@)
564 PRUNTIME_FUNCTION WINAPI RtlLookupFunctionEntry( ULONG_PTR pc, ULONG_PTR *base,
565 UNWIND_HISTORY_TABLE *table )
567 LDR_DATA_TABLE_ENTRY *module;
568 RUNTIME_FUNCTION *func;
570 /* FIXME: should use the history table to make things faster */
572 if (!(func = lookup_function_info( pc, base, &module )))
574 *base = 0;
575 WARN( "no exception table found for %lx\n", pc );
577 return func;
580 #endif /* __x86_64__ || __arm__ || __aarch64__ */
583 /*************************************************************
584 * _assert
586 void __cdecl _assert( const char *str, const char *file, unsigned int line )
588 ERR( "%s:%u: Assertion failed %s\n", file, line, debugstr_a(str) );
589 RtlRaiseStatus( EXCEPTION_WINE_ASSERTION );
593 /*************************************************************
594 * __wine_spec_unimplemented_stub
596 * ntdll-specific implementation to avoid depending on kernel functions.
597 * Can be removed once ntdll.spec no longer contains stubs.
599 void __cdecl __wine_spec_unimplemented_stub( const char *module, const char *function )
601 EXCEPTION_RECORD record;
603 record.ExceptionCode = EXCEPTION_WINE_STUB;
604 record.ExceptionFlags = EH_NONCONTINUABLE;
605 record.ExceptionRecord = NULL;
606 record.ExceptionAddress = __wine_spec_unimplemented_stub;
607 record.NumberParameters = 2;
608 record.ExceptionInformation[0] = (ULONG_PTR)module;
609 record.ExceptionInformation[1] = (ULONG_PTR)function;
610 for (;;) RtlRaiseException( &record );
614 /*************************************************************
615 * IsBadStringPtrA
617 * IsBadStringPtrA replacement for ntdll, to catch exception in debug traces.
619 BOOL WINAPI IsBadStringPtrA( LPCSTR str, UINT_PTR max )
621 if (!str) return TRUE;
622 __TRY
624 volatile const char *p = str;
625 while (p != str + max) if (!*p++) break;
627 __EXCEPT_PAGE_FAULT
629 return TRUE;
631 __ENDTRY
632 return FALSE;
636 /*************************************************************
637 * IsBadStringPtrW
639 * IsBadStringPtrW replacement for ntdll, to catch exception in debug traces.
641 BOOL WINAPI IsBadStringPtrW( LPCWSTR str, UINT_PTR max )
643 if (!str) return TRUE;
644 __TRY
646 volatile const WCHAR *p = str;
647 while (p != str + max) if (!*p++) break;
649 __EXCEPT_PAGE_FAULT
651 return TRUE;
653 __ENDTRY
654 return FALSE;