Date: Thu, 3 Oct 1996 08:57:56 +0200 (IST) From: Eli Zaretskii To: DJ Delorie , Charles Sandmann Cc: djgpp-workers AT delorie DOT com Subject: Re: `abort' in nested programs In-Reply-To: <199609291715.NAA00650@delorie.com> Message-Id: Mime-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII On Sun, 29 Sep 1996, DJ Delorie wrote: > > So the call to `atexit' on go32/dpmiexcp.c should be also undone. I can > > submit the patches if necessary. > > Correct, and a forced call put into _exit. Here are the necessary patches to make a call to `abort' safe in nested programs. I also added a small test program to `abort.c' (which is otherwise unchanged) so you can see the difference before and after applying the patches. Since the original `_exit' was an assembly function on `crt0.s', I preferred not to mess with it; so I just renamed it to `__exit' (`___exit' in assembly) and added `_exit' to go32/dpmiexcp.c. I understand that dpmiexcp is always linked in, so that shouldn't be a problem. Am I right on this? Charles, would you please also take a look at these changes to see if I didn't screw anything? Thanks. *** src/libc/crt0/crt0.s~0 Thu Jan 25 02:54:12 1996 --- src/libc/crt0/crt0.s Wed Oct 2 10:36:46 1996 *************** *** 275,283 **** #define FREESEL(x) movw x, %bx; movw $0x0001, %ax; int $0x31 ! .global __exit .align 2 ! __exit: movb 4(%esp), %al exit: movb %al, %cl --- 275,283 ---- #define FREESEL(x) movw x, %bx; movw $0x0001, %ax; int $0x31 ! .global ___exit .align 2 ! ___exit: movb 4(%esp), %al exit: movb %al, %cl *************** *** 297,303 **** int $0x31 /* Free block and selector */ #ifdef MULTIBLOCK 9: movl ___djgpp_memory_handle_pointer, %ebx ! movl $__exit, %esp /* We will free stack! Old init code as temp stack */ jmp 7f 6: subl $8, %ebx movl (%ebx), %edi --- 297,303 ---- int $0x31 /* Free block and selector */ #ifdef MULTIBLOCK 9: movl ___djgpp_memory_handle_pointer, %ebx ! movl $___exit, %esp /* We will free stack! Old init code as temp stack */ jmp 7f 6: subl $8, %ebx movl (%ebx), %edi *** src/libc/crt0/crt0.t~2 Tue Aug 13 19:20:38 1996 --- src/libc/crt0/crt0.txh Wed Oct 2 11:23:00 1996 *************** *** 110,119 **** @subheading Description This function exits the program, returning @var{exit_code} to the ! calling process. No additional processing is done, and any ! @code{atexit} functions are not called. This function is normally ! called only by @code{exit}. Since this does not unhook hardware ! interrupts, this can cause crashes after the program exits. @subheading Return Value --- 110,144 ---- @subheading Description This function exits the program, returning @var{exit_code} to the ! calling process. No additional processing (such as closing file ! descriptors or calls to the static destructor functions) is done, and ! any @code{atexit} functions are not called; only the hardware interrupt ! handlers are unhooked, to prevent system crashes e.g. after a call to ! @code{abort}. This function is normally called only by @code{exit} and ! @code{abort}. ! ! @subheading Return Value ! ! This function does not return. ! ! @c ---------------------------------------------------------------------- ! @node __exit, process ! @subheading Syntax ! ! @example ! #include ! ! void __exit(int exit_code); ! @end example ! ! @subheading Description ! ! This is an internal library function which exits the program, returning ! @var{exit_code} to the calling process. No additional processing is ! done, and any @code{atexit} functions are not called. Since hardware ! interrupts are not unhooked, this can cause crashes after the program ! exits. This function is normally called only by @code{_exit}; do ! @emph{not} call it directly. @subheading Return Value *** src/libc/go32/dpmiexcp.c~1 Sat May 4 19:09:44 1996 --- src/libc/go32/dpmiexcp.c Wed Oct 2 10:32:42 1996 *************** *** 318,324 **** __dpmi_paddr except; __dpmi_meminfo lockmem; int i; - static int veryfirst = 1; for (i = 0; i < SIGMAX; i++) signal_list[i] = (SignalHandler)SIG_DFL; --- 318,323 ---- *************** *** 358,367 **** __dpmi_get_protected_mode_interrupt_vector(9, &__djgpp_old_kbd); __djgpp_exception_toggle(); /* Set new values & save old values */ - if (veryfirst) { - veryfirst = 0; - atexit(__djgpp_exception_toggle); /* Toggle at exit */ - } /* get original video mode and save */ old_video_mode = _farpeekb(_dos_ds, 0x449); } --- 357,362 ---- *************** *** 375,378 **** --- 370,386 ---- else __djgpp_hwint_flags |= 1; return oldenable; + } + + void __attribute__((noreturn)) + _exit(int status) + { + /* We need to restore hardware interrupt handlers even if somebody calls + `_exit' directly, or else we crash the machine in nested programs. + We only toggle the handlers if the original keyboard handler is intact + (otherwise, they might have already toggled them). */ + if (__djgpp_old_kbd.offset32 == kbd_ori.offset32 + && __djgpp_old_kbd.selector == kbd_ori.selector) + __djgpp_exception_toggle (); + __exit (status); } *** src/libc/ansi/stdlib/abort.c~0 Thu Apr 13 09:21:48 1995 --- src/libc/ansi/stdlib/abort.c Wed Oct 2 11:06:30 1996 *************** *** 11,13 **** --- 11,51 ---- _write(STDERR_FILENO, msg, sizeof(msg)-1); _exit(1); } + + #ifdef TEST + + #include + #include + #include + #include + #include + + int main (int argc, char *argv[]) + { + int status = 0; + + errno = 0; + if (argc > 1) + { + if (strcmp (argv[1], "abort") == 0) + abort (); + else if (strcmp (argv[1], "toggle") == 0) + { + __djgpp_exception_toggle (); + abort (); + } + } + else + { + fprintf (stderr, "\tType `%s abort RET'\n" + "or\n" + "\t `%s toggle RET'\n", argv[0], argv[0]); + status = system (""); + } + + fprintf (stderr, "Child returned %d\n", status); + if (errno) + perror ("spawn"); + return 0; + } + #endif