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