Back to index

glibc  2.9
abort.c
Go to the documentation of this file.
00001 /* Copyright (C) 1991,93,95,96,97,98,2001,02 Free Software Foundation, Inc.
00002    This file is part of the GNU C Library.
00003 
00004    The GNU C Library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Lesser General Public
00006    License as published by the Free Software Foundation; either
00007    version 2.1 of the License, or (at your option) any later version.
00008 
00009    The GNU C Library is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Lesser General Public License for more details.
00013 
00014    You should have received a copy of the GNU Lesser General Public
00015    License along with the GNU C Library; if not, write to the Free
00016    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00017    02111-1307 USA.  */
00018 
00019 #include <bits/libc-lock.h>
00020 #include <signal.h>
00021 #include <stdio.h>
00022 #include <stdlib.h>
00023 #include <string.h>
00024 #include <unistd.h>
00025 
00026 /* Try to get a machine dependent instruction which will make the
00027    program crash.  This is used in case everything else fails.  */
00028 #include <abort-instr.h>
00029 #ifndef ABORT_INSTRUCTION
00030 /* No such instruction is available.  */
00031 # define ABORT_INSTRUCTION
00032 #endif
00033 
00034 #ifdef USE_IN_LIBIO
00035 # include <libio/libioP.h>
00036 # define fflush(s) _IO_flush_all_lockp (0)
00037 #endif
00038 
00039 /* We must avoid to run in circles.  Therefore we remember how far we
00040    already got.  */
00041 static int stage;
00042 
00043 /* We should be prepared for multiple threads trying to run abort.  */
00044 __libc_lock_define_initialized_recursive (static, lock);
00045 
00046 
00047 /* Cause an abnormal program termination with core-dump.  */
00048 void
00049 abort (void)
00050 {
00051   struct sigaction act;
00052   sigset_t sigs;
00053 
00054   /* First acquire the lock.  */
00055   __libc_lock_lock_recursive (lock);
00056 
00057   /* Now it's for sure we are alone.  But recursive calls are possible.  */
00058 
00059   /* Unlock SIGABRT.  */
00060   if (stage == 0)
00061     {
00062       ++stage;
00063       if (__sigemptyset (&sigs) == 0 &&
00064          __sigaddset (&sigs, SIGABRT) == 0)
00065        __sigprocmask (SIG_UNBLOCK, &sigs, (sigset_t *) NULL);
00066     }
00067 
00068   /* Flush all streams.  We cannot close them now because the user
00069      might have registered a handler for SIGABRT.  */
00070   if (stage == 1)
00071     {
00072       ++stage;
00073       fflush (NULL);
00074     }
00075 
00076   /* Send signal which possibly calls a user handler.  */
00077   if (stage == 2)
00078     {
00079       /* This stage is special: we must allow repeated calls of
00080         `abort' when a user defined handler for SIGABRT is installed.
00081         This is risky since the `raise' implementation might also
00082         fail but I don't see another possibility.  */
00083       int save_stage = stage;
00084 
00085       stage = 0;
00086       __libc_lock_unlock_recursive (lock);
00087 
00088       raise (SIGABRT);
00089 
00090       __libc_lock_lock_recursive (lock);
00091       stage = save_stage + 1;
00092     }
00093 
00094   /* There was a handler installed.  Now remove it.  */
00095   if (stage == 3)
00096     {
00097       ++stage;
00098       memset (&act, '\0', sizeof (struct sigaction));
00099       act.sa_handler = SIG_DFL;
00100       __sigfillset (&act.sa_mask);
00101       act.sa_flags = 0;
00102       __sigaction (SIGABRT, &act, NULL);
00103     }
00104 
00105   /* Now close the streams which also flushes the output the user
00106      defined handler might has produced.  */
00107   if (stage == 4)
00108     {
00109       ++stage;
00110       __fcloseall ();
00111     }
00112 
00113   /* Try again.  */
00114   if (stage == 5)
00115     {
00116       ++stage;
00117       raise (SIGABRT);
00118     }
00119 
00120   /* Now try to abort using the system specific command.  */
00121   if (stage == 6)
00122     {
00123       ++stage;
00124       ABORT_INSTRUCTION;
00125     }
00126 
00127   /* If we can't signal ourselves and the abort instruction failed, exit.  */
00128   if (stage == 7)
00129     {
00130       ++stage;
00131       _exit (127);
00132     }
00133 
00134   /* If even this fails try to use the provided instruction to crash
00135      or otherwise make sure we never return.  */
00136   while (1)
00137     /* Try for ever and ever.  */
00138     ABORT_INSTRUCTION;
00139 }
00140 libc_hidden_def (abort)