1 /* ex - Exception Handling */
3 /* Copyright (c) 2005-2015. The SimGrid Team.
4 * All rights reserved. */
6 /* Copyright (c) 2002-2004 Ralf S. Engelschall <rse@engelschall.com> */
7 /* Copyright (c) 2002-2004 The OSSP Project <http://www.ossp.org/> */
8 /* Copyright (c) 2002-2004 Cable & Wireless <http://www.cw.com/> */
9 /* All rights reserved. */
11 /* This code is inspirated from the OSSP version (as retrieved back in 2004)*/
12 /* It was heavily modified to fit the SimGrid framework. */
14 /* The OSSP version has the following copyright notice:
15 ** OSSP ex - Exception Handling
16 ** Copyright (c) 2002-2004 Ralf S. Engelschall <rse@engelschall.com>
17 ** Copyright (c) 2002-2004 The OSSP Project <http://www.ossp.org/>
18 ** Copyright (c) 2002-2004 Cable & Wireless <http://www.cw.com/>
20 ** This file is part of OSSP ex, an exception handling library
21 ** which can be found at http://www.ossp.org/pkg/lib/ex/.
23 ** Permission to use, copy, modify, and distribute this software for
24 ** any purpose with or without fee is hereby granted, provided that
25 ** the above copyright notice and this permission notice appear in all
28 ** THIS SOFTWARE IS PROVIDED `AS IS'' AND ANY EXPRESSED OR IMPLIED
29 ** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
30 ** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
31 ** IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR
32 ** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
35 ** USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
36 ** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
37 ** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
38 ** OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
42 /* The extensions made for the SimGrid project can either be distributed */
43 /* under the same license, or under the LGPL v2.1 */
48 #include "portable.h" /* execinfo when available */
51 #include "xbt/synchro_core.h"
52 #include "xbt_modinter.h" /* backtrace initialization headers */
54 #include "xbt/ex_interface.h"
55 #include "simgrid/sg_config.h" /* Configuration mechanism of SimGrid */
59 #if defined(HAVE_EXECINFO_H) && defined(HAVE_POPEN) && defined(ADDR2LINE)
60 # define HAVE_BACKTRACE 1 /* Hello linux box */
63 #if defined(_XBT_WIN32) && defined(_M_IX86) && !defined(__GNUC__)
64 # define HAVE_BACKTRACE 1 /* Hello x86 windows box */
68 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(xbt_ex, xbt, "Exception mecanism");
70 XBT_EXPORT_NO_IMPORT(const xbt_running_ctx_t) __xbt_ex_ctx_initializer = XBT_RUNNING_CTX_INITIALIZER;
72 /* default __ex_ctx callback function */
73 xbt_running_ctx_t *__xbt_ex_ctx_default(void)
75 /* Don't scream: this is a default which is never used (so, yes,
76 there is one setjump container by running entity).
78 This default gets overriden in xbt/xbt_os_thread.c so that it works in
79 real life and in simulation when using threads to implement the simulation
80 processes (ie, with pthreads and on windows).
82 It also gets overriden in xbt/context.c when using ucontexts (as well as
83 in Java for now, but after the java overhaul, it will get cleaned out)
85 static xbt_running_ctx_t ctx = XBT_RUNNING_CTX_INITIALIZER;
90 /* Change raw libc symbols to file names and line numbers */
91 void xbt_ex_setup_backtrace(xbt_ex_t * e);
93 void xbt_backtrace_display(xbt_ex_t * e)
95 xbt_ex_setup_backtrace(e);
99 fprintf(stderr, "(backtrace not set)\n");
103 fprintf(stderr, "Backtrace (displayed in thread %p):\n",
104 (void *) xbt_thread_self());
105 for (i = 1; i < e->used; i++) /* no need to display "xbt_backtrace_display" */
106 fprintf(stderr, "---> %s\n", e->bt_strings[i] + 4);
109 /* don't fool xbt_ex_free with uninitialized msg field */
114 XBT_ERROR("No backtrace on this arch");
118 /** \brief show the backtrace of the current point (lovely while debuging) */
119 void xbt_backtrace_display_current(void)
122 xbt_backtrace_current(&e);
123 xbt_backtrace_display(&e);
126 #if defined(HAVE_EXECINFO_H) && defined(HAVE_POPEN) && defined(ADDR2LINE)
127 # include "backtrace_linux.c"
128 #elif (defined(_XBT_WIN32) && defined (_M_IX86)) && !defined(__GNUC__)
129 # include "backtrace_windows.c"
131 # include "backtrace_dummy.c"
134 /** @brief shows an exception content and the associated stack if available */
135 void xbt_ex_display(xbt_ex_t * e)
137 char *thrower = NULL;
138 if (e->pid != xbt_getpid())
139 thrower = bprintf(" on process %d",e->pid);
142 "** SimGrid: UNCAUGHT EXCEPTION received on %s(%d): category: %s; value: %d\n"
144 "** Thrown by %s()%s\n",
145 xbt_binary_name, xbt_getpid(),
146 xbt_ex_catname(e->category), e->value, e->msg,
147 e->procname, thrower ? thrower : " in this process");
148 XBT_CRITICAL("%s", e->msg);
151 if (xbt_initialized==0 || smx_cleaned) {
152 fprintf(stderr, "Ouch. SimGrid is not initialized yet, or already closing. No backtrace available.\n");
153 return; /* Not started yet or already closing. Trying to generate a backtrace would probably fail */
157 xbt_ex_setup_backtrace(e);
159 #ifdef HAVE_BACKTRACE
160 if (e->used && e->bt_strings) {
161 /* We have everything to build neat backtraces */
164 fprintf(stderr, "\n");
165 for (i = 0; i < e->used; i++) {
166 if (sg_cfg_get_boolean("exception/cutpath")) {
167 char* p = e->bt_strings[i];
168 xbt_str_rtrim(p, ":0123456789");
169 char* filename = strrchr(p, '/')+1;
170 char* end_of_message = strrchr(p, ' ');
172 int length = strlen(p)-strlen(end_of_message);
173 char* dest = malloc(length);
175 memcpy(dest, &p[0], length);
178 fprintf(stderr, "%s %s\n", dest, filename);
183 fprintf(stderr, "%s\n", e->bt_strings[i]);
192 "** In %s() at %s:%d\n"
193 "** (no backtrace available)\n",
194 e->func, e->file, e->line);
199 /* default __ex_terminate callback function */
200 void __xbt_ex_terminate_default(xbt_ex_t * e)
206 /* the externally visible API */
207 XBT_EXPORT_NO_IMPORT(xbt_running_ctx_fetcher_t) __xbt_running_ctx_fetch = &__xbt_ex_ctx_default;
208 XBT_EXPORT_NO_IMPORT(ex_term_cb_t) __xbt_ex_terminate = &__xbt_ex_terminate_default;
211 void xbt_ex_free(xbt_ex_t e)
218 for (i = 0; i < e.used; i++)
219 free(e.bt_strings[i]);
222 /* memset(e,0,sizeof(xbt_ex_t)); */
225 /** \brief returns a short name for the given exception category */
226 const char *xbt_ex_catname(xbt_errcat_t cat)
230 return "unknown error";
232 return "invalid argument";
234 return "out of bounds";
237 case not_found_error:
240 return "system error";
242 return "network error";
246 return "action canceled";
248 return "thread error";
250 return "host failed";
252 return "tracing error";
259 return "INVALID ERROR";
267 XBT_TEST_SUITE("xbt_ex", "Exception Handling");
269 XBT_TEST_UNIT("controlflow", test_controlflow, "basic nested control flow")
274 xbt_test_add("basic nested control flow");
278 xbt_test_fail("M1: n=%d (!= 1)", n);
282 xbt_test_fail("M2: n=%d (!= 2)", n);
284 THROWF(unknown_error, 0, "something");
288 xbt_test_fail("M3: n=%d (!= 3)", n);
295 xbt_test_fail("M2: n=%d (!= 5)", n);
297 THROWF(unknown_error, 0, "something");
301 xbt_test_fail("M3: n=%d (!= 6)", n);
306 xbt_test_fail("MX: n=%d (shouldn't reach this point)", n);
310 xbt_test_fail("M4: n=%d (!= 7)", n);
315 xbt_test_fail("M5: n=%d (!= 8)", n);
318 XBT_TEST_UNIT("value", test_value, "exception value passing")
323 THROWF(unknown_error, 2, "toto");
326 xbt_test_add("exception value passing");
327 if (ex.category != unknown_error)
328 xbt_test_fail("category=%d (!= 1)", (int)ex.category);
330 xbt_test_fail("value=%d (!= 2)", ex.value);
331 if (strcmp(ex.msg, "toto"))
332 xbt_test_fail("message=%s (!= toto)", ex.msg);
337 XBT_TEST_UNIT("variables", test_variables, "variable value preservation")
341 int XBT_ATTRIB_UNUSED r2;
345 r1 = r2 = v1 = v2 = 1234;
349 THROWF(unknown_error, 0, "toto");
352 xbt_test_add("variable preservation");
354 xbt_test_fail("r1=%d (!= 1234)", r1);
356 xbt_test_fail("v1=%d (!= 1234)", v1);
357 /* r2 is allowed to be destroyed because not volatile */
359 xbt_test_fail("v2=%d (!= 5678)", v2);
364 XBT_TEST_UNIT("cleanup", test_cleanup, "cleanup handling")
370 xbt_test_add("cleanup handling");
376 THROWF(1, 2, "blah");
380 xbt_test_fail("v1 = %d (!= 5678)", v1);
385 xbt_test_fail("v1 = %d (!= 5678)", v1);
386 if (!(ex.category == 1 && ex.value == 2 && !strcmp(ex.msg, "blah")))
387 xbt_test_fail("unexpected exception contents");
391 xbt_test_fail("xbt_ex_free not executed");
396 * The following is the example included in the documentation. It's a good
397 * idea to check its syntax even if we don't try to run it.
398 * And actually, it allows to put comments in the code despite doxygen.
400 static char *mallocex(int size)
405 #define SMALLAMOUNT 10
406 #define TOOBIG 100000000
408 #if 0 /* this contains syntax errors, actually */
409 static void bad_example(void)
418 char *cp1, *cp2, *cp3;
420 cp1 = mallocex(SMALLAMOUNT);
421 globalcontext->first = cp1;
422 cp2 = mallocex(TOOBIG);
423 cp3 = mallocex(SMALLAMOUNT);
433 printf("cp3=%s", cp3);
436 /* end_of_bad_example */
443 static void good_example(void)
445 global_context_t *global_context = xbt_malloc(sizeof(global_context_t));
449 char *volatile /*03 */ cp1 = NULL /*02 */ ;
450 char *volatile /*03 */ cp2 = NULL /*02 */ ;
451 char *volatile /*03 */ cp3 = NULL /*02 */ ;
453 cp1 = mallocex(SMALLAMOUNT);
454 global_context->first = cp1;
455 cp1 = NULL /*05 give away */ ;
456 cp2 = mallocex(TOOBIG);
457 cp3 = mallocex(SMALLAMOUNT);
461 TRY_CLEANUP { /*04 */
462 printf("cp3=%s", cp3 == NULL /*02 */ ? "" : cp3);
465 /*05 cp1 was given away */
468 /*05 global context untouched */
472 /* end_of_good_example */
474 #endif /* SIMGRID_TEST */