Hi All,
I've run into an interrupt related problem with Quicken 2002's installer.
Two 16bit programs launch, one after the other. Each program hooks INT 0, however since our interrupt tables are global to all tasks, the second task retrieves the interrupt vector that the first task set.
The first task exits, and restores the original INT 0 vector. When the second task exits, tries to restore the INT 0 vector set by the first task, which now has an invalid selector, so it crashes.
After a bit of discussion and writing a test program, we discovered that it appears that some interrupt vectors are task local, and some are global. The local ones appear to be stored in the TDB (task descriptor block), in offsets 0x26 - 0x4a.
The attached patch fixes this, though we're not sure that it is correct for DOS programs.
I have enclosed a test program that shows the problem.
Mike
Index: include/task.h =================================================================== RCS file: /cvstrees/crossover/office/wine/include/task.h,v retrieving revision 1.1.1.5 diff -u -r1.1.1.5 task.h --- include/task.h 12 Sep 2003 18:37:36 -0000 1.1.1.5 +++ include/task.h 7 Oct 2003 06:29:43 -0000 @@ -98,13 +98,13 @@ FARPROC16 sighandler WINE_PACKED; /* 26 Signal handler */ FARPROC16 userhandler WINE_PACKED; /* 2a USER signal handler */ FARPROC16 discardhandler WINE_PACKED; /* 2e Handler for GlobalNotify() */ - DWORD int0 WINE_PACKED; /* 32 int 0 (divide by 0) handler */ - DWORD int2 WINE_PACKED; /* 36 int 2 (NMI) handler */ - DWORD int4 WINE_PACKED; /* 3a int 4 (INTO) handler */ - DWORD int6 WINE_PACKED; /* 3e int 6 (invalid opc) handler */ - DWORD int7 WINE_PACKED; /* 42 int 7 (coprocessor) handler */ - DWORD int3e WINE_PACKED; /* 46 int 3e (80x87 emu) handler */ - DWORD int75 WINE_PACKED; /* 4a int 75 (80x87 error) handler */ + FARPROC16 int0 WINE_PACKED; /* 32 int 0 (divide by 0) handler */ + FARPROC16 int2 WINE_PACKED; /* 36 int 2 (NMI) handler */ + FARPROC16 int4 WINE_PACKED; /* 3a int 4 (INTO) handler */ + FARPROC16 int6 WINE_PACKED; /* 3e int 6 (invalid opc) handler */ + FARPROC16 int7 WINE_PACKED; /* 42 int 7 (coprocessor) handler */ + FARPROC16 int3e WINE_PACKED; /* 46 int 3e (80x87 emu) handler */ + FARPROC16 int75 WINE_PACKED; /* 4a int 75 (80x87 error) handler */ DWORD compat_flags WINE_PACKED; /* 4e Compatibility flags */ BYTE unused4[2]; /* 52 */ struct _TEB *teb; /* 54 Pointer to thread database */ Index: dlls/winedos/interrupts.c =================================================================== RCS file: /cvstrees/crossover/office/wine/dlls/winedos/interrupts.c,v retrieving revision 1.1.1.8 diff -u -r1.1.1.8 interrupts.c --- dlls/winedos/interrupts.c 12 Sep 2003 18:37:31 -0000 1.1.1.8 +++ dlls/winedos/interrupts.c 7 Oct 2003 06:29:47 -0000 @@ -25,6 +25,7 @@ #include "wine/winbase16.h"
#include "thread.h" +#include "task.h"
WINE_DEFAULT_DEBUG_CHANNEL(int); WINE_DECLARE_DEBUG_CHANNEL(relay); @@ -541,9 +542,42 @@ */ FARPROC16 DOSVM_GetPMHandler16( BYTE intnum ) { + TDB *pTask; + FARPROC16 proc = 0; + + pTask = TASK_GetCurrent(); + if (pTask) + { + switch( intnum ) + { + case 0x00: + proc = pTask->int0; + break; + case 0x02: + proc = pTask->int2; + break; + case 0x04: + proc = pTask->int4; + break; + case 0x06: + proc = pTask->int6; + break; + case 0x07: + proc = pTask->int7; + break; + case 0x3e: + proc = pTask->int3e; + break; + case 0x75: + proc = pTask->int75; + break; + } + if( proc ) + return proc; + } if (!DOSVM_Vectors16[intnum]) { - FARPROC16 proc = (FARPROC16)MAKESEGPTR( DOSVM_dpmi_segments->int16_sel, + proc = (FARPROC16)MAKESEGPTR( DOSVM_dpmi_segments->int16_sel, DOSVM_STUB_PM16 * intnum ); DOSVM_Vectors16[intnum] = proc; } @@ -558,9 +592,41 @@ */ void DOSVM_SetPMHandler16( BYTE intnum, FARPROC16 handler ) { + TDB *pTask; + TRACE("Set protected mode interrupt vector %02x <- %04x:%04x\n", intnum, HIWORD(handler), LOWORD(handler) ); - DOSVM_Vectors16[intnum] = handler; + + pTask = TASK_GetCurrent(); + if (!pTask) + return; + switch( intnum ) + { + case 0x00: + pTask->int0 = handler; + break; + case 0x02: + pTask->int2 = handler; + break; + case 0x04: + pTask->int4 = handler; + break; + case 0x06: + pTask->int6 = handler; + break; + case 0x07: + pTask->int7 = handler; + break; + case 0x3e: + pTask->int3e = handler; + break; + case 0x75: + pTask->int75 = handler; + break; + default: + DOSVM_Vectors16[intnum] = handler; + break; + } }
#include <stdio.h> #include <windows.h>
void myintfn(void) { }
int PASCAL WinMain(HANDLE hInstance, HANDLE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { int old_seg, old_ofs, new_seg, new_ofs; char str[16]; /* get the old interrupt handler for int 0 */ _asm { push bx push es mov ax,0x3502 int 21h mov old_seg, es mov old_ofs, bx pop es pop bx } /* print it in a message box */ sprintf(str, "old %04x:%04x", old_seg, old_ofs ); MessageBox( 0, str, "Int 02", MB_OK); /* set the new interrupt handler */ _asm { push ds push dx mov ax,0x2502 push cs pop ds mov dx, offset myintfn int 21h pop dx pop ds }
if( !hPrevInstance) WinExec("taskint.exe",SW_SHOW);
/* fetch it back again */ _asm { push bx push es mov ax,0x3502 int 21h mov new_seg, es mov new_ofs, bx pop es pop bx } sprintf(str, "new %04x:%04x", new_seg, new_ofs ); MessageBox( 0, str, "Int 02", MB_OK);
/* now set the original back again */ _asm { push ds push dx mov ax,0x2502 mov ds, old_seg mov dx, old_ofs int 21h pop dx pop ds }
return 0; }