1 | /* |
---|
2 | * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers. |
---|
3 | * All rights reserved. |
---|
4 | * |
---|
5 | * By using this file, you agree to the terms and conditions set |
---|
6 | * forth in the LICENSE file which can be found at the top level of |
---|
7 | * the sendmail distribution. |
---|
8 | * |
---|
9 | */ |
---|
10 | |
---|
11 | #include <sm/gen.h> |
---|
12 | SM_RCSID("@(#)$Id: assert.c,v 1.1.1.1 2003-04-08 15:06:03 zacheiss Exp $") |
---|
13 | |
---|
14 | /* |
---|
15 | ** Abnormal program termination and assertion checking. |
---|
16 | ** For documentation, see assert.html. |
---|
17 | */ |
---|
18 | |
---|
19 | #include <signal.h> |
---|
20 | #include <stdlib.h> |
---|
21 | #include <unistd.h> |
---|
22 | |
---|
23 | #include <sm/assert.h> |
---|
24 | #include <sm/exc.h> |
---|
25 | #include <sm/io.h> |
---|
26 | #include <sm/varargs.h> |
---|
27 | |
---|
28 | /* |
---|
29 | ** Debug categories that are used to guard expensive assertion checks. |
---|
30 | */ |
---|
31 | |
---|
32 | SM_DEBUG_T SmExpensiveAssert = SM_DEBUG_INITIALIZER("sm_check_assert", |
---|
33 | "@(#)$Debug: sm_check_assert - check assertions $"); |
---|
34 | |
---|
35 | SM_DEBUG_T SmExpensiveRequire = SM_DEBUG_INITIALIZER("sm_check_require", |
---|
36 | "@(#)$Debug: sm_check_require - check function preconditions $"); |
---|
37 | |
---|
38 | SM_DEBUG_T SmExpensiveEnsure = SM_DEBUG_INITIALIZER("sm_check_ensure", |
---|
39 | "@(#)$Debug: sm_check_ensure - check function postconditions $"); |
---|
40 | |
---|
41 | /* |
---|
42 | ** Debug category: send self SIGSTOP on fatal error, |
---|
43 | ** so that you can run a debugger on the stopped process. |
---|
44 | */ |
---|
45 | |
---|
46 | SM_DEBUG_T SmAbortStop = SM_DEBUG_INITIALIZER("sm_abort_stop", |
---|
47 | "@(#)$Debug: sm_abort_stop - stop process on fatal error $"); |
---|
48 | |
---|
49 | /* |
---|
50 | ** SM_ABORT_DEFAULTHANDLER -- Default procedure for abnormal program |
---|
51 | ** termination. |
---|
52 | ** |
---|
53 | ** The goal is to display an error message without disturbing the |
---|
54 | ** process state too much, then dump core. |
---|
55 | ** |
---|
56 | ** Parameters: |
---|
57 | ** filename -- filename (can be NULL). |
---|
58 | ** lineno -- line number. |
---|
59 | ** msg -- message. |
---|
60 | ** |
---|
61 | ** Returns: |
---|
62 | ** doesn't return. |
---|
63 | */ |
---|
64 | |
---|
65 | static void |
---|
66 | sm_abort_defaulthandler __P(( |
---|
67 | const char *filename, |
---|
68 | int lineno, |
---|
69 | const char *msg)); |
---|
70 | |
---|
71 | static void |
---|
72 | sm_abort_defaulthandler(filename, lineno, msg) |
---|
73 | const char *filename; |
---|
74 | int lineno; |
---|
75 | const char *msg; |
---|
76 | { |
---|
77 | if (filename != NULL) |
---|
78 | sm_io_fprintf(smioerr, SM_TIME_DEFAULT, "%s:%d: %s\n", filename, |
---|
79 | lineno, msg); |
---|
80 | else |
---|
81 | sm_io_fprintf(smioerr, SM_TIME_DEFAULT, "%s\n", msg); |
---|
82 | sm_io_flush(smioerr, SM_TIME_DEFAULT); |
---|
83 | #ifdef SIGSTOP |
---|
84 | if (sm_debug_active(&SmAbortStop, 1)) |
---|
85 | kill(getpid(), SIGSTOP); |
---|
86 | #endif /* SIGSTOP */ |
---|
87 | abort(); |
---|
88 | } |
---|
89 | |
---|
90 | /* |
---|
91 | ** This is the action to be taken to cause abnormal program termination. |
---|
92 | */ |
---|
93 | |
---|
94 | static SM_ABORT_HANDLER_T SmAbortHandler = sm_abort_defaulthandler; |
---|
95 | |
---|
96 | /* |
---|
97 | ** SM_ABORT_SETHANDLER -- Set handler for SM_ABORT() |
---|
98 | ** |
---|
99 | ** This allows you to set a handler function for causing abnormal |
---|
100 | ** program termination; it is called when a logic bug is detected. |
---|
101 | ** |
---|
102 | ** Parameters: |
---|
103 | ** f -- handler. |
---|
104 | ** |
---|
105 | ** Returns: |
---|
106 | ** none. |
---|
107 | */ |
---|
108 | |
---|
109 | void |
---|
110 | sm_abort_sethandler(f) |
---|
111 | SM_ABORT_HANDLER_T f; |
---|
112 | { |
---|
113 | if (f == NULL) |
---|
114 | SmAbortHandler = sm_abort_defaulthandler; |
---|
115 | else |
---|
116 | SmAbortHandler = f; |
---|
117 | } |
---|
118 | |
---|
119 | /* |
---|
120 | ** SM_ABORT -- Call it when you have detected a logic bug. |
---|
121 | ** |
---|
122 | ** Parameters: |
---|
123 | ** fmt -- format string. |
---|
124 | ** ... -- arguments. |
---|
125 | ** |
---|
126 | ** Returns: |
---|
127 | ** doesn't. |
---|
128 | */ |
---|
129 | |
---|
130 | void |
---|
131 | #if SM_VA_STD |
---|
132 | sm_abort(char *fmt, ...) |
---|
133 | #else /* SM_VA_STD */ |
---|
134 | sm_abort(fmt, va_alist) |
---|
135 | char *fmt; |
---|
136 | va_dcl |
---|
137 | #endif /* SM_VA_STD */ |
---|
138 | { |
---|
139 | char msg[128]; |
---|
140 | SM_VA_LOCAL_DECL |
---|
141 | |
---|
142 | SM_VA_START(ap, fmt); |
---|
143 | sm_vsnprintf(msg, sizeof msg, fmt, ap); |
---|
144 | SM_VA_END(ap); |
---|
145 | sm_abort_at(NULL, 0, msg); |
---|
146 | } |
---|
147 | |
---|
148 | /* |
---|
149 | ** SM_ABORT_AT -- Initiate abnormal program termination. |
---|
150 | ** |
---|
151 | ** This is the low level function that is called to initiate abnormal |
---|
152 | ** program termination. It prints an error message and terminates the |
---|
153 | ** program. It is called by sm_abort and by the assertion macros. |
---|
154 | ** If filename != NULL then filename and lineno specify the line of source |
---|
155 | ** code at which the bug was detected. |
---|
156 | ** |
---|
157 | ** Parameters: |
---|
158 | ** filename -- filename (can be NULL). |
---|
159 | ** lineno -- line number. |
---|
160 | ** msg -- message. |
---|
161 | ** |
---|
162 | ** Returns: |
---|
163 | ** doesn't. |
---|
164 | */ |
---|
165 | |
---|
166 | void |
---|
167 | sm_abort_at(filename, lineno, msg) |
---|
168 | const char *filename; |
---|
169 | int lineno; |
---|
170 | const char *msg; |
---|
171 | { |
---|
172 | SM_TRY |
---|
173 | (*SmAbortHandler)(filename, lineno, msg); |
---|
174 | SM_EXCEPT(exc, "*") |
---|
175 | sm_io_fprintf(smioerr, SM_TIME_DEFAULT, |
---|
176 | "exception raised by abort handler:\n"); |
---|
177 | sm_exc_print(exc, smioerr); |
---|
178 | sm_io_flush(smioerr, SM_TIME_DEFAULT); |
---|
179 | SM_END_TRY |
---|
180 | |
---|
181 | /* |
---|
182 | ** SmAbortHandler isn't supposed to return. |
---|
183 | ** Since it has, let's make sure that the program is terminated. |
---|
184 | */ |
---|
185 | |
---|
186 | abort(); |
---|
187 | } |
---|