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