assert.c revision 95154
1107178Snjl/*
2107178Snjl * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
3107178Snjl *	All rights reserved.
4107178Snjl *
5107178Snjl * By using this file, you agree to the terms and conditions set
6107178Snjl * forth in the LICENSE file which can be found at the top level of
7107178Snjl * the sendmail distribution.
8107178Snjl *
9107178Snjl */
10107178Snjl
11107178Snjl#include <sm/gen.h>
12107178SnjlSM_RCSID("@(#)$Id: assert.c,v 1.1.1.1 2002/02/17 21:56:43 gshapiro Exp $")
13107178Snjl
14107178Snjl/*
15107178Snjl**  Abnormal program termination and assertion checking.
16107178Snjl**  For documentation, see assert.html.
17107178Snjl*/
18107178Snjl
19107178Snjl#include <signal.h>
20107178Snjl#include <stdlib.h>
21107178Snjl#include <unistd.h>
22107178Snjl
23107178Snjl#include <sm/assert.h>
24107178Snjl#include <sm/exc.h>
25107178Snjl#include <sm/io.h>
26107178Snjl#include <sm/varargs.h>
27107178Snjl
28107178Snjl/*
29107178Snjl**  Debug categories that are used to guard expensive assertion checks.
30107178Snjl*/
31107178Snjl
32107178SnjlSM_DEBUG_T SmExpensiveAssert = SM_DEBUG_INITIALIZER("sm_check_assert",
33107178Snjl	"@(#)$Debug: sm_check_assert - check assertions $");
34107178Snjl
35107178SnjlSM_DEBUG_T SmExpensiveRequire = SM_DEBUG_INITIALIZER("sm_check_require",
36107178Snjl	"@(#)$Debug: sm_check_require - check function preconditions $");
37107178Snjl
38107178SnjlSM_DEBUG_T SmExpensiveEnsure = SM_DEBUG_INITIALIZER("sm_check_ensure",
39107178Snjl	"@(#)$Debug: sm_check_ensure - check function postconditions $");
40107178Snjl
41107178Snjl/*
42107178Snjl**  Debug category: send self SIGSTOP on fatal error,
43107178Snjl**  so that you can run a debugger on the stopped process.
44107178Snjl*/
45107178Snjl
46107178SnjlSM_DEBUG_T SmAbortStop = SM_DEBUG_INITIALIZER("sm_abort_stop",
47107178Snjl	"@(#)$Debug: sm_abort_stop - stop process on fatal error $");
48107178Snjl
49107178Snjl/*
50107178Snjl**  SM_ABORT_DEFAULTHANDLER -- Default procedure for abnormal program
51107178Snjl**				termination.
52107178Snjl**
53107178Snjl**	The goal is to display an error message without disturbing the
54107178Snjl**	process state too much, then dump core.
55107178Snjl**
56107178Snjl**	Parameters:
57107178Snjl**		filename -- filename (can be NULL).
58107178Snjl**		lineno -- line number.
59107178Snjl**		msg -- message.
60107178Snjl**
61107178Snjl**	Returns:
62107178Snjl**		doesn't return.
63107178Snjl*/
64107178Snjl
65107178Snjlstatic void
66107178Snjlsm_abort_defaulthandler __P((
67107178Snjl	const char *filename,
68107178Snjl	int lineno,
69107178Snjl	const char *msg));
70107178Snjl
71107178Snjlstatic void
72107178Snjlsm_abort_defaulthandler(filename, lineno, msg)
73107178Snjl	const char *filename;
74107178Snjl	int lineno;
75107178Snjl	const char *msg;
76107178Snjl{
77107178Snjl	if (filename != NULL)
78107178Snjl		sm_io_fprintf(smioerr, SM_TIME_DEFAULT, "%s:%d: %s\n", filename,
79107178Snjl			      lineno, msg);
80107178Snjl	else
81107178Snjl		sm_io_fprintf(smioerr, SM_TIME_DEFAULT, "%s\n", msg);
82107178Snjl	sm_io_flush(smioerr, SM_TIME_DEFAULT);
83107178Snjl#ifdef SIGSTOP
84107178Snjl	if (sm_debug_active(&SmAbortStop, 1))
85107178Snjl		kill(getpid(), SIGSTOP);
86107178Snjl#endif /* SIGSTOP */
87107178Snjl	abort();
88107178Snjl}
89107178Snjl
90107178Snjl/*
91107178Snjl**  This is the action to be taken to cause abnormal program termination.
92107178Snjl*/
93107178Snjl
94107178Snjlstatic SM_ABORT_HANDLER_T SmAbortHandler = sm_abort_defaulthandler;
95107178Snjl
96107178Snjl/*
97107178Snjl**  SM_ABORT_SETHANDLER -- Set handler for SM_ABORT()
98107178Snjl**
99107178Snjl**	This allows you to set a handler function for causing abnormal
100107178Snjl**	program termination; it is called when a logic bug is detected.
101107178Snjl**
102107178Snjl**	Parameters:
103107178Snjl**		f -- handler.
104107178Snjl**
105107178Snjl**	Returns:
106107178Snjl**		none.
107107178Snjl*/
108107178Snjl
109107178Snjlvoid
110107178Snjlsm_abort_sethandler(f)
111107178Snjl	SM_ABORT_HANDLER_T f;
112107178Snjl{
113107178Snjl	if (f == NULL)
114107178Snjl		SmAbortHandler = sm_abort_defaulthandler;
115107178Snjl	else
116107178Snjl		SmAbortHandler = f;
117107178Snjl}
118107178Snjl
119107178Snjl/*
120107178Snjl**  SM_ABORT -- Call it when you have detected a logic bug.
121107178Snjl**
122107178Snjl**	Parameters:
123107178Snjl**		fmt -- format string.
124107178Snjl**		... -- arguments.
125107178Snjl**
126107178Snjl**	Returns:
127107178Snjl**		doesn't.
128107178Snjl*/
129107178Snjl
130107178Snjlvoid
131107178Snjl#if SM_VA_STD
132107178Snjlsm_abort(char *fmt, ...)
133107178Snjl#else /* SM_VA_STD */
134107178Snjlsm_abort(fmt, va_alist)
135107178Snjl	char *fmt;
136107178Snjl	va_dcl
137107178Snjl#endif /* SM_VA_STD */
138107178Snjl{
139107178Snjl	char msg[128];
140107178Snjl	SM_VA_LOCAL_DECL
141107178Snjl
142107178Snjl	SM_VA_START(ap, fmt);
143107178Snjl	sm_vsnprintf(msg, sizeof msg, fmt, ap);
144107178Snjl	SM_VA_END(ap);
145107178Snjl	sm_abort_at(NULL, 0, msg);
146107178Snjl}
147107178Snjl
148107178Snjl/*
149107178Snjl**  SM_ABORT_AT -- Initiate abnormal program termination.
150107178Snjl**
151107178Snjl**	This is the low level function that is called to initiate abnormal
152107178Snjl**	program termination.  It prints an error message and terminates the
153107178Snjl**	program.  It is called by sm_abort and by the assertion macros.
154107178Snjl**	If filename != NULL then filename and lineno specify the line of source
155107178Snjl**	code at which the bug was detected.
156107178Snjl**
157107178Snjl**	Parameters:
158107178Snjl**		filename -- filename (can be NULL).
159107178Snjl**		lineno -- line number.
160107178Snjl**		msg -- message.
161107178Snjl**
162107178Snjl**	Returns:
163107178Snjl**		doesn't.
164107178Snjl*/
165107178Snjl
166107178Snjlvoid
167107178Snjlsm_abort_at(filename, lineno, msg)
168107178Snjl	const char *filename;
169107178Snjl	int lineno;
170107178Snjl	const char *msg;
171107178Snjl{
172107178Snjl	SM_TRY
173107178Snjl		(*SmAbortHandler)(filename, lineno, msg);
174107178Snjl	SM_EXCEPT(exc, "*")
175107178Snjl		sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
176107178Snjl			      "exception raised by abort handler:\n");
177107178Snjl		sm_exc_print(exc, smioerr);
178107178Snjl		sm_io_flush(smioerr, SM_TIME_DEFAULT);
179107178Snjl	SM_END_TRY
180107178Snjl
181107178Snjl	/*
182107178Snjl	**  SmAbortHandler isn't supposed to return.
183107178Snjl	**  Since it has, let's make sure that the program is terminated.
184107178Snjl	*/
185107178Snjl
186107178Snjl	abort();
187107178Snjl}
188107178Snjl