assert.c revision 132943
1107178Snjl/* 2107178Snjl * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers. 3107178Snjl * All rights reserved. 4107178Snjl * 5107178Snjl * By using this file, you agree to the terms and conditions set 6107178Snjl * forth in the LICENSE file which can be found at the top level of 7107178Snjl * the sendmail distribution. 8107178Snjl * 9107178Snjl */ 10107178Snjl 11107178Snjl#include <sm/gen.h> 12107178SnjlSM_RCSID("@(#)$Id: assert.c,v 1.26 2003/12/05 22:45:24 ca Exp $") 13107178Snjl 14107178Snjl/* 15107178Snjl** Abnormal program termination and assertion checking. 16107178Snjl** For documentation, see assert.html. 17107178Snjl*/ 18107178Snjl 19107178Snjl#include <signal.h> 20107178Snjl#include <stdlib.h> 21107178Snjl#include <unistd.h> 22107178Snjl 23107178Snjl#include <sm/assert.h> 24107178Snjl#include <sm/exc.h> 25107178Snjl#include <sm/io.h> 26107178Snjl#include <sm/varargs.h> 27107178Snjl 28107178Snjl/* 29107178Snjl** Debug categories that are used to guard expensive assertion checks. 30107178Snjl*/ 31107178Snjl 32107178SnjlSM_DEBUG_T SmExpensiveAssert = SM_DEBUG_INITIALIZER("sm_check_assert", 33107178Snjl "@(#)$Debug: sm_check_assert - check assertions $"); 34107178Snjl 35107178SnjlSM_DEBUG_T SmExpensiveRequire = SM_DEBUG_INITIALIZER("sm_check_require", 36107178Snjl "@(#)$Debug: sm_check_require - check function preconditions $"); 37107178Snjl 38107178SnjlSM_DEBUG_T SmExpensiveEnsure = SM_DEBUG_INITIALIZER("sm_check_ensure", 39107178Snjl "@(#)$Debug: sm_check_ensure - check function postconditions $"); 40107178Snjl 41107178Snjl/* 42107178Snjl** Debug category: send self SIGSTOP on fatal error, 43107178Snjl** so that you can run a debugger on the stopped process. 44107178Snjl*/ 45107178Snjl 46107178SnjlSM_DEBUG_T SmAbortStop = SM_DEBUG_INITIALIZER("sm_abort_stop", 47107178Snjl "@(#)$Debug: sm_abort_stop - stop process on fatal error $"); 48107178Snjl 49107178Snjl/* 50107178Snjl** SM_ABORT_DEFAULTHANDLER -- Default procedure for abnormal program 51107178Snjl** termination. 52107178Snjl** 53107178Snjl** The goal is to display an error message without disturbing the 54107178Snjl** process state too much, then dump core. 55107178Snjl** 56107178Snjl** Parameters: 57107178Snjl** filename -- filename (can be NULL). 58107178Snjl** lineno -- line number. 59107178Snjl** msg -- message. 60107178Snjl** 61107178Snjl** Returns: 62107178Snjl** doesn't return. 63107178Snjl*/ 64107178Snjl 65107178Snjlstatic void 66107178Snjlsm_abort_defaulthandler __P(( 67107178Snjl const char *filename, 68107178Snjl int lineno, 69107178Snjl const char *msg)); 70107178Snjl 71107178Snjlstatic void 72107178Snjlsm_abort_defaulthandler(filename, lineno, msg) 73107178Snjl const char *filename; 74107178Snjl int lineno; 75107178Snjl const char *msg; 76107178Snjl{ 77107178Snjl if (filename != NULL) 78107178Snjl sm_io_fprintf(smioerr, SM_TIME_DEFAULT, "%s:%d: %s\n", filename, 79107178Snjl lineno, msg); 80107178Snjl else 81107178Snjl sm_io_fprintf(smioerr, SM_TIME_DEFAULT, "%s\n", msg); 82107178Snjl sm_io_flush(smioerr, SM_TIME_DEFAULT); 83107178Snjl#ifdef SIGSTOP 84107178Snjl if (sm_debug_active(&SmAbortStop, 1)) 85107178Snjl kill(getpid(), SIGSTOP); 86107178Snjl#endif /* SIGSTOP */ 87107178Snjl abort(); 88107178Snjl} 89107178Snjl 90107178Snjl/* 91107178Snjl** This is the action to be taken to cause abnormal program termination. 92107178Snjl*/ 93107178Snjl 94107178Snjlstatic SM_ABORT_HANDLER_T SmAbortHandler = sm_abort_defaulthandler; 95107178Snjl 96107178Snjl/* 97107178Snjl** SM_ABORT_SETHANDLER -- Set handler for SM_ABORT() 98107178Snjl** 99107178Snjl** This allows you to set a handler function for causing abnormal 100107178Snjl** program termination; it is called when a logic bug is detected. 101107178Snjl** 102107178Snjl** Parameters: 103107178Snjl** f -- handler. 104107178Snjl** 105107178Snjl** Returns: 106107178Snjl** none. 107107178Snjl*/ 108107178Snjl 109107178Snjlvoid 110107178Snjlsm_abort_sethandler(f) 111107178Snjl SM_ABORT_HANDLER_T f; 112107178Snjl{ 113107178Snjl if (f == NULL) 114107178Snjl SmAbortHandler = sm_abort_defaulthandler; 115107178Snjl else 116107178Snjl SmAbortHandler = f; 117107178Snjl} 118107178Snjl 119107178Snjl/* 120107178Snjl** SM_ABORT -- Call it when you have detected a logic bug. 121107178Snjl** 122107178Snjl** Parameters: 123107178Snjl** fmt -- format string. 124107178Snjl** ... -- arguments. 125107178Snjl** 126107178Snjl** Returns: 127107178Snjl** doesn't. 128109345Snjl*/ 129109345Snjl 130109345Snjlvoid SM_DEAD_D 131109345Snjl#if SM_VA_STD 132107178Snjlsm_abort(char *fmt, ...) 133107178Snjl#else /* SM_VA_STD */ 134107178Snjlsm_abort(fmt, va_alist) 135107178Snjl char *fmt; 136107178Snjl va_dcl 137107178Snjl#endif /* SM_VA_STD */ 138107178Snjl{ 139107178Snjl char msg[128]; 140107178Snjl SM_VA_LOCAL_DECL 141107178Snjl 142107178Snjl SM_VA_START(ap, fmt); 143107178Snjl sm_vsnprintf(msg, sizeof msg, fmt, ap); 144107178Snjl SM_VA_END(ap); 145107178Snjl sm_abort_at(NULL, 0, msg); 146107178Snjl} 147107178Snjl 148107178Snjl/* 149107178Snjl** SM_ABORT_AT -- Initiate abnormal program termination. 150107178Snjl** 151107178Snjl** This is the low level function that is called to initiate abnormal 152107178Snjl** program termination. It prints an error message and terminates the 153107178Snjl** program. It is called by sm_abort and by the assertion macros. 154107178Snjl** If filename != NULL then filename and lineno specify the line of source 155107178Snjl** code at which the bug was detected. 156107178Snjl** 157107178Snjl** Parameters: 158107178Snjl** filename -- filename (can be NULL). 159107178Snjl** lineno -- line number. 160107178Snjl** msg -- message. 161107178Snjl** 162107178Snjl** Returns: 163107178Snjl** doesn't. 164107178Snjl*/ 165107178Snjl 166107178Snjlvoid SM_DEAD_D 167107178Snjlsm_abort_at(filename, lineno, msg) 168107178Snjl const char *filename; 169107178Snjl int lineno; 170107178Snjl const char *msg; 171107178Snjl{ 172107178Snjl SM_TRY 173107178Snjl (*SmAbortHandler)(filename, lineno, msg); 174107178Snjl SM_EXCEPT(exc, "*") 175107178Snjl sm_io_fprintf(smioerr, SM_TIME_DEFAULT, 176107178Snjl "exception raised by abort handler:\n"); 177107178Snjl sm_exc_print(exc, smioerr); 178107178Snjl sm_io_flush(smioerr, SM_TIME_DEFAULT); 179107178Snjl SM_END_TRY 180107178Snjl 181107178Snjl /* 182107178Snjl ** SmAbortHandler isn't supposed to return. 183107178Snjl ** Since it has, let's make sure that the program is terminated. 184107178Snjl */ 185107178Snjl 186107178Snjl abort(); 187107178Snjl} 188107178Snjl