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