Update copyright notices with scripts/update-copyrights.
[jlayton/glibc.git] / stdlib / abort.c
1 /* Copyright (C) 1991-2013 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3
4    The GNU C Library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Lesser General Public
6    License as published by the Free Software Foundation; either
7    version 2.1 of the License, or (at your option) any later version.
8
9    The GNU C Library is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    Lesser General Public License for more details.
13
14    You should have received a copy of the GNU Lesser General Public
15    License along with the GNU C Library; if not, see
16    <http://www.gnu.org/licenses/>.  */
17
18 #include <bits/libc-lock.h>
19 #include <signal.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <unistd.h>
24
25 /* Try to get a machine dependent instruction which will make the
26    program crash.  This is used in case everything else fails.  */
27 #include <abort-instr.h>
28 #ifndef ABORT_INSTRUCTION
29 /* No such instruction is available.  */
30 # define ABORT_INSTRUCTION
31 #endif
32
33 #include <libio/libioP.h>
34 #define fflush(s) _IO_flush_all_lockp (0)
35
36 /* Exported variable to locate abort message in core files etc.  */
37 struct abort_msg_s *__abort_msg __attribute__ ((nocommon));
38 libc_hidden_def (__abort_msg)
39
40 /* We must avoid to run in circles.  Therefore we remember how far we
41    already got.  */
42 static int stage;
43
44 /* We should be prepared for multiple threads trying to run abort.  */
45 __libc_lock_define_initialized_recursive (static, lock);
46
47
48 /* Cause an abnormal program termination with core-dump.  */
49 void
50 abort (void)
51 {
52   struct sigaction act;
53   sigset_t sigs;
54
55   /* First acquire the lock.  */
56   __libc_lock_lock_recursive (lock);
57
58   /* Now it's for sure we are alone.  But recursive calls are possible.  */
59
60   /* Unlock SIGABRT.  */
61   if (stage == 0)
62     {
63       ++stage;
64       if (__sigemptyset (&sigs) == 0 &&
65           __sigaddset (&sigs, SIGABRT) == 0)
66         __sigprocmask (SIG_UNBLOCK, &sigs, (sigset_t *) NULL);
67     }
68
69   /* Flush all streams.  We cannot close them now because the user
70      might have registered a handler for SIGABRT.  */
71   if (stage == 1)
72     {
73       ++stage;
74       fflush (NULL);
75     }
76
77   /* Send signal which possibly calls a user handler.  */
78   if (stage == 2)
79     {
80       /* This stage is special: we must allow repeated calls of
81          `abort' when a user defined handler for SIGABRT is installed.
82          This is risky since the `raise' implementation might also
83          fail but I don't see another possibility.  */
84       int save_stage = stage;
85
86       stage = 0;
87       __libc_lock_unlock_recursive (lock);
88
89       raise (SIGABRT);
90
91       __libc_lock_lock_recursive (lock);
92       stage = save_stage + 1;
93     }
94
95   /* There was a handler installed.  Now remove it.  */
96   if (stage == 3)
97     {
98       ++stage;
99       memset (&act, '\0', sizeof (struct sigaction));
100       act.sa_handler = SIG_DFL;
101       __sigfillset (&act.sa_mask);
102       act.sa_flags = 0;
103       __sigaction (SIGABRT, &act, NULL);
104     }
105
106   /* Now close the streams which also flushes the output the user
107      defined handler might has produced.  */
108   if (stage == 4)
109     {
110       ++stage;
111       __fcloseall ();
112     }
113
114   /* Try again.  */
115   if (stage == 5)
116     {
117       ++stage;
118       raise (SIGABRT);
119     }
120
121   /* Now try to abort using the system specific command.  */
122   if (stage == 6)
123     {
124       ++stage;
125       ABORT_INSTRUCTION;
126     }
127
128   /* If we can't signal ourselves and the abort instruction failed, exit.  */
129   if (stage == 7)
130     {
131       ++stage;
132       _exit (127);
133     }
134
135   /* If even this fails try to use the provided instruction to crash
136      or otherwise make sure we never return.  */
137   while (1)
138     /* Try for ever and ever.  */
139     ABORT_INSTRUCTION;
140 }
141 libc_hidden_def (abort)