Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Remove useless #includes
[simgrid.git] / src / xbt / ex.c
1 /* ex - Exception Handling                                                  */
2
3 /* Copyright (c) 2005-2015. The SimGrid Team.
4  * All rights reserved.                                                     */
5
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.                                                    */
10
11 /* This code is inspirated from the OSSP version (as retrieved back in 2004)*/
12 /* It was heavily modified to fit the SimGrid framework.                    */
13
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/>
19 **
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/.
22 **
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
26 **  copies.
27 **
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
39 **  SUCH DAMAGE.
40  */
41
42 /* The extensions made for the SimGrid project can either be distributed    */
43 /* under the same license, or under the LGPL v2.1                           */
44
45 #include <stdio.h>
46 #include <stdlib.h>
47
48 #include "src/internal_config.h"           /* execinfo when available */
49 #include "xbt/ex.h"
50 #include "xbt/str.h"
51 #include "xbt/synchro_core.h"
52 #include "src/xbt_modinter.h"       /* backtrace initialization headers */
53
54 #include "src/xbt/ex_interface.h"
55 #include "simgrid/sg_config.h"  /* Configuration mechanism of SimGrid */
56
57 #include "simgrid/simix.h" /* SIMIX_process_self_get_name() */
58
59 #undef HAVE_BACKTRACE
60 #if HAVE_EXECINFO_H && HAVE_POPEN && defined(ADDR2LINE)
61 # define HAVE_BACKTRACE 1       /* Hello linux box */
62 #endif
63
64 #if defined(_WIN32) && defined(_M_IX86) && !defined(__GNUC__)
65 # define HAVE_BACKTRACE 1       /* Hello x86 windows box */
66 #endif
67
68 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(xbt_ex, xbt, "Exception mecanism");
69
70 XBT_EXPORT_NO_IMPORT(const xbt_running_ctx_t) __xbt_ex_ctx_initializer = XBT_RUNNING_CTX_INITIALIZER;
71
72 /* default __ex_ctx callback function */
73 xbt_running_ctx_t *__xbt_ex_ctx_default(void)
74 {
75   /* Don't scream: this is a default which is never used (so, yes,
76      there is one setjump container by running entity).
77
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).
81
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)
84    */
85   static xbt_running_ctx_t ctx = XBT_RUNNING_CTX_INITIALIZER;
86
87   return &ctx;
88 }
89
90 /* Change raw libc symbols to file names and line numbers */
91 void xbt_ex_setup_backtrace(xbt_ex_t * e);
92
93 void xbt_backtrace_display(xbt_ex_t * e)
94 {
95   xbt_ex_setup_backtrace(e);
96
97 #ifdef HAVE_BACKTRACE
98   if (e->used == 0) {
99     fprintf(stderr, "(backtrace not set)\n");
100   } else {
101     fprintf(stderr, "Backtrace (displayed in process %s):\n", SIMIX_process_self_get_name());
102     for (int i = 1; i < e->used; i++)       /* no need to display "xbt_backtrace_display" */
103       fprintf(stderr, "---> %s\n", e->bt_strings[i] + 4);
104   }
105
106   /* don't fool xbt_ex_free with uninitialized msg field */
107   e->msg = NULL;
108   xbt_ex_free(*e);
109 #else
110   XBT_ERROR("No backtrace on this arch");
111 #endif
112 }
113
114 /** \brief show the backtrace of the current point (lovely while debuging) */
115 void xbt_backtrace_display_current(void)
116 {
117   xbt_ex_t e;
118   xbt_backtrace_current(&e);
119   xbt_backtrace_display(&e);
120 }
121
122 #if HAVE_EXECINFO_H && HAVE_POPEN && defined(ADDR2LINE)
123 # include "src/xbt/backtrace_linux.c"
124 #else
125 # include "src/xbt/backtrace_dummy.c"
126 #endif
127
128 /** @brief shows an exception content and the associated stack if available */
129 void xbt_ex_display(xbt_ex_t * e)
130 {
131   char *thrower = NULL;
132   if (e->pid != xbt_getpid())
133     thrower = bprintf(" on process %d",e->pid);
134
135   fprintf(stderr, "** SimGrid: UNCAUGHT EXCEPTION received on %s(%d): category: %s; value: %d\n"
136           "** %s\n"
137           "** Thrown by %s()%s\n",
138           xbt_binary_name, xbt_getpid(), xbt_ex_catname(e->category), e->value, e->msg,
139           e->procname, thrower ? thrower : " in this process");
140   XBT_CRITICAL("%s", e->msg);
141   xbt_free(thrower);
142
143   if (xbt_initialized==0 || smx_cleaned) {
144     fprintf(stderr, "Ouch. SimGrid is not initialized yet, or already closing. No backtrace available.\n");
145     return; /* Not started yet or already closing. Trying to generate a backtrace would probably fail */
146   }
147
148   if (!e->bt_strings)
149     xbt_ex_setup_backtrace(e);
150
151 #ifdef HAVE_BACKTRACE
152   if (e->used && e->bt_strings) {
153     /* We have everything to build neat backtraces */
154     int i;
155     int cutpath = 0;
156     TRY { // We don't want to have an exception while checking how to deal with the one we already have, do we?
157       cutpath = xbt_cfg_get_boolean("exception/cutpath");
158     } CATCH_ANONYMOUS { }
159
160     fprintf(stderr, "\n");
161     for (i = 0; i < e->used; i++) {
162         
163       if (cutpath) {
164         char* p = e->bt_strings[i];
165         xbt_str_rtrim(p, ":0123456789");
166         char* filename = strrchr(p, '/')+1;
167         char* end_of_message  = strrchr(p, ' ');
168
169         int length = strlen(p)-strlen(end_of_message);
170         char* dest = malloc(length);
171
172         memcpy(dest, &p[0], length);
173         dest[length] = 0;
174
175         fprintf(stderr, "%s %s\n", dest, filename);
176
177         free(dest);
178       }
179       else {
180         fprintf(stderr, "%s\n", e->bt_strings[i]);
181       }
182     }
183   } else
184 #endif
185     fprintf(stderr, "\n"
186         "**   In %s() at %s:%d\n"
187         "**   (no backtrace available)\n", e->func, e->file, e->line);
188 }
189
190 /* default __ex_terminate callback function */
191 void __xbt_ex_terminate_default(xbt_ex_t * e)
192 {
193   xbt_ex_display(e);
194   xbt_abort();
195 }
196
197 /* the externally visible API */
198 XBT_EXPORT_NO_IMPORT(xbt_running_ctx_fetcher_t) __xbt_running_ctx_fetch = &__xbt_ex_ctx_default;
199 XBT_EXPORT_NO_IMPORT(ex_term_cb_t) __xbt_ex_terminate = &__xbt_ex_terminate_default;
200
201 void xbt_ex_free(xbt_ex_t e)
202 {
203   free(e.msg);
204
205   if (e.bt_strings) {
206     for (int i = 0; i < e.used; i++)
207       free(e.bt_strings[i]);
208     free(e.bt_strings);
209   }
210 }
211
212 /** \brief returns a short name for the given exception category */
213 const char *xbt_ex_catname(xbt_errcat_t cat)
214 {
215   switch (cat) {
216   case unknown_error:
217     return "unknown error";
218   case arg_error:
219     return "invalid argument";
220   case bound_error:
221     return "out of bounds";
222   case mismatch_error:
223     return "mismatch";
224   case not_found_error:
225     return "not found";
226   case system_error:
227     return "system error";
228   case network_error:
229     return "network error";
230   case timeout_error:
231     return "timeout";
232   case cancel_error:
233     return "action canceled";
234   case thread_error:
235     return "thread error";
236   case host_error:
237     return "host failed";
238   case tracing_error:
239     return "tracing error";
240   case io_error:
241     return "io error";
242   case vm_error:
243     return "vm error";
244   }
245   return "INVALID ERROR";
246 }
247
248 #ifdef SIMGRID_TEST
249 #include <stdio.h>
250 #include "xbt/ex.h"
251
252 XBT_TEST_SUITE("xbt_ex", "Exception Handling");
253
254 XBT_TEST_UNIT("controlflow", test_controlflow, "basic nested control flow")
255 {
256   xbt_ex_t ex;
257   volatile int n = 1;
258
259   xbt_test_add("basic nested control flow");
260
261   TRY {
262     if (n != 1)
263       xbt_test_fail("M1: n=%d (!= 1)", n);
264     n++;
265     TRY {
266       if (n != 2)
267         xbt_test_fail("M2: n=%d (!= 2)", n);
268       n++;
269       THROWF(unknown_error, 0, "something");
270     } CATCH(ex) {
271       if (n != 3)
272         xbt_test_fail("M3: n=%d (!= 3)", n);
273       n++;
274       xbt_ex_free(ex);
275     }
276     n++;
277     TRY {
278       if (n != 5)
279         xbt_test_fail("M2: n=%d (!= 5)", n);
280       n++;
281       THROWF(unknown_error, 0, "something");
282     } CATCH_ANONYMOUS {
283       if (n != 6)
284         xbt_test_fail("M3: n=%d (!= 6)", n);
285       n++;
286       RETHROW;
287       n++;
288     }
289     xbt_test_fail("MX: n=%d (shouldn't reach this point)", n);
290   } CATCH(ex) {
291     if (n != 7)
292       xbt_test_fail("M4: n=%d (!= 7)", n);
293     n++;
294     xbt_ex_free(ex);
295   }
296   if (n != 8)
297     xbt_test_fail("M5: n=%d (!= 8)", n);
298 }
299
300 XBT_TEST_UNIT("value", test_value, "exception value passing")
301 {
302   xbt_ex_t ex;
303
304   TRY {
305     THROWF(unknown_error, 2, "toto");
306   } CATCH(ex) {
307     xbt_test_add("exception value passing");
308     if (ex.category != unknown_error)
309       xbt_test_fail("category=%d (!= 1)", (int)ex.category);
310     if (ex.value != 2)
311       xbt_test_fail("value=%d (!= 2)", ex.value);
312     if (strcmp(ex.msg, "toto"))
313       xbt_test_fail("message=%s (!= toto)", ex.msg);
314     xbt_ex_free(ex);
315   }
316 }
317
318 XBT_TEST_UNIT("variables", test_variables, "variable value preservation")
319 {
320   xbt_ex_t ex;
321   int r1;
322   int XBT_ATTRIB_UNUSED r2;
323   int v1;
324   volatile int v2;
325
326   r1 = r2 = v1 = v2 = 1234;
327   TRY {
328     r2 = 5678;
329     v2 = 5678;
330     THROWF(unknown_error, 0, "toto");
331   } CATCH(ex) {
332     xbt_test_add("variable preservation");
333     if (r1 != 1234)
334       xbt_test_fail("r1=%d (!= 1234)", r1);
335     if (v1 != 1234)
336       xbt_test_fail("v1=%d (!= 1234)", v1);
337     /* r2 is allowed to be destroyed because not volatile */
338     if (v2 != 5678)
339       xbt_test_fail("v2=%d (!= 5678)", v2);
340     xbt_ex_free(ex);
341   }
342 }
343
344 XBT_TEST_UNIT("cleanup", test_cleanup, "cleanup handling")
345 {
346   xbt_ex_t ex;
347   volatile int v1;
348   int c;
349
350   xbt_test_add("cleanup handling");
351
352   v1 = 1234;
353   c = 0;
354   TRY {
355     v1 = 5678;
356     THROWF(1, 2, "blah");
357   }
358   TRY_CLEANUP {
359     if (v1 != 5678)
360       xbt_test_fail("v1 = %d (!= 5678)", v1);
361     c = 1;
362   } CATCH(ex) {
363     if (v1 != 5678)
364       xbt_test_fail("v1 = %d (!= 5678)", v1);
365     if (!(ex.category == 1 && ex.value == 2 && !strcmp(ex.msg, "blah")))
366       xbt_test_fail("unexpected exception contents");
367     xbt_ex_free(ex);
368   }
369   if (!c)
370     xbt_test_fail("xbt_ex_free not executed");
371 }
372
373 /*
374  * The following is the example included in the documentation. It's a good
375  * idea to check its syntax even if we don't try to run it.
376  * And actually, it allows to put comments in the code despite doxygen.
377  */
378 static char *mallocex(int size)
379 {
380   return NULL;
381 }
382
383 #define SMALLAMOUNT 10
384 #define TOOBIG 100000000
385
386 typedef struct {
387   char *first;
388 } global_context_t;
389
390 static void good_example(void)
391 {
392   global_context_t *global_context = xbt_malloc(sizeof(global_context_t));
393
394   /* GOOD_EXAMPLE */
395   {                             /*01 */
396     char *volatile /*03 */ cp1 = NULL /*02 */ ;
397     char *volatile /*03 */ cp2 = NULL /*02 */ ;
398     char *volatile /*03 */ cp3 = NULL /*02 */ ;
399     TRY {
400       cp1 = mallocex(SMALLAMOUNT);
401       global_context->first = cp1;
402       cp1 = NULL /*05 give away */ ;
403       cp2 = mallocex(TOOBIG);
404       cp3 = mallocex(SMALLAMOUNT);
405       strcpy(cp1, "foo");
406       strcpy(cp2, "bar");
407     }
408     TRY_CLEANUP {               /*04 */
409       printf("cp3=%s", cp3 == NULL /*02 */ ? "" : cp3);
410       free(cp3);
411       free(cp2);
412       /*05 cp1 was given away */
413     }
414     CATCH_ANONYMOUS {
415       /*05 global context untouched */
416       RETHROW;
417     }
418   }
419   /* end_of_good_example */
420 }
421 #endif                          /* SIMGRID_TEST */