File: assert.c

package info (click to toggle)
ntpsec 1.2.4%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 10,360 kB
  • sloc: ansic: 62,698; python: 32,477; sh: 1,575; yacc: 1,331; makefile: 193; javascript: 138
file content (161 lines) | stat: -rw-r--r-- 3,551 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
/*
 * Copyright Internet Systems Consortium, Inc. ("ISC")
 * Copyright Internet Software Consortium.
 * Copyright the NTPsec project contributors
 * SPDX-License-Identifier: ISC
 */

/*! \file */

#include "config.h"

#include <stdio.h>
#include <stdlib.h>

#include "ntp.h"
#include "ntp_debug.h"
#include "ntp_syslog.h"
#include "ntp_assert.h"
#include "isc_result.h"

#ifdef USEBACKTRACE

/*
 * Getting a back trace of a running process is tricky and highly platform
 * dependent.  Our current approach is as follows:
 * 1. If the system library supports the "backtrace()" function, use it.
 *    OS X support this starting at with SDK 10.5.  glibc since version 2.1
 * 2. Otherwise, if unwind.h exists then use the __Unwind_Backtrace() function.
 *    This function is available on Linux, OS X, and FreeBSD.  It is defined
 *    in Linux Standard Base since version 4.1
 * 3. Otherwise, tough luck.
 */

/*
 * The maximum number of stack frames to dump on assertion failure.
 */
#ifndef BACKTRACE_MAXFRAME
#define BACKTRACE_MAXFRAME 128
#endif


# ifdef HAVE_BACKTRACE_SYMBOLS_FD
#include <execinfo.h>

void
backtrace_log(void) {
	int nptrs;
	void *buffer[BACKTRACE_MAXFRAME];
	char **strings;

	nptrs = backtrace(buffer, BACKTRACE_MAXFRAME);
	strings = backtrace_symbols(buffer, nptrs);
	msyslog(LOG_ERR, "ERR: Stack trace:\n");
	if (strings) {
	   /* skip trace of this shim function */
	   for (int j = 1; j < nptrs; j++)
	       msyslog(LOG_ERR, "ERR:  %s\n", strings[j]);

	   free(strings);
	}
}
# elif defined(HAVE__UNWIND_BACKTRACE)
#include <unwind.h>

typedef struct {
	void **result;
	int max_depth;
	int skip_count;
	int count;
} trace_arg_t;

static _Unwind_Reason_Code
btcallback(struct _Unwind_Context *uc, void *opq) {
	trace_arg_t *arg = (trace_arg_t *)opq;

	if (arg->skip_count > 0)
		arg->skip_count--;
	else
		arg->result[arg->count++] = (void *)_Unwind_GetIP(uc);
	if (arg->count == arg->max_depth)
		return (5); /* _URC_END_OF_STACK */

	return (0); /* _URC_NO_REASON */
}


void
backtrace_log(void) {
	trace_arg_t arg;
	void *buffer[BACKTRACE_MAXFRAME];

	arg.skip_count = 1;
	arg.result = buffer;
	arg.max_depth = BACKTRACE_MAXFRAME;
	arg.count = 0;
	_Unwind_Backtrace(btcallback, &arg);

	msyslog(LOG_ERR, "ERR: Stack trace:\n");
	/* skip trace of this shim function */
	for (int i = 1; i < arg.count; i++) {
	    msyslog(LOG_ERR, "ERR: #%d %p in ??\n", i, buffer[i]);
	}

}
#endif /* HAVE__UNWIND_BACKTRACE */

#endif /* USEBACKTRACE */

/*% Type to Text */
static const char *
assertion_typetotext(assertiontype_t type) {
	const char *result;

	/*
	 * These strings have purposefully not been internationalized
	 * because they are considered to essentially be keywords of
	 * the ISC development environment.
	 */
	switch (type) {
	case assertiontype_require:
		result = "REQUIRE";
		break;
	case assertiontype_ensure:
		result = "ENSURE";
		break;
	case assertiontype_insist:
		result = "INSIST";
		break;
	case assertiontype_invariant:
		result = "INVARIANT";
		break;
	default:
		result = "(null)";
	}
	return (result);
}

/*
 * assertion_failed - Redirect assertion failed output to msyslog().
 */
void
assertion_failed(
	const char *file,
	int line,
	assertiontype_t type,
	const char *cond
	)
{
        /* Is recursion an issue? */

	termlogit = true; /* insist log to terminal */

	msyslog(LOG_ERR, "ERR: %s:%d: %s(%s) failed",
		file, line, assertion_typetotext(type), cond);
#ifndef BACKTRACE_DISABLED
        backtrace_log();
#endif
	msyslog(LOG_ERR, "ERR: exiting (due to assertion failure)");

	abort();
}