190792Sgshapiro/*
2261194Sgshapiro * Copyright (c) 2000-2001 Proofpoint, Inc. and its suppliers.
390792Sgshapiro *	All rights reserved.
490792Sgshapiro *
590792Sgshapiro * By using this file, you agree to the terms and conditions set
690792Sgshapiro * forth in the LICENSE file which can be found at the top level of
790792Sgshapiro * the sendmail distribution.
890792Sgshapiro *
990792Sgshapiro */
1090792Sgshapiro
1190792Sgshapiro#include <sm/gen.h>
12266527SgshapiroSM_RCSID("@(#)$Id: assert.c,v 1.27 2013-11-22 20:51:42 ca Exp $")
1390792Sgshapiro
1490792Sgshapiro/*
1590792Sgshapiro**  Abnormal program termination and assertion checking.
1690792Sgshapiro**  For documentation, see assert.html.
1790792Sgshapiro*/
1890792Sgshapiro
1990792Sgshapiro#include <signal.h>
2090792Sgshapiro#include <stdlib.h>
2190792Sgshapiro#include <unistd.h>
2290792Sgshapiro
2390792Sgshapiro#include <sm/assert.h>
2490792Sgshapiro#include <sm/exc.h>
2590792Sgshapiro#include <sm/io.h>
2690792Sgshapiro#include <sm/varargs.h>
2790792Sgshapiro
2890792Sgshapiro/*
2990792Sgshapiro**  Debug categories that are used to guard expensive assertion checks.
3090792Sgshapiro*/
3190792Sgshapiro
3290792SgshapiroSM_DEBUG_T SmExpensiveAssert = SM_DEBUG_INITIALIZER("sm_check_assert",
3390792Sgshapiro	"@(#)$Debug: sm_check_assert - check assertions $");
3490792Sgshapiro
3590792SgshapiroSM_DEBUG_T SmExpensiveRequire = SM_DEBUG_INITIALIZER("sm_check_require",
3690792Sgshapiro	"@(#)$Debug: sm_check_require - check function preconditions $");
3790792Sgshapiro
3890792SgshapiroSM_DEBUG_T SmExpensiveEnsure = SM_DEBUG_INITIALIZER("sm_check_ensure",
3990792Sgshapiro	"@(#)$Debug: sm_check_ensure - check function postconditions $");
4090792Sgshapiro
4190792Sgshapiro/*
4290792Sgshapiro**  Debug category: send self SIGSTOP on fatal error,
4390792Sgshapiro**  so that you can run a debugger on the stopped process.
4490792Sgshapiro*/
4590792Sgshapiro
4690792SgshapiroSM_DEBUG_T SmAbortStop = SM_DEBUG_INITIALIZER("sm_abort_stop",
4790792Sgshapiro	"@(#)$Debug: sm_abort_stop - stop process on fatal error $");
4890792Sgshapiro
4990792Sgshapiro/*
5090792Sgshapiro**  SM_ABORT_DEFAULTHANDLER -- Default procedure for abnormal program
5190792Sgshapiro**				termination.
5290792Sgshapiro**
5390792Sgshapiro**	The goal is to display an error message without disturbing the
5490792Sgshapiro**	process state too much, then dump core.
5590792Sgshapiro**
5690792Sgshapiro**	Parameters:
5790792Sgshapiro**		filename -- filename (can be NULL).
5890792Sgshapiro**		lineno -- line number.
5990792Sgshapiro**		msg -- message.
6090792Sgshapiro**
6190792Sgshapiro**	Returns:
6290792Sgshapiro**		doesn't return.
6390792Sgshapiro*/
6490792Sgshapiro
6590792Sgshapirostatic void
6690792Sgshapirosm_abort_defaulthandler __P((
6790792Sgshapiro	const char *filename,
6890792Sgshapiro	int lineno,
6990792Sgshapiro	const char *msg));
7090792Sgshapiro
7190792Sgshapirostatic void
7290792Sgshapirosm_abort_defaulthandler(filename, lineno, msg)
7390792Sgshapiro	const char *filename;
7490792Sgshapiro	int lineno;
7590792Sgshapiro	const char *msg;
7690792Sgshapiro{
7790792Sgshapiro	if (filename != NULL)
7890792Sgshapiro		sm_io_fprintf(smioerr, SM_TIME_DEFAULT, "%s:%d: %s\n", filename,
7990792Sgshapiro			      lineno, msg);
8090792Sgshapiro	else
8190792Sgshapiro		sm_io_fprintf(smioerr, SM_TIME_DEFAULT, "%s\n", msg);
8290792Sgshapiro	sm_io_flush(smioerr, SM_TIME_DEFAULT);
8390792Sgshapiro#ifdef SIGSTOP
8490792Sgshapiro	if (sm_debug_active(&SmAbortStop, 1))
8590792Sgshapiro		kill(getpid(), SIGSTOP);
86363466Sgshapiro#endif
8790792Sgshapiro	abort();
8890792Sgshapiro}
8990792Sgshapiro
9090792Sgshapiro/*
9190792Sgshapiro**  This is the action to be taken to cause abnormal program termination.
9290792Sgshapiro*/
9390792Sgshapiro
9490792Sgshapirostatic SM_ABORT_HANDLER_T SmAbortHandler = sm_abort_defaulthandler;
9590792Sgshapiro
9690792Sgshapiro/*
9790792Sgshapiro**  SM_ABORT_SETHANDLER -- Set handler for SM_ABORT()
9890792Sgshapiro**
9990792Sgshapiro**	This allows you to set a handler function for causing abnormal
10090792Sgshapiro**	program termination; it is called when a logic bug is detected.
10190792Sgshapiro**
10290792Sgshapiro**	Parameters:
10390792Sgshapiro**		f -- handler.
10490792Sgshapiro**
10590792Sgshapiro**	Returns:
10690792Sgshapiro**		none.
10790792Sgshapiro*/
10890792Sgshapiro
10990792Sgshapirovoid
11090792Sgshapirosm_abort_sethandler(f)
11190792Sgshapiro	SM_ABORT_HANDLER_T f;
11290792Sgshapiro{
11390792Sgshapiro	if (f == NULL)
11490792Sgshapiro		SmAbortHandler = sm_abort_defaulthandler;
11590792Sgshapiro	else
11690792Sgshapiro		SmAbortHandler = f;
11790792Sgshapiro}
11890792Sgshapiro
11990792Sgshapiro/*
12090792Sgshapiro**  SM_ABORT -- Call it when you have detected a logic bug.
12190792Sgshapiro**
12290792Sgshapiro**	Parameters:
12390792Sgshapiro**		fmt -- format string.
12490792Sgshapiro**		... -- arguments.
12590792Sgshapiro**
12690792Sgshapiro**	Returns:
12790792Sgshapiro**		doesn't.
12890792Sgshapiro*/
12990792Sgshapiro
130125820Sgshapirovoid SM_DEAD_D
13190792Sgshapiro#if SM_VA_STD
13290792Sgshapirosm_abort(char *fmt, ...)
13390792Sgshapiro#else /* SM_VA_STD */
13490792Sgshapirosm_abort(fmt, va_alist)
13590792Sgshapiro	char *fmt;
13690792Sgshapiro	va_dcl
13790792Sgshapiro#endif /* SM_VA_STD */
13890792Sgshapiro{
13990792Sgshapiro	char msg[128];
14090792Sgshapiro	SM_VA_LOCAL_DECL
14190792Sgshapiro
14290792Sgshapiro	SM_VA_START(ap, fmt);
14390792Sgshapiro	sm_vsnprintf(msg, sizeof msg, fmt, ap);
14490792Sgshapiro	SM_VA_END(ap);
14590792Sgshapiro	sm_abort_at(NULL, 0, msg);
14690792Sgshapiro}
14790792Sgshapiro
14890792Sgshapiro/*
14990792Sgshapiro**  SM_ABORT_AT -- Initiate abnormal program termination.
15090792Sgshapiro**
15190792Sgshapiro**	This is the low level function that is called to initiate abnormal
15290792Sgshapiro**	program termination.  It prints an error message and terminates the
15390792Sgshapiro**	program.  It is called by sm_abort and by the assertion macros.
15490792Sgshapiro**	If filename != NULL then filename and lineno specify the line of source
15590792Sgshapiro**	code at which the bug was detected.
15690792Sgshapiro**
15790792Sgshapiro**	Parameters:
15890792Sgshapiro**		filename -- filename (can be NULL).
15990792Sgshapiro**		lineno -- line number.
16090792Sgshapiro**		msg -- message.
16190792Sgshapiro**
16290792Sgshapiro**	Returns:
16390792Sgshapiro**		doesn't.
16490792Sgshapiro*/
16590792Sgshapiro
166125820Sgshapirovoid SM_DEAD_D
16790792Sgshapirosm_abort_at(filename, lineno, msg)
16890792Sgshapiro	const char *filename;
16990792Sgshapiro	int lineno;
17090792Sgshapiro	const char *msg;
17190792Sgshapiro{
17290792Sgshapiro	SM_TRY
17390792Sgshapiro		(*SmAbortHandler)(filename, lineno, msg);
17490792Sgshapiro	SM_EXCEPT(exc, "*")
17590792Sgshapiro		sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
17690792Sgshapiro			      "exception raised by abort handler:\n");
17790792Sgshapiro		sm_exc_print(exc, smioerr);
17890792Sgshapiro		sm_io_flush(smioerr, SM_TIME_DEFAULT);
17990792Sgshapiro	SM_END_TRY
18090792Sgshapiro
18190792Sgshapiro	/*
18290792Sgshapiro	**  SmAbortHandler isn't supposed to return.
18390792Sgshapiro	**  Since it has, let's make sure that the program is terminated.
18490792Sgshapiro	*/
18590792Sgshapiro
18690792Sgshapiro	abort();
18790792Sgshapiro}
188