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 "src/internal_config.h" /* execinfo when available */
51 #include "xbt/synchro_core.h"
52 #include "src/xbt_modinter.h" /* backtrace initialization headers */
54 #include "src/xbt/ex_interface.h"
55 #include "simgrid/sg_config.h" /* Configuration mechanism of SimGrid */
57 #include "simgrid/simix.h" /* SIMIX_process_self_get_name() */
59 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(xbt_ex, xbt, "Exception mechanism");
61 XBT_EXPORT_NO_IMPORT(const xbt_running_ctx_t) __xbt_ex_ctx_initializer = XBT_RUNNING_CTX_INITIALIZER;
63 /* default __ex_ctx callback function */
64 xbt_running_ctx_t *__xbt_ex_ctx_default(void)
66 /* Don't scream: this is a default which is never used (so, yes,
67 there is one setjump container by running entity).
69 This default gets overriden in xbt/xbt_os_thread.c so that it works in
70 real life and in simulation when using threads to implement the simulation
71 processes (ie, with pthreads and on windows).
73 It also gets overriden in xbt/context.c when using ucontexts (as well as
74 in Java for now, but after the java overhaul, it will get cleaned out)
76 static xbt_running_ctx_t ctx = XBT_RUNNING_CTX_INITIALIZER;
81 /* Change raw libc symbols to file names and line numbers */
82 void xbt_ex_setup_backtrace(xbt_ex_t * e);
84 void xbt_backtrace_display(xbt_ex_t * e)
86 xbt_ex_setup_backtrace(e);
90 fprintf(stderr, "(backtrace not set)\n");
92 fprintf(stderr, "Backtrace (displayed in process %s):\n", SIMIX_process_self_get_name());
93 for (int i = 1; i < e->used; i++) /* no need to display "xbt_backtrace_display" */
94 fprintf(stderr, "---> %s\n", e->bt_strings[i] + 4);
97 /* don't fool xbt_ex_free with uninitialized msg field */
101 XBT_ERROR("No backtrace on this arch");
105 /** \brief show the backtrace of the current point (lovely while debuging) */
106 void xbt_backtrace_display_current(void)
109 xbt_backtrace_current(&e);
110 xbt_backtrace_display(&e);
113 #if HAVE_BACKTRACE && HAVE_EXECINFO_H && HAVE_POPEN && defined(ADDR2LINE)
114 # include "src/xbt/backtrace_linux.c"
116 # include "src/xbt/backtrace_dummy.c"
119 /** @brief shows an exception content and the associated stack if available */
120 void xbt_ex_display(xbt_ex_t * e)
122 char *thrower = NULL;
123 if (e->pid != xbt_getpid())
124 thrower = bprintf(" on process %d",e->pid);
126 fprintf(stderr, "** SimGrid: UNCAUGHT EXCEPTION received on %s(%d): category: %s; value: %d\n"
128 "** Thrown by %s()%s\n",
129 xbt_binary_name, xbt_getpid(), xbt_ex_catname(e->category), e->value, e->msg,
130 e->procname, thrower ? thrower : " in this process");
131 XBT_CRITICAL("%s", e->msg);
134 if (xbt_initialized==0 || smx_cleaned) {
135 fprintf(stderr, "Ouch. SimGrid is not initialized yet, or already closing. No backtrace available.\n");
136 return; /* Not started yet or already closing. Trying to generate a backtrace would probably fail */
140 xbt_ex_setup_backtrace(e);
142 #ifdef HAVE_BACKTRACE
143 if (e->used && e->bt_strings) {
144 /* We have everything to build neat backtraces */
147 TRY { // We don't want to have an exception while checking how to deal with the one we already have, do we?
148 cutpath = xbt_cfg_get_boolean("exception/cutpath");
149 } CATCH_ANONYMOUS { }
151 fprintf(stderr, "\n");
152 for (i = 0; i < e->used; i++) {
155 char* p = e->bt_strings[i];
156 xbt_str_rtrim(p, ":0123456789");
157 char* filename = strrchr(p, '/')+1;
158 char* end_of_message = strrchr(p, ' ');
160 int length = strlen(p)-strlen(end_of_message);
161 char* dest = malloc(length);
163 memcpy(dest, &p[0], length);
166 fprintf(stderr, "%s %s\n", dest, filename);
171 fprintf(stderr, "%s\n", e->bt_strings[i]);
177 "** In %s() at %s:%d\n"
178 "** (no backtrace available)\n", e->func, e->file, e->line);
181 /* default __ex_terminate callback function */
182 void __xbt_ex_terminate_default(xbt_ex_t * e)
188 /* the externally visible API */
189 XBT_EXPORT_NO_IMPORT(xbt_running_ctx_fetcher_t) __xbt_running_ctx_fetch = &__xbt_ex_ctx_default;
190 XBT_EXPORT_NO_IMPORT(ex_term_cb_t) __xbt_ex_terminate = &__xbt_ex_terminate_default;
192 void xbt_ex_free(xbt_ex_t e)
197 for (int i = 0; i < e.used; i++)
198 free(e.bt_strings[i]);
203 /** \brief returns a short name for the given exception category */
204 const char *xbt_ex_catname(xbt_errcat_t cat)
208 return "unknown error";
210 return "invalid argument";
212 return "out of bounds";
215 case not_found_error:
218 return "system error";
220 return "network error";
224 return "action canceled";
226 return "thread error";
228 return "host failed";
230 return "tracing error";
236 return "INVALID ERROR";
243 XBT_TEST_SUITE("xbt_ex", "Exception Handling");
245 XBT_TEST_UNIT("controlflow", test_controlflow, "basic nested control flow")
250 xbt_test_add("basic nested control flow");
254 xbt_test_fail("M1: n=%d (!= 1)", n);
258 xbt_test_fail("M2: n=%d (!= 2)", n);
260 THROWF(unknown_error, 0, "something");
263 xbt_test_fail("M3: n=%d (!= 3)", n);
270 xbt_test_fail("M2: n=%d (!= 5)", n);
272 THROWF(unknown_error, 0, "something");
275 xbt_test_fail("M3: n=%d (!= 6)", n);
280 xbt_test_fail("MX: n=%d (shouldn't reach this point)", n);
283 xbt_test_fail("M4: n=%d (!= 7)", n);
288 xbt_test_fail("M5: n=%d (!= 8)", n);
291 XBT_TEST_UNIT("value", test_value, "exception value passing")
296 THROWF(unknown_error, 2, "toto");
298 xbt_test_add("exception value passing");
299 if (ex.category != unknown_error)
300 xbt_test_fail("category=%d (!= 1)", (int)ex.category);
302 xbt_test_fail("value=%d (!= 2)", ex.value);
303 if (strcmp(ex.msg, "toto"))
304 xbt_test_fail("message=%s (!= toto)", ex.msg);
309 XBT_TEST_UNIT("variables", test_variables, "variable value preservation")
313 int XBT_ATTRIB_UNUSED r2;
317 r1 = r2 = v1 = v2 = 1234;
321 THROWF(unknown_error, 0, "toto");
323 xbt_test_add("variable preservation");
325 xbt_test_fail("r1=%d (!= 1234)", r1);
327 xbt_test_fail("v1=%d (!= 1234)", v1);
328 /* r2 is allowed to be destroyed because not volatile */
330 xbt_test_fail("v2=%d (!= 5678)", v2);
335 XBT_TEST_UNIT("cleanup", test_cleanup, "cleanup handling")
341 xbt_test_add("cleanup handling");
347 THROWF(1, 2, "blah");
351 xbt_test_fail("v1 = %d (!= 5678)", v1);
355 xbt_test_fail("v1 = %d (!= 5678)", v1);
356 if (!(ex.category == 1 && ex.value == 2 && !strcmp(ex.msg, "blah")))
357 xbt_test_fail("unexpected exception contents");
361 xbt_test_fail("xbt_ex_free not executed");
365 * The following is the example included in the documentation. It's a good
366 * idea to check its syntax even if we don't try to run it.
367 * And actually, it allows to put comments in the code despite doxygen.
369 static char *mallocex(int size)
374 #define SMALLAMOUNT 10
375 #define TOOBIG 100000000
381 static void good_example(void)
383 global_context_t *global_context = xbt_malloc(sizeof(global_context_t));
387 char *volatile /*03 */ cp1 = NULL /*02 */ ;
388 char *volatile /*03 */ cp2 = NULL /*02 */ ;
389 char *volatile /*03 */ cp3 = NULL /*02 */ ;
391 cp1 = mallocex(SMALLAMOUNT);
392 global_context->first = cp1;
393 cp1 = NULL /*05 give away */ ;
394 cp2 = mallocex(TOOBIG);
395 cp3 = mallocex(SMALLAMOUNT);
396 strncpy(cp1, "foo",3);
397 strncpy(cp2, "bar",3);
399 TRY_CLEANUP { /*04 */
400 printf("cp3=%s", cp3 == NULL /*02 */ ? "" : cp3);
403 /*05 cp1 was given away */
406 /*05 global context untouched */
410 /* end_of_good_example */
412 #endif /* SIMGRID_TEST */