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