assert.c revision 261363
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> 12SM_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 32SM_DEBUG_T SmExpensiveAssert = SM_DEBUG_INITIALIZER("sm_check_assert", 33 "@(#)$Debug: sm_check_assert - check assertions $"); 34 35SM_DEBUG_T SmExpensiveRequire = SM_DEBUG_INITIALIZER("sm_check_require", 36 "@(#)$Debug: sm_check_require - check function preconditions $"); 37 38SM_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 46SM_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 65static void 66sm_abort_defaulthandler __P(( 67 const char *filename, 68 int lineno, 69 const char *msg)); 70 71static void 72sm_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 /* SIGSTOP */ 87 abort(); 88} 89 90/* 91** This is the action to be taken to cause abnormal program termination. 92*/ 93 94static 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 109void 110sm_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 130void SM_DEAD_D 131#if SM_VA_STD 132sm_abort(char *fmt, ...) 133#else /* SM_VA_STD */ 134sm_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 166void SM_DEAD_D 167sm_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