[9633] | 1 | /*
|
---|
| 2 | * msvcrt.dll exception handling
|
---|
| 3 | *
|
---|
| 4 | * Copyright 2000 Jon Griffiths
|
---|
| 5 | *
|
---|
| 6 | * This library is free software; you can redistribute it and/or
|
---|
| 7 | * modify it under the terms of the GNU Lesser General Public
|
---|
| 8 | * License as published by the Free Software Foundation; either
|
---|
| 9 | * version 2.1 of the License, or (at your option) any later version.
|
---|
| 10 | *
|
---|
| 11 | * This library is distributed in the hope that it will be useful,
|
---|
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
---|
| 14 | * Lesser General Public License for more details.
|
---|
| 15 | *
|
---|
| 16 | * You should have received a copy of the GNU Lesser General Public
|
---|
| 17 | * License along with this library; if not, write to the Free Software
|
---|
| 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
---|
| 19 | *
|
---|
| 20 | * NOTES:
|
---|
| 21 | *
|
---|
| 22 | * See http://www.microsoft.com/msj/0197/exception/exception.htm,
|
---|
| 23 | * but don't believe all of it.
|
---|
| 24 | *
|
---|
| 25 | * FIXME: Incomplete support for nested exceptions/try block cleanup.
|
---|
| 26 | */
|
---|
| 27 |
|
---|
| 28 | #ifdef __WIN32OS2__
|
---|
| 29 | #include <emxheader.h>
|
---|
[10005] | 30 | #include <stdlib.h>
|
---|
| 31 | #include <string.h>
|
---|
[9633] | 32 | #include <winbase.h>
|
---|
| 33 | #else
|
---|
| 34 | #include "config.h"
|
---|
| 35 | #endif
|
---|
| 36 |
|
---|
| 37 | #include "wine/port.h"
|
---|
| 38 |
|
---|
| 39 | #include "winternl.h"
|
---|
| 40 | #include "wine/exception.h"
|
---|
| 41 | #include "thread.h"
|
---|
| 42 | #include "msvcrt.h"
|
---|
| 43 |
|
---|
[10005] | 44 | #include "msvcrt/stdlib.h"
|
---|
[9633] | 45 | #include "msvcrt/setjmp.h"
|
---|
| 46 | #include "excpt.h"
|
---|
| 47 |
|
---|
| 48 |
|
---|
| 49 | #include "wine/debug.h"
|
---|
| 50 |
|
---|
| 51 | WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
|
---|
| 52 |
|
---|
| 53 | typedef void (*MSVCRT_sig_handler_func)(void);
|
---|
| 54 |
|
---|
| 55 | /* VC++ extensions to Win32 SEH */
|
---|
| 56 | typedef struct _SCOPETABLE
|
---|
| 57 | {
|
---|
| 58 | int previousTryLevel;
|
---|
| 59 | int (*lpfnFilter)(PEXCEPTION_POINTERS);
|
---|
| 60 | int (*lpfnHandler)(void);
|
---|
| 61 | } SCOPETABLE, *PSCOPETABLE;
|
---|
| 62 |
|
---|
| 63 | typedef struct _MSVCRT_EXCEPTION_FRAME
|
---|
| 64 | {
|
---|
| 65 | EXCEPTION_FRAME *prev;
|
---|
| 66 | void (*handler)(PEXCEPTION_RECORD, PEXCEPTION_FRAME,
|
---|
| 67 | PCONTEXT, PEXCEPTION_RECORD);
|
---|
| 68 | PSCOPETABLE scopetable;
|
---|
| 69 | int trylevel;
|
---|
| 70 | int _ebp;
|
---|
| 71 | PEXCEPTION_POINTERS xpointers;
|
---|
| 72 | } MSVCRT_EXCEPTION_FRAME;
|
---|
| 73 |
|
---|
| 74 | #define TRYLEVEL_END (-1) /* End of trylevel list */
|
---|
| 75 |
|
---|
| 76 | #if defined(__GNUC__) && defined(__i386__)
|
---|
| 77 | inline static void call_finally_block( void *code_block, void *base_ptr )
|
---|
| 78 | {
|
---|
| 79 | __asm__ __volatile__ ("movl %1,%%ebp; call *%%eax" \
|
---|
| 80 | : : "a" (code_block), "g" (base_ptr));
|
---|
| 81 | }
|
---|
| 82 |
|
---|
| 83 | inline static DWORD call_filter( void *func, void *arg, void *ebp )
|
---|
| 84 | {
|
---|
| 85 | DWORD ret;
|
---|
| 86 | __asm__ __volatile__ ("pushl %%ebp; pushl %3; movl %2,%%ebp; call *%%eax; popl %%ebp; popl %%ebp"
|
---|
| 87 | : "=a" (ret)
|
---|
| 88 | : "0" (func), "g" (ebp), "g" (arg)
|
---|
| 89 | : "ecx", "edx", "memory" );
|
---|
| 90 | return ret;
|
---|
| 91 | }
|
---|
| 92 | #endif
|
---|
| 93 |
|
---|
| 94 | static DWORD MSVCRT_nested_handler(PEXCEPTION_RECORD rec,
|
---|
| 95 | struct __EXCEPTION_FRAME* frame,
|
---|
| 96 | PCONTEXT context WINE_UNUSED,
|
---|
| 97 | struct __EXCEPTION_FRAME** dispatch)
|
---|
| 98 | {
|
---|
| 99 | if (rec->ExceptionFlags & 0x6)
|
---|
| 100 | return ExceptionContinueSearch;
|
---|
| 101 | *dispatch = frame;
|
---|
| 102 | return ExceptionCollidedUnwind;
|
---|
| 103 | }
|
---|
| 104 |
|
---|
| 105 |
|
---|
| 106 | /*********************************************************************
|
---|
| 107 | * _XcptFilter (MSVCRT.@)
|
---|
| 108 | */
|
---|
| 109 | int _XcptFilter(int ex, PEXCEPTION_POINTERS ptr)
|
---|
| 110 | {
|
---|
| 111 | FIXME("(%d,%p)semi-stub\n", ex, ptr);
|
---|
| 112 | return UnhandledExceptionFilter(ptr);
|
---|
| 113 | }
|
---|
| 114 |
|
---|
| 115 | /*********************************************************************
|
---|
| 116 | * _EH_prolog (MSVCRT.@)
|
---|
| 117 | */
|
---|
| 118 | #ifdef __i386__
|
---|
| 119 | /* Provided for VC++ binary compatability only */
|
---|
| 120 | __ASM_GLOBAL_FUNC(_EH_prolog,
|
---|
| 121 | "pushl $-1\n\t"
|
---|
| 122 | "pushl %eax\n\t"
|
---|
| 123 | "pushl %fs:0\n\t"
|
---|
| 124 | "movl %esp, %fs:0\n\t"
|
---|
| 125 | "movl 12(%esp), %eax\n\t"
|
---|
| 126 | "movl %ebp, 12(%esp)\n\t"
|
---|
| 127 | "leal 12(%esp), %ebp\n\t"
|
---|
| 128 | "pushl %eax\n\t"
|
---|
| 129 | "ret");
|
---|
| 130 | #endif
|
---|
| 131 |
|
---|
| 132 | /*******************************************************************
|
---|
| 133 | * _global_unwind2 (MSVCRT.@)
|
---|
| 134 | */
|
---|
| 135 | void _global_unwind2(PEXCEPTION_FRAME frame)
|
---|
| 136 | {
|
---|
| 137 | TRACE("(%p)\n",frame);
|
---|
| 138 | RtlUnwind( frame, 0, 0, 0 );
|
---|
| 139 | }
|
---|
| 140 |
|
---|
| 141 | /*******************************************************************
|
---|
| 142 | * _local_unwind2 (MSVCRT.@)
|
---|
| 143 | */
|
---|
| 144 | void _local_unwind2(MSVCRT_EXCEPTION_FRAME* frame, int trylevel)
|
---|
| 145 | {
|
---|
| 146 | MSVCRT_EXCEPTION_FRAME *curframe = frame;
|
---|
| 147 | EXCEPTION_FRAME reg;
|
---|
| 148 |
|
---|
[10005] | 149 | TRACE("MSVCRT: _local_unwind2 (%p,%d,%d)\n",frame, frame->trylevel, trylevel);
|
---|
[9633] | 150 |
|
---|
| 151 | /* Register a handler in case of a nested exception */
|
---|
| 152 | reg.Handler = (PEXCEPTION_HANDLER)MSVCRT_nested_handler;
|
---|
| 153 | reg.Prev = NtCurrentTeb()->except;
|
---|
| 154 | __wine_push_frame(®);
|
---|
| 155 |
|
---|
| 156 | while (frame->trylevel != TRYLEVEL_END && frame->trylevel != trylevel)
|
---|
| 157 | {
|
---|
| 158 | int curtrylevel = frame->scopetable[frame->trylevel].previousTryLevel;
|
---|
| 159 | curframe = frame;
|
---|
| 160 | curframe->trylevel = curtrylevel;
|
---|
| 161 | if (!frame->scopetable[curtrylevel].lpfnFilter)
|
---|
| 162 | {
|
---|
| 163 | ERR("__try block cleanup not implemented - expect crash!\n");
|
---|
| 164 | /* FIXME: Remove current frame, set ebp, call
|
---|
| 165 | * frame->scopetable[curtrylevel].lpfnHandler()
|
---|
| 166 | */
|
---|
| 167 | }
|
---|
| 168 | }
|
---|
| 169 | __wine_pop_frame(®);
|
---|
| 170 | TRACE("unwound OK\n");
|
---|
| 171 | }
|
---|
| 172 |
|
---|
| 173 | /*********************************************************************
|
---|
| 174 | * _except_handler2 (MSVCRT.@)
|
---|
| 175 | */
|
---|
| 176 | int _except_handler2(PEXCEPTION_RECORD rec,
|
---|
| 177 | PEXCEPTION_FRAME frame,
|
---|
| 178 | PCONTEXT context,
|
---|
| 179 | PEXCEPTION_FRAME* dispatcher)
|
---|
| 180 | {
|
---|
| 181 | FIXME("exception %lx flags=%lx at %p handler=%p %p %p stub\n",
|
---|
| 182 | rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress,
|
---|
| 183 | frame->Handler, context, dispatcher);
|
---|
| 184 | return ExceptionContinueSearch;
|
---|
| 185 | }
|
---|
| 186 |
|
---|
| 187 | /*********************************************************************
|
---|
| 188 | * _except_handler3 (MSVCRT.@)
|
---|
| 189 | */
|
---|
| 190 | int _except_handler3(PEXCEPTION_RECORD rec,
|
---|
| 191 | MSVCRT_EXCEPTION_FRAME* frame,
|
---|
| 192 | PCONTEXT context, void* dispatcher)
|
---|
| 193 | {
|
---|
| 194 | #if defined(__GNUC__) && defined(__i386__)
|
---|
| 195 | long retval;
|
---|
| 196 | int trylevel;
|
---|
| 197 | EXCEPTION_POINTERS exceptPtrs;
|
---|
| 198 | PSCOPETABLE pScopeTable;
|
---|
| 199 |
|
---|
[10005] | 200 | TRACE("MSVCRT: exception %lx flags=%lx at %p handler=%p %p %p semi-stub\n",
|
---|
[9633] | 201 | rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress,
|
---|
| 202 | frame->handler, context, dispatcher);
|
---|
| 203 |
|
---|
| 204 | __asm__ __volatile__ ("cld");
|
---|
| 205 |
|
---|
| 206 | if (rec->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND))
|
---|
| 207 | {
|
---|
| 208 | /* Unwinding the current frame */
|
---|
| 209 | _local_unwind2(frame, TRYLEVEL_END);
|
---|
| 210 | return ExceptionContinueSearch;
|
---|
| 211 | }
|
---|
| 212 | else
|
---|
| 213 | {
|
---|
| 214 | /* Hunting for handler */
|
---|
| 215 | exceptPtrs.ExceptionRecord = rec;
|
---|
| 216 | exceptPtrs.ContextRecord = context;
|
---|
| 217 | *((DWORD *)frame-1) = (DWORD)&exceptPtrs;
|
---|
| 218 | trylevel = frame->trylevel;
|
---|
| 219 | pScopeTable = frame->scopetable;
|
---|
| 220 |
|
---|
| 221 | while (trylevel != TRYLEVEL_END)
|
---|
| 222 | {
|
---|
| 223 | if (pScopeTable[trylevel].lpfnFilter)
|
---|
| 224 | {
|
---|
| 225 | TRACE("filter = %p\n", pScopeTable[trylevel].lpfnFilter);
|
---|
| 226 |
|
---|
| 227 | retval = call_filter( pScopeTable[trylevel].lpfnFilter, &exceptPtrs, &frame->_ebp );
|
---|
| 228 |
|
---|
| 229 | TRACE("filter returned %s\n", retval == EXCEPTION_CONTINUE_EXECUTION ?
|
---|
| 230 | "CONTINUE_EXECUTION" : retval == EXCEPTION_EXECUTE_HANDLER ?
|
---|
| 231 | "EXECUTE_HANDLER" : "CONTINUE_SEARCH");
|
---|
| 232 |
|
---|
| 233 | if (retval == EXCEPTION_CONTINUE_EXECUTION)
|
---|
| 234 | return ExceptionContinueExecution;
|
---|
| 235 |
|
---|
| 236 | if (retval == EXCEPTION_EXECUTE_HANDLER)
|
---|
| 237 | {
|
---|
| 238 | /* Unwind all higher frames, this one will handle the exception */
|
---|
| 239 | _global_unwind2((PEXCEPTION_FRAME)frame);
|
---|
| 240 | _local_unwind2(frame, trylevel);
|
---|
| 241 |
|
---|
| 242 | /* Set our trylevel to the enclosing block, and call the __finally
|
---|
| 243 | * code, which won't return
|
---|
| 244 | */
|
---|
| 245 | frame->trylevel = pScopeTable->previousTryLevel;
|
---|
| 246 | TRACE("__finally block %p\n",pScopeTable[trylevel].lpfnHandler);
|
---|
| 247 | call_finally_block(pScopeTable[trylevel].lpfnHandler, &frame->_ebp);
|
---|
| 248 | ERR("Returned from __finally block - expect crash!\n");
|
---|
| 249 | }
|
---|
| 250 | }
|
---|
| 251 | trylevel = pScopeTable->previousTryLevel;
|
---|
| 252 | }
|
---|
| 253 | }
|
---|
| 254 | #else
|
---|
| 255 | TRACE("exception %lx flags=%lx at %p handler=%p %p %p stub\n",
|
---|
| 256 | rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress,
|
---|
| 257 | frame->handler, context, dispatcher);
|
---|
| 258 | #endif
|
---|
| 259 | return ExceptionContinueSearch;
|
---|
| 260 | }
|
---|
| 261 |
|
---|
| 262 | /*********************************************************************
|
---|
| 263 | * _abnormal_termination (MSVCRT.@)
|
---|
| 264 | */
|
---|
| 265 | int _abnormal_termination(void)
|
---|
| 266 | {
|
---|
| 267 | FIXME("(void)stub\n");
|
---|
| 268 | return 0;
|
---|
| 269 | }
|
---|
| 270 |
|
---|
| 271 | /*
|
---|
| 272 | * setjmp/longjmp implementation
|
---|
| 273 | */
|
---|
| 274 |
|
---|
| 275 | #ifdef __i386__
|
---|
| 276 | #define MSVCRT_JMP_MAGIC 0x56433230 /* ID value for new jump structure */
|
---|
| 277 | typedef void (*MSVCRT_unwind_function)(const void*);
|
---|
| 278 |
|
---|
| 279 | /*
|
---|
| 280 | * The signatures of the setjmp/longjmp functions do not match that
|
---|
| 281 | * declared in the setjmp header so they don't follow the regular naming
|
---|
| 282 | * convention to avoid conflicts.
|
---|
| 283 | */
|
---|
| 284 |
|
---|
| 285 | /*******************************************************************
|
---|
| 286 | * _setjmp (MSVCRT.@)
|
---|
| 287 | */
|
---|
| 288 | #ifdef __WIN32OS2__
|
---|
| 289 | DEFINE_REGS_ENTRYPOINT_1( _MSVCRT__setjmp, EXC_MSVCRT__setjmp, _JUMP_BUFFER);
|
---|
| 290 | void EXC_MSVCRT__setjmp(_JUMP_BUFFER *jmp, CONTEXT86* context)
|
---|
| 291 | #else
|
---|
| 292 | void _MSVCRT__setjmp(_JUMP_BUFFER *jmp, CONTEXT86* context)
|
---|
| 293 | #endif
|
---|
| 294 | {
|
---|
[10005] | 295 | TRACE("MSVCRT: _setjmp (%p)\n",jmp);
|
---|
[9633] | 296 | jmp->Ebp = context->Ebp;
|
---|
| 297 | jmp->Ebx = context->Ebx;
|
---|
| 298 | jmp->Edi = context->Edi;
|
---|
| 299 | jmp->Esi = context->Esi;
|
---|
| 300 | jmp->Esp = context->Esp;
|
---|
| 301 | jmp->Eip = context->Eip;
|
---|
| 302 | jmp->Registration = (unsigned long)NtCurrentTeb()->except;
|
---|
| 303 | if (jmp->Registration == TRYLEVEL_END)
|
---|
| 304 | jmp->TryLevel = TRYLEVEL_END;
|
---|
| 305 | else
|
---|
| 306 | jmp->TryLevel = ((MSVCRT_EXCEPTION_FRAME*)jmp->Registration)->trylevel;
|
---|
| 307 | TRACE("returning 0\n");
|
---|
| 308 | context->Eax=0;
|
---|
| 309 | }
|
---|
| 310 |
|
---|
| 311 | /*******************************************************************
|
---|
| 312 | * _setjmp3 (MSVCRT.@)
|
---|
| 313 | */
|
---|
| 314 | #ifdef __WIN32OS2__
|
---|
| 315 | DEFINE_REGS_ENTRYPOINT_2( _MSVCRT__setjmp3, EXC_MSVCRT__setjmp3, _JUMP_BUFFER *, int );
|
---|
| 316 | void EXC_MSVCRT__setjmp3(_JUMP_BUFFER *jmp, int nb_args, CONTEXT86* context)
|
---|
| 317 | #else
|
---|
| 318 | void _MSVCRT__setjmp3(_JUMP_BUFFER *jmp, int nb_args, CONTEXT86* context)
|
---|
| 319 | #endif
|
---|
| 320 | {
|
---|
[10005] | 321 | TRACE("MSVCRT: _setjmp3 (%p,%d)\n",jmp,nb_args);
|
---|
[9633] | 322 | jmp->Ebp = context->Ebp;
|
---|
| 323 | jmp->Ebx = context->Ebx;
|
---|
| 324 | jmp->Edi = context->Edi;
|
---|
| 325 | jmp->Esi = context->Esi;
|
---|
| 326 | jmp->Esp = context->Esp;
|
---|
| 327 | jmp->Eip = context->Eip;
|
---|
| 328 | jmp->Cookie = MSVCRT_JMP_MAGIC;
|
---|
| 329 | jmp->UnwindFunc = 0;
|
---|
| 330 | jmp->Registration = (unsigned long)NtCurrentTeb()->except;
|
---|
| 331 | if (jmp->Registration == TRYLEVEL_END)
|
---|
| 332 | {
|
---|
| 333 | jmp->TryLevel = TRYLEVEL_END;
|
---|
| 334 | }
|
---|
| 335 | else
|
---|
| 336 | {
|
---|
| 337 | void **args = ((void**)context->Esp)+2;
|
---|
| 338 |
|
---|
| 339 | if (nb_args > 0) jmp->UnwindFunc = (unsigned long)*args++;
|
---|
| 340 | if (nb_args > 1) jmp->TryLevel = (unsigned long)*args++;
|
---|
| 341 | else jmp->TryLevel = ((MSVCRT_EXCEPTION_FRAME*)jmp->Registration)->trylevel;
|
---|
| 342 | if (nb_args > 2)
|
---|
| 343 | {
|
---|
| 344 | size_t size = (nb_args - 2) * sizeof(DWORD);
|
---|
| 345 | memcpy( jmp->UnwindData, args, min( size, sizeof(jmp->UnwindData) ));
|
---|
| 346 | }
|
---|
| 347 | }
|
---|
| 348 | TRACE("returning 0\n");
|
---|
| 349 | context->Eax = 0;
|
---|
| 350 | }
|
---|
| 351 |
|
---|
| 352 | /*********************************************************************
|
---|
| 353 | * longjmp (MSVCRT.@)
|
---|
| 354 | */
|
---|
| 355 | #ifdef __WIN32OS2__
|
---|
| 356 | DEFINE_REGS_ENTRYPOINT_2( _MSVCRT_longjmp, EXC_MSVCRT_longjmp, _JUMP_BUFFER *, int );
|
---|
| 357 | void EXC_MSVCRT_longjmp(_JUMP_BUFFER *jmp, int retval, CONTEXT86* context)
|
---|
| 358 | #else
|
---|
| 359 | void _MSVCRT_longjmp(_JUMP_BUFFER *jmp, int retval, CONTEXT86* context)
|
---|
| 360 | #endif
|
---|
| 361 | {
|
---|
| 362 | unsigned long cur_frame = 0;
|
---|
| 363 |
|
---|
[10005] | 364 | TRACE("MSVCRT: longjmp (%p,%d)\n", jmp, retval);
|
---|
[9633] | 365 |
|
---|
| 366 | cur_frame=(unsigned long)NtCurrentTeb()->except;
|
---|
| 367 | TRACE("cur_frame=%lx\n",cur_frame);
|
---|
| 368 |
|
---|
| 369 | if (cur_frame != jmp->Registration)
|
---|
| 370 | _global_unwind2((PEXCEPTION_FRAME)jmp->Registration);
|
---|
| 371 |
|
---|
| 372 | if (jmp->Registration)
|
---|
| 373 | {
|
---|
| 374 | if (!IsBadReadPtr(&jmp->Cookie, sizeof(long)) &&
|
---|
| 375 | jmp->Cookie == MSVCRT_JMP_MAGIC && jmp->UnwindFunc)
|
---|
| 376 | {
|
---|
| 377 | MSVCRT_unwind_function unwind_func;
|
---|
| 378 |
|
---|
| 379 | unwind_func=(MSVCRT_unwind_function)jmp->UnwindFunc;
|
---|
| 380 | unwind_func(jmp);
|
---|
| 381 | }
|
---|
| 382 | else
|
---|
| 383 | _local_unwind2((MSVCRT_EXCEPTION_FRAME*)jmp->Registration,
|
---|
| 384 | jmp->TryLevel);
|
---|
| 385 | }
|
---|
| 386 |
|
---|
| 387 | if (!retval)
|
---|
| 388 | retval = 1;
|
---|
| 389 |
|
---|
| 390 | TRACE("Jump to %lx returning %d\n",jmp->Eip,retval);
|
---|
| 391 | context->Ebp = jmp->Ebp;
|
---|
| 392 | context->Ebx = jmp->Ebx;
|
---|
| 393 | context->Edi = jmp->Edi;
|
---|
| 394 | context->Esi = jmp->Esi;
|
---|
| 395 | context->Esp = jmp->Esp;
|
---|
| 396 | context->Eip = jmp->Eip;
|
---|
| 397 | context->Eax = retval;
|
---|
| 398 | }
|
---|
| 399 |
|
---|
| 400 | /*********************************************************************
|
---|
| 401 | * _seh_longjmp_unwind (MSVCRT.@)
|
---|
| 402 | */
|
---|
| 403 | void __stdcall _seh_longjmp_unwind(_JUMP_BUFFER *jmp)
|
---|
| 404 | {
|
---|
| 405 | _local_unwind2( (MSVCRT_EXCEPTION_FRAME *)jmp->Registration, jmp->TryLevel );
|
---|
| 406 | }
|
---|
| 407 | #endif /* i386 */
|
---|
| 408 |
|
---|
[10005] | 409 |
|
---|
[9633] | 410 | /*********************************************************************
|
---|
| 411 | * signal (MSVCRT.@)
|
---|
| 412 | */
|
---|
| 413 | void* MSVCRT_signal(int sig, MSVCRT_sig_handler_func func)
|
---|
| 414 | {
|
---|
[10005] | 415 | dprintf(("MSVCRT: signal(%d %p): NOT COMPLETE\n", sig, func));
|
---|
| 416 | return SIG_IGN_W;
|
---|
[9633] | 417 | }
|
---|