1 /* 2 * msvcrt.dll exception handling 3 * 4 * Copyright 2000 Jon Griffiths 5 * Copyright 2005 Juan Lang 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 * FIXME: Incomplete support for nested exceptions/try block cleanup. 22 */ 23 24 #include "config.h" 25 #include "wine/port.h" 26 27 #include <stdarg.h> 28 29 #include "ntstatus.h" 30 #define WIN32_NO_STATUS 31 #include "windef.h" 32 #include "winbase.h" 33 #include "winternl.h" 34 #include "wine/exception.h" 35 #include "msvcrt.h" 36 #include "excpt.h" 37 #include "wincon.h" 38 #include "wine/debug.h" 39 40 #include "cppexcept.h" 41 42 WINE_DEFAULT_DEBUG_CHANNEL(seh); 43 44 #if _MSVCR_VER>=70 && _MSVCR_VER<=71 45 static MSVCRT_security_error_handler security_error_handler; 46 #endif 47 48 static MSVCRT___sighandler_t sighandlers[MSVCRT_NSIG] = { MSVCRT_SIG_DFL }; 49 50 static BOOL WINAPI msvcrt_console_handler(DWORD ctrlType) 51 { 52 BOOL ret = FALSE; 53 54 switch (ctrlType) 55 { 56 case CTRL_C_EVENT: 57 if (sighandlers[MSVCRT_SIGINT]) 58 { 59 if (sighandlers[MSVCRT_SIGINT] != MSVCRT_SIG_IGN) 60 sighandlers[MSVCRT_SIGINT](MSVCRT_SIGINT); 61 ret = TRUE; 62 } 63 break; 64 } 65 return ret; 66 } 67 68 /********************************************************************* 69 * __pxcptinfoptrs (MSVCRT.@) 70 */ 71 void** CDECL MSVCRT___pxcptinfoptrs(void) 72 { 73 return (void**)&msvcrt_get_thread_data()->xcptinfo; 74 } 75 76 typedef void (CDECL *float_handler)(int, int); 77 78 /* The exception codes are actually NTSTATUS values */ 79 static const struct 80 { 81 NTSTATUS status; 82 int signal; 83 } float_exception_map[] = { 84 { EXCEPTION_FLT_DENORMAL_OPERAND, MSVCRT__FPE_DENORMAL }, 85 { EXCEPTION_FLT_DIVIDE_BY_ZERO, MSVCRT__FPE_ZERODIVIDE }, 86 { EXCEPTION_FLT_INEXACT_RESULT, MSVCRT__FPE_INEXACT }, 87 { EXCEPTION_FLT_INVALID_OPERATION, MSVCRT__FPE_INVALID }, 88 { EXCEPTION_FLT_OVERFLOW, MSVCRT__FPE_OVERFLOW }, 89 { EXCEPTION_FLT_STACK_CHECK, MSVCRT__FPE_STACKOVERFLOW }, 90 { EXCEPTION_FLT_UNDERFLOW, MSVCRT__FPE_UNDERFLOW }, 91 }; 92 93 static LONG msvcrt_exception_filter(struct _EXCEPTION_POINTERS *except) 94 { 95 LONG ret = EXCEPTION_CONTINUE_SEARCH; 96 MSVCRT___sighandler_t handler; 97 98 if (!except || !except->ExceptionRecord) 99 return EXCEPTION_CONTINUE_SEARCH; 100 101 switch (except->ExceptionRecord->ExceptionCode) 102 { 103 case EXCEPTION_ACCESS_VIOLATION: 104 if ((handler = sighandlers[MSVCRT_SIGSEGV]) != MSVCRT_SIG_DFL) 105 { 106 if (handler != MSVCRT_SIG_IGN) 107 { 108 EXCEPTION_POINTERS **ep = (EXCEPTION_POINTERS**)MSVCRT___pxcptinfoptrs(), *old_ep; 109 110 old_ep = *ep; 111 *ep = except; 112 sighandlers[MSVCRT_SIGSEGV] = MSVCRT_SIG_DFL; 113 handler(MSVCRT_SIGSEGV); 114 *ep = old_ep; 115 } 116 ret = EXCEPTION_CONTINUE_EXECUTION; 117 } 118 break; 119 /* According to msdn, 120 * the FPE signal handler takes as a second argument the type of 121 * floating point exception. 122 */ 123 case EXCEPTION_FLT_DENORMAL_OPERAND: 124 case EXCEPTION_FLT_DIVIDE_BY_ZERO: 125 case EXCEPTION_FLT_INEXACT_RESULT: 126 case EXCEPTION_FLT_INVALID_OPERATION: 127 case EXCEPTION_FLT_OVERFLOW: 128 case EXCEPTION_FLT_STACK_CHECK: 129 case EXCEPTION_FLT_UNDERFLOW: 130 if ((handler = sighandlers[MSVCRT_SIGFPE]) != MSVCRT_SIG_DFL) 131 { 132 if (handler != MSVCRT_SIG_IGN) 133 { 134 EXCEPTION_POINTERS **ep = (EXCEPTION_POINTERS**)MSVCRT___pxcptinfoptrs(), *old_ep; 135 unsigned int i; 136 int float_signal = MSVCRT__FPE_INVALID; 137 138 sighandlers[MSVCRT_SIGFPE] = MSVCRT_SIG_DFL; 139 for (i = 0; i < ARRAY_SIZE(float_exception_map); i++) 140 { 141 if (float_exception_map[i].status == 142 except->ExceptionRecord->ExceptionCode) 143 { 144 float_signal = float_exception_map[i].signal; 145 break; 146 } 147 } 148 149 old_ep = *ep; 150 *ep = except; 151 ((float_handler)handler)(MSVCRT_SIGFPE, float_signal); 152 *ep = old_ep; 153 } 154 ret = EXCEPTION_CONTINUE_EXECUTION; 155 } 156 break; 157 case EXCEPTION_ILLEGAL_INSTRUCTION: 158 case EXCEPTION_PRIV_INSTRUCTION: 159 if ((handler = sighandlers[MSVCRT_SIGILL]) != MSVCRT_SIG_DFL) 160 { 161 if (handler != MSVCRT_SIG_IGN) 162 { 163 EXCEPTION_POINTERS **ep = (EXCEPTION_POINTERS**)MSVCRT___pxcptinfoptrs(), *old_ep; 164 165 old_ep = *ep; 166 *ep = except; 167 sighandlers[MSVCRT_SIGILL] = MSVCRT_SIG_DFL; 168 handler(MSVCRT_SIGILL); 169 *ep = old_ep; 170 } 171 ret = EXCEPTION_CONTINUE_EXECUTION; 172 } 173 break; 174 } 175 return ret; 176 } 177 178 void msvcrt_init_signals(void) 179 { 180 SetConsoleCtrlHandler(msvcrt_console_handler, TRUE); 181 } 182 183 void msvcrt_free_signals(void) 184 { 185 SetConsoleCtrlHandler(msvcrt_console_handler, FALSE); 186 } 187 188 /********************************************************************* 189 * signal (MSVCRT.@) 190 * Some signals may never be generated except through an explicit call to 191 * raise. 192 */ 193 MSVCRT___sighandler_t CDECL MSVCRT_signal(int sig, MSVCRT___sighandler_t func) 194 { 195 MSVCRT___sighandler_t ret = MSVCRT_SIG_ERR; 196 197 TRACE("(%d, %p)\n", sig, func); 198 199 if (func == MSVCRT_SIG_ERR) return MSVCRT_SIG_ERR; 200 201 switch (sig) 202 { 203 /* Cases handled internally. Note SIGTERM is never generated by Windows, 204 * so we effectively mask it. 205 */ 206 case MSVCRT_SIGABRT: 207 case MSVCRT_SIGFPE: 208 case MSVCRT_SIGILL: 209 case MSVCRT_SIGSEGV: 210 case MSVCRT_SIGINT: 211 case MSVCRT_SIGTERM: 212 case MSVCRT_SIGBREAK: 213 ret = sighandlers[sig]; 214 sighandlers[sig] = func; 215 break; 216 default: 217 ret = MSVCRT_SIG_ERR; 218 } 219 return ret; 220 } 221 222 /********************************************************************* 223 * raise (MSVCRT.@) 224 */ 225 int CDECL MSVCRT_raise(int sig) 226 { 227 MSVCRT___sighandler_t handler; 228 229 TRACE("(%d)\n", sig); 230 231 switch (sig) 232 { 233 case MSVCRT_SIGFPE: 234 case MSVCRT_SIGILL: 235 case MSVCRT_SIGSEGV: 236 handler = sighandlers[sig]; 237 if (handler == MSVCRT_SIG_DFL) MSVCRT__exit(3); 238 if (handler != MSVCRT_SIG_IGN) 239 { 240 EXCEPTION_POINTERS **ep = (EXCEPTION_POINTERS**)MSVCRT___pxcptinfoptrs(), *old_ep; 241 242 sighandlers[sig] = MSVCRT_SIG_DFL; 243 244 old_ep = *ep; 245 *ep = NULL; 246 if (sig == MSVCRT_SIGFPE) 247 ((float_handler)handler)(sig, MSVCRT__FPE_EXPLICITGEN); 248 else 249 handler(sig); 250 *ep = old_ep; 251 } 252 break; 253 case MSVCRT_SIGABRT: 254 case MSVCRT_SIGINT: 255 case MSVCRT_SIGTERM: 256 case MSVCRT_SIGBREAK: 257 handler = sighandlers[sig]; 258 if (handler == MSVCRT_SIG_DFL) MSVCRT__exit(3); 259 if (handler != MSVCRT_SIG_IGN) 260 { 261 sighandlers[sig] = MSVCRT_SIG_DFL; 262 handler(sig); 263 } 264 break; 265 default: 266 return -1; 267 } 268 return 0; 269 } 270 271 /********************************************************************* 272 * _XcptFilter (MSVCRT.@) 273 */ 274 int CDECL _XcptFilter(NTSTATUS ex, PEXCEPTION_POINTERS ptr) 275 { 276 TRACE("(%08x,%p)\n", ex, ptr); 277 /* I assume ptr->ExceptionRecord->ExceptionCode is the same as ex */ 278 return msvcrt_exception_filter(ptr); 279 } 280 281 #ifndef __REACTOS__ 282 /********************************************************************* 283 * _abnormal_termination (MSVCRT.@) 284 */ 285 int CDECL _abnormal_termination(void) 286 { 287 FIXME("(void)stub\n"); 288 return 0; 289 } 290 #endif /* __REACTOS__ */ 291 292 /****************************************************************** 293 * __uncaught_exception (MSVCRT.@) 294 */ 295 BOOL CDECL MSVCRT___uncaught_exception(void) 296 { 297 return msvcrt_get_thread_data()->processing_throw != 0; 298 } 299 300 #if _MSVCR_VER>=70 && _MSVCR_VER<=71 301 302 /********************************************************************* 303 * _set_security_error_handler (MSVCR70.@) 304 */ 305 MSVCRT_security_error_handler CDECL _set_security_error_handler( 306 MSVCRT_security_error_handler handler ) 307 { 308 MSVCRT_security_error_handler old = security_error_handler; 309 310 TRACE("(%p)\n", handler); 311 312 security_error_handler = handler; 313 return old; 314 } 315 316 /********************************************************************* 317 * __security_error_handler (MSVCR70.@) 318 */ 319 void CDECL __security_error_handler(int code, void *data) 320 { 321 if(security_error_handler) 322 security_error_handler(code, data); 323 else 324 FIXME("(%d, %p) stub\n", code, data); 325 326 MSVCRT__exit(3); 327 } 328 329 #endif /* _MSVCR_VER>=70 && _MSVCR_VER<=71 */ 330 331 #if _MSVCR_VER>=110 332 /********************************************************************* 333 * __crtSetUnhandledExceptionFilter (MSVCR110.@) 334 */ 335 LPTOP_LEVEL_EXCEPTION_FILTER CDECL MSVCR110__crtSetUnhandledExceptionFilter(LPTOP_LEVEL_EXCEPTION_FILTER filter) 336 { 337 return SetUnhandledExceptionFilter(filter); 338 } 339 #endif 340 341 /********************************************************************* 342 * _CreateFrameInfo (MSVCR80.@) 343 */ 344 frame_info* CDECL _CreateFrameInfo(frame_info *fi, void *obj) 345 { 346 thread_data_t *data = msvcrt_get_thread_data(); 347 348 TRACE("(%p, %p)\n", fi, obj); 349 350 fi->next = data->frame_info_head; 351 data->frame_info_head = fi; 352 fi->object = obj; 353 return fi; 354 } 355 356 /********************************************************************* 357 * _FindAndUnlinkFrame (MSVCR80.@) 358 */ 359 void CDECL _FindAndUnlinkFrame(frame_info *fi) 360 { 361 thread_data_t *data = msvcrt_get_thread_data(); 362 frame_info *cur = data->frame_info_head; 363 364 TRACE("(%p)\n", fi); 365 366 if (cur == fi) 367 { 368 data->frame_info_head = cur->next; 369 return; 370 } 371 372 for (; cur->next; cur = cur->next) 373 { 374 if (cur->next == fi) 375 { 376 cur->next = fi->next; 377 return; 378 } 379 } 380 381 ERR("frame not found, native crashes in this case\n"); 382 } 383 384 /********************************************************************* 385 * _IsExceptionObjectToBeDestroyed (MSVCR80.@) 386 */ 387 BOOL __cdecl _IsExceptionObjectToBeDestroyed(const void *obj) 388 { 389 frame_info *cur; 390 391 TRACE( "%p\n", obj ); 392 393 for (cur = msvcrt_get_thread_data()->frame_info_head; cur; cur = cur->next) 394 { 395 if (cur->object == obj) 396 return FALSE; 397 } 398 399 return TRUE; 400 } 401 402 /********************************************************************* 403 * __DestructExceptionObject (MSVCRT.@) 404 */ 405 void CDECL __DestructExceptionObject(EXCEPTION_RECORD *rec) 406 { 407 cxx_exception_type *info = (cxx_exception_type*) rec->ExceptionInformation[2]; 408 void *object = (void*)rec->ExceptionInformation[1]; 409 410 TRACE("(%p)\n", rec); 411 412 if (rec->ExceptionCode != CXX_EXCEPTION) return; 413 #ifndef __x86_64__ 414 if (rec->NumberParameters != 3) return; 415 #else 416 if (rec->NumberParameters != 4) return; 417 #endif 418 if (rec->ExceptionInformation[0] < CXX_FRAME_MAGIC_VC6 || 419 rec->ExceptionInformation[0] > CXX_FRAME_MAGIC_VC8) return; 420 421 if (!info || !info->destructor) 422 return; 423 424 #if defined(__i386__) 425 #ifdef _MSC_VER 426 ((void(__fastcall*)(void*))info->destructor)(object); 427 #else 428 __asm__ __volatile__("call *%0" : : "r" (info->destructor), "c" (object) : "eax", "edx", "memory"); 429 #endif 430 #elif defined(__x86_64__) 431 ((void (__cdecl*)(void*))(info->destructor+rec->ExceptionInformation[3]))(object); 432 #else 433 ((void (__cdecl*)(void*))info->destructor)(object); 434 #endif 435 } 436 437 /********************************************************************* 438 * __CxxRegisterExceptionObject (MSVCRT.@) 439 */ 440 BOOL CDECL __CxxRegisterExceptionObject(EXCEPTION_POINTERS *ep, cxx_frame_info *frame_info) 441 { 442 thread_data_t *data = msvcrt_get_thread_data(); 443 444 TRACE("(%p, %p)\n", ep, frame_info); 445 446 if (!ep || !ep->ExceptionRecord) 447 { 448 frame_info->rec = (void*)-1; 449 frame_info->context = (void*)-1; 450 return TRUE; 451 } 452 453 frame_info->rec = data->exc_record; 454 frame_info->context = data->ctx_record; 455 data->exc_record = ep->ExceptionRecord; 456 data->ctx_record = ep->ContextRecord; 457 _CreateFrameInfo(&frame_info->frame_info, (void*)ep->ExceptionRecord->ExceptionInformation[1]); 458 return TRUE; 459 } 460 461 /********************************************************************* 462 * __CxxUnregisterExceptionObject (MSVCRT.@) 463 */ 464 void CDECL __CxxUnregisterExceptionObject(cxx_frame_info *frame_info, BOOL in_use) 465 { 466 thread_data_t *data = msvcrt_get_thread_data(); 467 468 TRACE("(%p)\n", frame_info); 469 470 if(frame_info->rec == (void*)-1) 471 return; 472 473 _FindAndUnlinkFrame(&frame_info->frame_info); 474 if(data->exc_record->ExceptionCode == CXX_EXCEPTION && !in_use 475 && _IsExceptionObjectToBeDestroyed((void*)data->exc_record->ExceptionInformation[1])) 476 __DestructExceptionObject(data->exc_record); 477 data->exc_record = frame_info->rec; 478 data->ctx_record = frame_info->context; 479 } 480 481 struct __std_exception_data { 482 char *what; 483 MSVCRT_bool dofree; 484 }; 485 486 #if _MSVCR_VER>=140 487 488 /********************************************************************* 489 * __std_exception_copy (UCRTBASE.@) 490 */ 491 void CDECL MSVCRT___std_exception_copy(const struct __std_exception_data *src, 492 struct __std_exception_data *dst) 493 { 494 TRACE("(%p %p)\n", src, dst); 495 496 if(src->dofree && src->what) { 497 dst->what = MSVCRT__strdup(src->what); 498 dst->dofree = 1; 499 } else { 500 dst->what = src->what; 501 dst->dofree = 0; 502 } 503 } 504 505 /********************************************************************* 506 * __std_exception_destroy (UCRTBASE.@) 507 */ 508 void CDECL MSVCRT___std_exception_destroy(struct __std_exception_data *data) 509 { 510 TRACE("(%p)\n", data); 511 512 if(data->dofree) 513 MSVCRT_free(data->what); 514 data->what = NULL; 515 data->dofree = 0; 516 } 517 518 /********************************************************************* 519 * __current_exception (UCRTBASE.@) 520 */ 521 void** CDECL __current_exception(void) 522 { 523 TRACE("()\n"); 524 return (void**)&msvcrt_get_thread_data()->exc_record; 525 } 526 527 /********************************************************************* 528 * __current_exception_context (UCRTBASE.@) 529 */ 530 void** CDECL __current_exception_context(void) 531 { 532 TRACE("()\n"); 533 return (void**)&msvcrt_get_thread_data()->ctx_record; 534 } 535 536 /********************************************************************* 537 * __processing_throw (UCRTBASE.@) 538 */ 539 int* CDECL __processing_throw(void) 540 { 541 TRACE("()\n"); 542 return &msvcrt_get_thread_data()->processing_throw; 543 } 544 545 #endif /* _MSVCR_VER>=140 */ 546