Revert "LATER... ei_kerberos_kdc_session_key ..."
[wireshark-sm.git] / epan / except.c
blob6aaf63f45e72846b9261d0a00df01532c9af55e4
1 /*
2 * Portable Exception Handling for ANSI C.
3 * Copyright (C) 1999 Kaz Kylheku <kaz@ashi.footprints.net>
5 * Free Software License:
7 * All rights are reserved by the author, with the following exceptions:
8 * Permission is granted to freely reproduce and distribute this software,
9 * possibly in exchange for a fee, provided that this copyright notice appears
10 * intact. Permission is also granted to adapt this software to produce
11 * derivative works, as long as the modified versions carry this copyright
12 * notice and additional notices stating that the work has been modified.
13 * This source code may be translated into executable form and incorporated
14 * into proprietary software; there is no requirement for such software to
15 * contain a copyright notice related to this source.
19 * Modified to support throwing an exception with a null message pointer,
20 * and to have the message not be const (as we generate messages with
21 * "ws_strdup_printf()", which means they need to be freed; using
22 * a null message means that we don't have to use a special string
23 * for exceptions with no message, and don't have to worry about
24 * not freeing that).
27 #include "config.h"
29 #include <assert.h>
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <stdarg.h>
33 #include <limits.h>
35 #include <glib.h>
37 #include "except.h"
39 #ifdef _WIN32
40 #include <windows.h>
41 #include "exceptions.h"
42 #endif
44 #define XCEPT_BUFFER_SIZE 1024
46 #ifdef KAZLIB_POSIX_THREADS
48 #include <pthread.h>
50 static pthread_mutex_t init_mtx = PTHREAD_MUTEX_INITIALIZER;
51 static int init_counter;
52 static pthread_key_t top_key;
53 static pthread_key_t uh_key;
54 static pthread_key_t alloc_key;
55 static pthread_key_t dealloc_key;
56 static void unhandled_catcher(except_t *);
58 #define get_top() ((struct except_stacknode *) pthread_getspecific(top_key))
59 #define set_top(T) (pthread_setspecific(top_key, (T)), (void)((T) == (struct except_stacknode *) 0))
60 #define set_catcher(C) (pthread_setspecific(uh_key, (void *) (C)), (void)((C) == (void (*)(except_t *)) 0))
61 #define set_alloc(A) (pthread_setspecific(alloc_key, (void *) (A)), (void)((A) == (void *(*)(size_t)) 0))
62 #define set_dealloc(D) (pthread_setspecific(dealloc_key, (void *) (D)), (void)((D) == (void (*)(void *)) 0))
64 static void (*get_catcher(void))(except_t *)
66 void (*catcher)(except_t *) = (void (*)(except_t *)) pthread_getspecific(uh_key);
67 return (catcher == 0) ? unhandled_catcher : catcher;
70 static void *(*get_alloc(void))(size_t)
72 void *(*alloc)(size_t) = (void *(*)(size_t)) pthread_getspecific(alloc_key);
73 return (alloc == 0) ? malloc : alloc;
76 static void (*get_dealloc(void))(void *)
78 void (*dealloc)(void *) = (void (*)(void *)) pthread_getspecific(dealloc_key);
79 return (dealloc == 0) ? free : dealloc;
82 int except_init(void)
84 int retval = 1;
86 pthread_mutex_lock(&init_mtx);
88 assert (init_counter < INT_MAX);
90 if (init_counter++ == 0) {
91 int top_ok = (pthread_key_create(&top_key, 0) == 0);
92 int uh_ok = (pthread_key_create(&uh_key, 0) == 0);
93 int alloc_ok = (pthread_key_create(&alloc_key, 0) == 0);
94 int dealloc_ok = (pthread_key_create(&dealloc_key, 0) == 0);
96 if (!top_ok || !uh_ok || !alloc_ok || !dealloc_ok) {
97 retval = 0;
98 init_counter = 0;
99 if (top_ok)
100 pthread_key_delete(top_key);
101 if (uh_ok)
102 pthread_key_delete(uh_key);
103 if (alloc_ok)
104 pthread_key_delete(alloc_key);
105 if (dealloc_ok)
106 pthread_key_delete(dealloc_key);
110 pthread_mutex_unlock(&init_mtx);
112 return retval;
115 void except_deinit(void)
117 pthread_mutex_lock(&init_mtx);
119 assert (init_counter > 0);
121 if (--init_counter == 0) {
122 pthread_key_delete(top_key);
123 pthread_key_delete(uh_key);
124 pthread_key_delete(alloc_key);
125 pthread_key_delete(dealloc_key);
128 pthread_mutex_unlock(&init_mtx);
131 #else /* not using POSIX thread support */
134 * We make the catcher stack per-thread, because we must.
136 * We don't make the unhandled-exception-catcher, the allocator, or the
137 * deallocator thread-specific, as we don't need to.
139 * We don't protext the init level with a mutex, as we only initialize
140 * it and de-initialize it once.
142 static int init_counter;
143 static void unhandled_catcher(except_t *);
144 static void (*uh_catcher_ptr)(except_t *) = unhandled_catcher;
145 /* We need this 'size_t' cast due to a glitch in GLib where g_malloc was prototyped
146 * as 'void *g_malloc (unsigned long n_bytes)'. This was later fixed to the correct prototype
147 * 'void *g_malloc (size_t n_bytes)'. In Wireshark we use the latter prototype
148 * throughout the code. We can get away with this even with older versions of GLib by
149 * adding a '(void *(*)(size_t))' cast whenever we refer to g_malloc. The only platform
150 * supported by Wireshark where this isn't safe (sizeof size_t != sizeof unsigned long) is Win64.
151 * However, we _always_ bundle the newest version of GLib on this platform so
152 * the size_t issue doesn't exists here. Pheew.. */
153 static void *(*allocator)(size_t) = (void *(*)(size_t)) g_malloc;
154 static void (*deallocator)(void *) = g_free;
155 static WS_THREAD_LOCAL struct except_stacknode *stack_top;
157 #define get_top() (stack_top)
158 #define set_top(T) (stack_top = (T))
159 #define get_catcher() (uh_catcher_ptr)
160 #define set_catcher(C) (uh_catcher_ptr = (C))
161 #define get_alloc() (allocator)
162 #define set_alloc(A) (allocator = (A))
163 #define get_dealloc() (deallocator)
164 #define set_dealloc(D) (deallocator = (D))
166 int except_init(void)
168 assert (init_counter < INT_MAX);
169 init_counter++;
170 return 1;
173 void except_deinit(void)
175 assert (init_counter > 0);
176 init_counter--;
179 #endif
182 static int match(const volatile except_id_t *thrown, const except_id_t *caught)
184 int group_match = (caught->except_group == XCEPT_GROUP_ANY ||
185 caught->except_group == thrown->except_group);
186 int code_match = (caught->except_code == XCEPT_CODE_ANY ||
187 caught->except_code == thrown->except_code);
189 return group_match && code_match;
192 WS_NORETURN static void do_throw(except_t *except)
194 struct except_stacknode *top;
196 assert (except->except_id.except_group != 0 &&
197 except->except_id.except_code != 0);
199 for (top = get_top(); top != 0; top = top->except_down) {
200 if (top->except_type == XCEPT_CLEANUP) {
201 top->except_info.except_cleanup->except_func(top->except_info.except_cleanup->except_context);
202 } else {
203 struct except_catch *catcher = top->except_info.except_catcher;
204 const except_id_t *pi = catcher->except_id;
205 size_t i;
207 assert (top->except_type == XCEPT_CATCHER);
208 except_free(catcher->except_obj.except_dyndata);
210 for (i = 0; i < catcher->except_size; pi++, i++) {
211 if (match(&except->except_id, pi)) {
212 catcher->except_obj = *except;
213 set_top(top);
214 longjmp(catcher->except_jmp, 1);
220 set_top(top);
221 get_catcher()(except); /* unhandled exception */
222 abort();
225 static void unhandled_catcher(except_t *except)
227 if (except->except_message == NULL) {
228 fprintf(stderr, "Unhandled exception (group=%lu, code=%lu)\n",
229 except->except_id.except_group,
230 except->except_id.except_code);
231 } else {
232 fprintf(stderr, "Unhandled exception (\"%s\", group=%lu, code=%lu)\n",
233 except->except_message, except->except_id.except_group,
234 except->except_id.except_code);
236 abort();
239 static void stack_push(struct except_stacknode *node)
241 node->except_down = get_top();
242 set_top(node);
245 void except_setup_clean(struct except_stacknode *esn,
246 struct except_cleanup *ecl, void (*cleanf)(void *), void *context)
248 esn->except_type = XCEPT_CLEANUP;
249 ecl->except_func = cleanf;
250 ecl->except_context = context;
251 esn->except_info.except_cleanup = ecl;
252 stack_push(esn);
255 void except_setup_try(struct except_stacknode *esn,
256 struct except_catch *ech, const except_id_t id[], size_t size)
258 ech->except_id = id;
259 ech->except_size = size;
260 ech->except_obj.except_dyndata = 0;
261 esn->except_type = XCEPT_CATCHER;
262 esn->except_info.except_catcher = ech;
263 stack_push(esn);
266 struct except_stacknode *except_pop(void)
268 struct except_stacknode *top = get_top();
269 assert (top->except_type == XCEPT_CLEANUP || top->except_type == XCEPT_CATCHER);
270 set_top(top->except_down);
271 return top;
274 WS_NORETURN void except_rethrow(except_t *except)
276 struct except_stacknode *top = get_top();
277 assert (top != 0);
278 assert (top->except_type == XCEPT_CATCHER);
279 assert (&top->except_info.except_catcher->except_obj == except);
280 set_top(top->except_down);
281 do_throw(except);
284 WS_NORETURN void except_throw(long group, long code, const char *msg)
286 except_t except;
288 except.except_id.except_group = group;
289 except.except_id.except_code = code;
290 except.except_message = msg;
291 except.except_dyndata = 0;
293 #ifdef _WIN32
294 if (code == DissectorError && IsDebuggerPresent()) {
295 DebugBreak();
297 #endif
299 do_throw(&except);
302 WS_NORETURN void except_throwd(long group, long code, const char *msg, void *data)
304 except_t except;
306 except.except_id.except_group = group;
307 except.except_id.except_code = code;
308 except.except_message = msg;
309 except.except_dyndata = data;
311 do_throw(&except);
315 * XXX - should we use ws_strdup_printf() here, so we're not limited by
316 * XCEPT_BUFFER_SIZE? We could then just use this to generate formatted
317 * messages.
319 WS_NORETURN void except_vthrowf(long group, long code, const char *fmt,
320 va_list vl)
322 char *buf = (char *)except_alloc(XCEPT_BUFFER_SIZE);
324 vsnprintf(buf, XCEPT_BUFFER_SIZE, fmt, vl);
325 except_throwd(group, code, buf, buf);
328 WS_NORETURN void except_throwf(long group, long code, const char *fmt, ...)
330 va_list vl;
332 va_start (vl, fmt);
333 except_vthrowf(group, code, fmt, vl);
334 va_end (vl);
337 void (*except_unhandled_catcher(void (*new_catcher)(except_t *)))(except_t *)
339 void (*old_catcher)(except_t *) = get_catcher();
340 set_catcher(new_catcher);
341 return old_catcher;
344 #undef except_code
345 #undef except_group
346 #undef except_message
347 #undef except_data
349 unsigned long except_code(except_t *ex)
351 return ex->except_id.except_code;
354 unsigned long except_group(except_t *ex)
356 return ex->except_id.except_group;
359 const char *except_message(except_t *ex)
361 return ex->except_message;
364 void *except_data(except_t *ex)
366 return ex->except_dyndata;
369 void *except_take_data(except_t *ex)
371 void *data = ex->except_dyndata;
372 ex->except_dyndata = 0;
373 return data;
376 void except_set_allocator(void *(*alloc)(size_t), void (*dealloc)(void *))
378 set_alloc(alloc);
379 set_dealloc(dealloc);
382 void *except_alloc(size_t size)
384 void *ptr = get_alloc()(size);
386 if (ptr == 0)
387 except_throw(XCEPT_BAD_ALLOC, 0, "out of memory");
388 return ptr;
391 void except_free(void *ptr)
393 get_dealloc()(ptr);
396 #ifdef KAZLIB_TEST_MAIN
399 static void cleanup(void *arg)
401 printf("cleanup(\"%s\") called\n", (char *) arg);
404 static void bottom_level(void)
406 char buf[256];
407 printf("throw exception? "); fflush(stdout);
408 fgets(buf, sizeof buf, stdin);
410 if (buf[0] >= 0 && (buf[0] == 'Y' || buf[0] == 'y'))
411 except_throw(1, 1, "nasty exception");
414 static void top_level(void)
416 except_cleanup_push(cleanup, "argument");
417 bottom_level();
418 except_cleanup_pop(0);
421 int main(int argc, char **argv)
423 static const except_id_t catch[] = { { 1, 1 }, { 1, 2 } };
424 except_t *ex;
425 char *msg;
428 * Nested exception ``try blocks''
431 /* outer */
432 except_try_push(catch, 2, &ex);
433 if (!ex) {
434 /* inner */
435 except_try_push(catch, 2, &ex);
436 if (!ex) {
437 top_level();
438 } else {
439 /* inner catch */
440 msg = except_message(ex);
441 if (msg == NULL) {
442 printf("caught exception (inner): s=%lu, c=%lu\n",
443 except_group(ex), except_code(ex));
444 } else {
445 printf("caught exception (inner): \"%s\", s=%lu, c=%lu\n",
446 msg, except_group(ex), except_code(ex));
448 except_rethrow(ex);
450 except_try_pop();
451 } else {
452 /* outer catch */
453 msg = except_message(ex);
454 if (msg == NULL) {
455 printf("caught exception (outer): s=%lu, c=%lu\n",
456 except_group(ex), except_code(ex));
457 } else {
458 printf("caught exception (outer): \"%s\", s=%lu, c=%lu\n",
459 except_message(ex), except_group(ex), except_code(ex));
462 except_try_pop();
463 except_throw(99, 99, "exception in main");
464 return 0;
468 #endif /* KAZLIB_TEST_MAIN */
471 * Editor modelines - https://www.wireshark.org/tools/modelines.html
473 * Local variables:
474 * c-basic-offset: 4
475 * tab-width: 8
476 * indent-tabs-mode: nil
477 * End:
479 * vi: set shiftwidth=4 tabstop=8 expandtab:
480 * :indentSize=4:tabSize=8:noTabs=true: