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