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