1 /* Copyright (C) 1991-2022 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    <https://www.gnu.org/licenses/>.  */
17 
18 #include <libc-lock.h>
19 #include <signal.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <unistd.h>
24 #include <internal-signals.h>
25 
26 /* Try to get a machine dependent instruction which will make the
27    program crash.  This is used in case everything else fails.  */
28 #include <abort-instr.h>
29 #ifndef ABORT_INSTRUCTION
30 /* No such instruction is available.  */
31 # define ABORT_INSTRUCTION
32 #endif
33 
34 /* Exported variable to locate abort message in core files etc.  */
35 struct abort_msg_s *__abort_msg;
36 libc_hidden_def (__abort_msg)
37 
38 /* We must avoid to run in circles.  Therefore we remember how far we
39    already got.  */
40 static int stage;
41 
42 /* We should be prepared for multiple threads trying to run abort.  */
43 __libc_lock_define_initialized_recursive (static, lock);
44 
45 
46 /* Cause an abnormal program termination with core-dump.  */
47 void
abort(void)48 abort (void)
49 {
50   struct sigaction act;
51 
52   /* First acquire the lock.  */
53   __libc_lock_lock_recursive (lock);
54 
55   /* Now it's for sure we are alone.  But recursive calls are possible.  */
56 
57   /* Unblock SIGABRT.  */
58   if (stage == 0)
59     {
60       ++stage;
61       internal_sigset_t sigs;
62       internal_sigemptyset (&sigs);
63       internal_sigaddset (&sigs, SIGABRT);
64       internal_sigprocmask (SIG_UNBLOCK, &sigs, NULL);
65     }
66 
67   /* Send signal which possibly calls a user handler.  */
68   if (stage == 1)
69     {
70       /* This stage is special: we must allow repeated calls of
71 	 `abort' when a user defined handler for SIGABRT is installed.
72 	 This is risky since the `raise' implementation might also
73 	 fail but I don't see another possibility.  */
74       int save_stage = stage;
75 
76       stage = 0;
77       __libc_lock_unlock_recursive (lock);
78 
79       raise (SIGABRT);
80 
81       __libc_lock_lock_recursive (lock);
82       stage = save_stage + 1;
83     }
84 
85   /* There was a handler installed.  Now remove it.  */
86   if (stage == 2)
87     {
88       ++stage;
89       memset (&act, '\0', sizeof (struct sigaction));
90       act.sa_handler = SIG_DFL;
91       __sigfillset (&act.sa_mask);
92       act.sa_flags = 0;
93       __sigaction (SIGABRT, &act, NULL);
94     }
95 
96   /* Try again.  */
97   if (stage == 3)
98     {
99       ++stage;
100       raise (SIGABRT);
101     }
102 
103   /* Now try to abort using the system specific command.  */
104   if (stage == 4)
105     {
106       ++stage;
107       ABORT_INSTRUCTION;
108     }
109 
110   /* If we can't signal ourselves and the abort instruction failed, exit.  */
111   if (stage == 5)
112     {
113       ++stage;
114       _exit (127);
115     }
116 
117   /* If even this fails try to use the provided instruction to crash
118      or otherwise make sure we never return.  */
119   while (1)
120     /* Try for ever and ever.  */
121     ABORT_INSTRUCTION;
122 }
123 libc_hidden_def (abort)
124