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