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> 14 SM_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 34 SM_DEBUG_T SmExpensiveAssert = SM_DEBUG_INITIALIZER("sm_check_assert", 35 "@(#)$Debug: sm_check_assert - check assertions $"); 36 37 SM_DEBUG_T SmExpensiveRequire = SM_DEBUG_INITIALIZER("sm_check_require", 38 "@(#)$Debug: sm_check_require - check function preconditions $"); 39 40 SM_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 48 SM_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 67 static void 68 sm_abort_defaulthandler __P(( 69 const char *filename, 70 int lineno, 71 const char *msg)); 72 73 static void 74 sm_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 96 static 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 111 void 112 sm_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 132 void SM_DEAD_D 133 #if SM_VA_STD 134 sm_abort(char *fmt, ...) 135 #else /* SM_VA_STD */ 136 sm_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 168 void SM_DEAD_D 169 sm_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