Ignore:
Timestamp:
Jul 5, 2011, 7:52:42 PM (14 years ago)
Author:
dmik
Message:

kernel32: SEH: Disabled unwinding Win32 exception handlers in response to the OS/2 unwind procedure to prevent endless recursive crashes inside OS2RtlUnwind() happening due to stack corruption under SMP kernel when too many threads are being unwound at once. Closes #37.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/kernel32/exceptions.cpp

    r21647 r21662  
    462462{
    463463  PWINEXCEPTION_FRAME frame, prevFrame, dispatch;
    464   WINEXCEPTION_RECORD record, newrec;
     464  WINEXCEPTION_RECORD record; //, newrec;
    465465  WINCONTEXT          context;
    466466  DWORD               rc;
     
    471471  if (!winteb)
    472472  {
    473       /* We're being called from __seh_handler called upon unwinding the OS/2
    474        * exception chain after the Win32 TIB structure is destroyed. This for
    475        * example happens when we terminate the thread or the process from within
    476        * the __try block. Just ignore this call retur (note that the Win32
    477        * exception chain should be already unwound by this moment). */
    478       dprintf(("KERNEL32: RtlUnwind returning due to zero Win32 TEB.\n"));
     473      dprintf(("KERNEL32: RtlUnwind TEB is NULL\n"));
     474      DebugInt3();
    479475      return 0;
    480476  }
     
    526522        if (pEndFrame && (frame > pEndFrame))
    527523        {
     524#if 0
     525            // TODO
    528526            newrec.ExceptionCode    = STATUS_INVALID_UNWIND_TARGET;
    529527            newrec.ExceptionFlags   = EH_NONCONTINUABLE;
    530528            newrec.ExceptionRecord  = pRecord;
    531529            newrec.NumberParameters = 0;
     530            RtlRaiseException(&newrec, NULL);
     531#else
    532532            dprintf(("KERNEL32: RtlUnwind terminating thread (invalid target).\n"));
    533533            DosExit(EXIT_THREAD, 0);
     534#endif
    534535        }
    535536        if (((void*)frame < winteb->stack_low) ||
     
    537538            (int)frame & 3)
    538539        {
     540#if 0
     541            // TODO
    539542            newrec.ExceptionCode    = STATUS_BAD_STACK;
    540543            newrec.ExceptionFlags   = EH_NONCONTINUABLE;
    541544            newrec.ExceptionRecord  = pRecord;
    542545            newrec.NumberParameters = 0;
     546#else
    543547            dprintf(("KERNEL32: RtlUnwind terminating thread (bad stack).\n"));
    544548            DosExit(EXIT_THREAD, 0);
     549#endif
    545550        }
    546551
     
    548553        dprintf(("KERNEL32: RtlUnwind - calling exception handler %08X", frame->Handler));
    549554        if(frame->Handler) {
     555            // ensure the Win32 FS (may be accessed directly in the handler)
     556            DWORD oldsel = SetReturnFS(winteb->teb_sel);
    550557            rc = EXC_CallHandler(pRecord, frame, &context, &dispatch, frame->Handler, EXC_UnwindHandler );
     558            // restore FS
     559            SetFS(oldsel);
    551560        }
    552561        else {
     
    563572            break;
    564573        default:
     574#if 0
     575            // TODO
    565576            newrec.ExceptionCode    = STATUS_INVALID_DISPOSITION;
    566577            newrec.ExceptionFlags   = EH_NONCONTINUABLE;
    567578            newrec.ExceptionRecord  = pRecord;
    568579            newrec.NumberParameters = 0;
    569             dprintf(("KERNEL32: RtlUnwind terminating thread.\n"));
     580#else
     581            dprintf(("KERNEL32: RtlUnwind terminating thread (invalid disposition).\n"));
    570582            DosExit(EXIT_THREAD, 0);
     583#endif
    571584            break;
    572585        }
    573586        dprintf(("KERNEL32: RtlUnwind (before)- frame=%08X, frame->Prev=%08X", frame, prevFrame));
    574         SetExceptionChain((DWORD)prevFrame);
     587        winteb->except = (void*)prevFrame;
    575588        frame = prevFrame;
    576589        dprintf(("KERNEL32: RtlUnwind (after) - frame=%08X, frame->Prev=%08X", frame,
     
    12091222#endif
    12101223
     1224// borrowed from ntddk.h
     1225extern "C"
     1226void WIN32API RtlUnwind(
     1227        LPVOID,
     1228        LPVOID,
     1229        LPVOID,DWORD);
     1230
    12111231// Assembly wrapper for clearing the direction flag before calling our real
    12121232// exception handler
     
    12341254//        sprintfException(pERepRec, pERegRec, pCtxRec, p, szTrapDump);
    12351255//    }
     1256
     1257    // We have to disable unwinding of the Win32 exception handlers because
     1258    // experiments have shown that when running under SMP kernel the stack
     1259    // becomes corrupt at the time when unwinding takes place: attempts to
     1260    // to follow the exception chain crash when accessing one of the the
     1261    // previous frame. Although it may seem that performing unwinding here
     1262    // (when we are definitely above any Win32 exception frames installed by
     1263    // the application so that the OS could theoretically already discard lower
     1264    // stack areas) is wrong, it's not the case of the crash. First, doing the
     1265    // very same thing from the SEH handler (see comments in sehutil.s), i.e.
     1266    // when the given Win32 stack frame (and all previous ones) is definitely
     1267    // alive, crahes due to the same stack corruption too. Second, when running
     1268    // under UNI kernel, BOTH approaches don't crash (i.e. the stack is fine).
     1269    // This looks like the SMP kernel doesn't manage the stack right during
     1270    // exception handling :( See also http://svn.netlabs.org/odin32/ticket/37.
     1271    //
     1272    // Note that disabling unwinding also breaks support for performing
     1273    // setjmp()/lonjmp() that crosses the bounds of the __try {} block.
     1274#if 0
     1275    if (pERepRec->fHandlerFlags & EH_UNWINDING)
     1276    {
     1277        // unwind the appropriate portion of the Win32 exception chain
     1278        if (pERepRec->fHandlerFlags & EH_EXIT_UNWIND)
     1279        {
     1280            dprintf(("KERNEL32: OS2ExceptionHandler: EH_EXIT_UNWIND, "
     1281                     "unwinding all the Win32 exception chain"));
     1282            RtlUnwind(NULL, 0, 0, 0);
     1283        }
     1284        else
     1285        {
     1286            dprintf(("KERNEL32: OS2ExceptionHandler: EH_UNWINDING, "
     1287                     "unwinding the Win32 exception chain up to 0x%p", pERegRec));
     1288
     1289            // find a Win32 exception frame closest to the OS/2 one (pERegRec)
     1290            // and unwind up to the previous one (to unwind the closest frame
     1291            // itself too as we are definitely jumping out of it)
     1292            TEB *winteb = GetThreadTEB();
     1293            PWINEXCEPTION_FRAME frame = (PWINEXCEPTION_FRAME)winteb->except;
     1294            while (frame != NULL && ((ULONG)frame)!= 0xFFFFFFFF &&
     1295                   ((ULONG)frame) <= ((ULONG)pERegRec))
     1296                frame = __seh_get_prev_frame(frame);
     1297            if (((ULONG)frame) == 0xFFFFFFFF)
     1298                frame = NULL;
     1299
     1300            RtlUnwind(frame, 0, 0, 0);
     1301        }
     1302        goto continuesearch;
     1303    }
     1304#endif
    12361305
    12371306    /* Access violation at a known location */
     
    15171586            if(OSLibDispatchException(pERepRec, pERegRec, pCtxRec, p) == TRUE)
    15181587            {
     1588                dprintf(("KERNEL32: OS2ExceptionHandler: fix and continue\n"));
    15191589                goto continueexecution;
    15201590            }
    15211591            else
    15221592            {
     1593                dprintf(("KERNEL32: OS2ExceptionHandler: continue search\n"));
    15231594                goto continuesearch;
    15241595            }
Note: See TracChangeset for help on using the changeset viewer.