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/portable.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() */
60 #if defined(HAVE_EXECINFO_H) && defined(HAVE_POPEN) && defined(ADDR2LINE)
61 # define HAVE_BACKTRACE 1 /* Hello linux box */
64 #if defined(_XBT_WIN32) && defined(_M_IX86) && !defined(__GNUC__)
65 # define HAVE_BACKTRACE 1 /* Hello x86 windows box */
69 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(xbt_ex, xbt, "Exception mecanism");
71 XBT_EXPORT_NO_IMPORT(const xbt_running_ctx_t) __xbt_ex_ctx_initializer = XBT_RUNNING_CTX_INITIALIZER;
73 /* default __ex_ctx callback function */
74 xbt_running_ctx_t *__xbt_ex_ctx_default(void)
76 /* Don't scream: this is a default which is never used (so, yes,
77 there is one setjump container by running entity).
79 This default gets overriden in xbt/xbt_os_thread.c so that it works in
80 real life and in simulation when using threads to implement the simulation
81 processes (ie, with pthreads and on windows).
83 It also gets overriden in xbt/context.c when using ucontexts (as well as
84 in Java for now, but after the java overhaul, it will get cleaned out)
86 static xbt_running_ctx_t ctx = XBT_RUNNING_CTX_INITIALIZER;
91 /* Change raw libc symbols to file names and line numbers */
92 void xbt_ex_setup_backtrace(xbt_ex_t * e);
94 void xbt_backtrace_display(xbt_ex_t * e)
96 xbt_ex_setup_backtrace(e);
100 fprintf(stderr, "(backtrace not set)\n");
104 fprintf(stderr, "Backtrace (displayed in process %s):\n",
105 SIMIX_process_self_get_name());
106 for (i = 1; i < e->used; i++) /* no need to display "xbt_backtrace_display" */
107 fprintf(stderr, "---> %s\n", e->bt_strings[i] + 4);
110 /* don't fool xbt_ex_free with uninitialized msg field */
115 XBT_ERROR("No backtrace on this arch");
119 /** \brief show the backtrace of the current point (lovely while debuging) */
120 void xbt_backtrace_display_current(void)
123 xbt_backtrace_current(&e);
124 xbt_backtrace_display(&e);
127 #if defined(HAVE_EXECINFO_H) && defined(HAVE_POPEN) && defined(ADDR2LINE)
128 # include "src/xbt/backtrace_linux.c"
129 #elif (defined(_XBT_WIN32) && defined (_M_IX86)) && !defined(__GNUC__)
130 # include "src/xbt/backtrace_windows.c"
132 # include "src/xbt/backtrace_dummy.c"
135 /** @brief shows an exception content and the associated stack if available */
136 void xbt_ex_display(xbt_ex_t * e)
138 char *thrower = NULL;
139 if (e->pid != xbt_getpid())
140 thrower = bprintf(" on process %d",e->pid);
143 "** SimGrid: UNCAUGHT EXCEPTION received on %s(%d): category: %s; value: %d\n"
145 "** Thrown by %s()%s\n",
146 xbt_binary_name, xbt_getpid(),
147 xbt_ex_catname(e->category), e->value, e->msg,
148 e->procname, thrower ? thrower : " in this process");
149 XBT_CRITICAL("%s", e->msg);
152 if (xbt_initialized==0 || smx_cleaned) {
153 fprintf(stderr, "Ouch. SimGrid is not initialized yet, or already closing. No backtrace available.\n");
154 return; /* Not started yet or already closing. Trying to generate a backtrace would probably fail */
158 xbt_ex_setup_backtrace(e);
160 #ifdef HAVE_BACKTRACE
161 if (e->used && e->bt_strings) {
162 /* We have everything to build neat backtraces */
165 TRY { // We don't want to have an exception while checking how to deal with the one we already have, do we?
166 cutpath = sg_cfg_get_boolean("exception/cutpath");
167 } CATCH_ANONYMOUS { }
169 fprintf(stderr, "\n");
170 for (i = 0; i < e->used; i++) {
173 char* p = e->bt_strings[i];
174 xbt_str_rtrim(p, ":0123456789");
175 char* filename = strrchr(p, '/')+1;
176 char* end_of_message = strrchr(p, ' ');
178 int length = strlen(p)-strlen(end_of_message);
179 char* dest = malloc(length);
181 memcpy(dest, &p[0], length);
184 fprintf(stderr, "%s %s\n", dest, filename);
189 fprintf(stderr, "%s\n", e->bt_strings[i]);
198 "** In %s() at %s:%d\n"
199 "** (no backtrace available)\n",
200 e->func, e->file, e->line);
205 /* default __ex_terminate callback function */
206 void __xbt_ex_terminate_default(xbt_ex_t * e)
212 /* the externally visible API */
213 XBT_EXPORT_NO_IMPORT(xbt_running_ctx_fetcher_t) __xbt_running_ctx_fetch = &__xbt_ex_ctx_default;
214 XBT_EXPORT_NO_IMPORT(ex_term_cb_t) __xbt_ex_terminate = &__xbt_ex_terminate_default;
217 void xbt_ex_free(xbt_ex_t e)
224 for (i = 0; i < e.used; i++)
225 free(e.bt_strings[i]);
228 /* memset(e,0,sizeof(xbt_ex_t)); */
231 /** \brief returns a short name for the given exception category */
232 const char *xbt_ex_catname(xbt_errcat_t cat)
236 return "unknown error";
238 return "invalid argument";
240 return "out of bounds";
243 case not_found_error:
246 return "system error";
248 return "network error";
252 return "action canceled";
254 return "thread error";
256 return "host failed";
258 return "tracing error";
265 return "INVALID ERROR";
273 XBT_TEST_SUITE("xbt_ex", "Exception Handling");
275 XBT_TEST_UNIT("controlflow", test_controlflow, "basic nested control flow")
280 xbt_test_add("basic nested control flow");
284 xbt_test_fail("M1: n=%d (!= 1)", n);
288 xbt_test_fail("M2: n=%d (!= 2)", n);
290 THROWF(unknown_error, 0, "something");
294 xbt_test_fail("M3: n=%d (!= 3)", n);
301 xbt_test_fail("M2: n=%d (!= 5)", n);
303 THROWF(unknown_error, 0, "something");
307 xbt_test_fail("M3: n=%d (!= 6)", n);
312 xbt_test_fail("MX: n=%d (shouldn't reach this point)", n);
316 xbt_test_fail("M4: n=%d (!= 7)", n);
321 xbt_test_fail("M5: n=%d (!= 8)", n);
324 XBT_TEST_UNIT("value", test_value, "exception value passing")
329 THROWF(unknown_error, 2, "toto");
332 xbt_test_add("exception value passing");
333 if (ex.category != unknown_error)
334 xbt_test_fail("category=%d (!= 1)", (int)ex.category);
336 xbt_test_fail("value=%d (!= 2)", ex.value);
337 if (strcmp(ex.msg, "toto"))
338 xbt_test_fail("message=%s (!= toto)", ex.msg);
343 XBT_TEST_UNIT("variables", test_variables, "variable value preservation")
347 int XBT_ATTRIB_UNUSED r2;
351 r1 = r2 = v1 = v2 = 1234;
355 THROWF(unknown_error, 0, "toto");
358 xbt_test_add("variable preservation");
360 xbt_test_fail("r1=%d (!= 1234)", r1);
362 xbt_test_fail("v1=%d (!= 1234)", v1);
363 /* r2 is allowed to be destroyed because not volatile */
365 xbt_test_fail("v2=%d (!= 5678)", v2);
370 XBT_TEST_UNIT("cleanup", test_cleanup, "cleanup handling")
376 xbt_test_add("cleanup handling");
382 THROWF(1, 2, "blah");
386 xbt_test_fail("v1 = %d (!= 5678)", v1);
391 xbt_test_fail("v1 = %d (!= 5678)", v1);
392 if (!(ex.category == 1 && ex.value == 2 && !strcmp(ex.msg, "blah")))
393 xbt_test_fail("unexpected exception contents");
397 xbt_test_fail("xbt_ex_free not executed");
402 * The following is the example included in the documentation. It's a good
403 * idea to check its syntax even if we don't try to run it.
404 * And actually, it allows to put comments in the code despite doxygen.
406 static char *mallocex(int size)
411 #define SMALLAMOUNT 10
412 #define TOOBIG 100000000
418 static void good_example(void)
420 global_context_t *global_context = xbt_malloc(sizeof(global_context_t));
424 char *volatile /*03 */ cp1 = NULL /*02 */ ;
425 char *volatile /*03 */ cp2 = NULL /*02 */ ;
426 char *volatile /*03 */ cp3 = NULL /*02 */ ;
428 cp1 = mallocex(SMALLAMOUNT);
429 global_context->first = cp1;
430 cp1 = NULL /*05 give away */ ;
431 cp2 = mallocex(TOOBIG);
432 cp3 = mallocex(SMALLAMOUNT);
436 TRY_CLEANUP { /*04 */
437 printf("cp3=%s", cp3 == NULL /*02 */ ? "" : cp3);
440 /*05 cp1 was given away */
443 /*05 global context untouched */
447 /* end_of_good_example */
449 #endif /* SIMGRID_TEST */