assert.c revision 261363
1/*
2 * Copyright (c) 2000-2001 Proofpoint, 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>
12SM_RCSID("@(#)$Id: assert.c,v 1.27 2013/11/22 20:51:42 ca 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
32SM_DEBUG_T SmExpensiveAssert = SM_DEBUG_INITIALIZER("sm_check_assert",
33	"@(#)$Debug: sm_check_assert - check assertions $");
34
35SM_DEBUG_T SmExpensiveRequire = SM_DEBUG_INITIALIZER("sm_check_require",
36	"@(#)$Debug: sm_check_require - check function preconditions $");
37
38SM_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
46SM_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
65static void
66sm_abort_defaulthandler __P((
67	const char *filename,
68	int lineno,
69	const char *msg));
70
71static void
72sm_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
94static 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
109void
110sm_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
130void SM_DEAD_D
131#if SM_VA_STD
132sm_abort(char *fmt, ...)
133#else /* SM_VA_STD */
134sm_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
166void SM_DEAD_D
167sm_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}
188