Skip to content

Commit 788e3ef

Browse files
committed
- Added a nice little signal handler that can gracefully recover from stack overflows, but causes other segmentation faults to make the executable die.
- Only implemented for the main function of the bootstrapped compiler. We will need to use some more code to make omc recover from a failed CORBA command or model instantiation, etc. git-svn-id: https://openmodelica.org/svn/OpenModelica/trunk@15357 f25d12d1-65f4-0310-ae8a-bbce733d8d8e
1 parent e5b28d3 commit 788e3ef

File tree

4 files changed

+190
-3
lines changed

4 files changed

+190
-3
lines changed

SimulationRuntime/c/Makefile.common

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ RUNTIME_HEADERS = $(LIBF2CHEADER) \
2424
./meta/meta_modelica_builtin.h \
2525
./meta/meta_modelica.h \
2626
./meta/meta_modelica_real.h \
27+
./meta/meta_modelica_segv.h \
2728
./meta/meta_modelica_string_lit.h \
2829
./openmodelica_func.h \
2930
./openmodelica.h \

SimulationRuntime/c/meta/meta_modelica.h

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ extern "C" {
4646
#include "mmc_gc.h"
4747
#include "meta_modelica_string_lit.h"
4848
#include "meta_modelica_builtin.h"
49+
#include "meta_modelica_segv.h"
4950
#include <stdio.h>
5051
#include <stdlib.h>
5152
#include <stdarg.h>
@@ -631,12 +632,16 @@ extern jmp_buf mmc_jumper[MMC_JMP_BUF_SIZE];
631632
extern int jmp_buf_index;
632633
*/
633634
extern jmp_buf *mmc_jumper;
634-
#define MMC_TRY() { jmp_buf new_mmc_jumper, *old_jumper; old_jumper = mmc_jumper; mmc_jumper = &new_mmc_jumper; if (setjmp(new_mmc_jumper) == 0) {
635+
#define MMC_TRY_INTERNAL(X) { jmp_buf new_mmc_jumper, *old_jumper; old_jumper = X; X = &new_mmc_jumper; if (setjmp(new_mmc_jumper) == 0) {
636+
#define MMC_TRY() MMC_TRY_INTERNAL(mmc_jumper)
637+
635638
#if !defined(_MSC_VER)
636-
#define MMC_CATCH() } mmc_jumper = old_jumper; mmc_GC_unwind_roots_state(mmc_GC_local_state); mmc_catch_dummy_fn();}
639+
#define MMC_CATCH_INTERNAL(X) } X = old_jumper; mmc_GC_unwind_roots_state(mmc_GC_local_state); mmc_catch_dummy_fn();}
637640
#else
638-
#define MMC_CATCH() } mmc_jumper = old_jumper; mmc_GC_unwind_roots_state(mmc_GC_local_state);}
641+
#define MMC_CATCH_INTERNAL(X) } X = old_jumper; mmc_GC_unwind_roots_state(mmc_GC_local_state);}
639642
#endif
643+
#define MMC_CATCH() MMC_CATCH_INTERNAL(mmc_jumper)
644+
640645
#define MMC_THROW() longjmp(*mmc_jumper,1)
641646
#define MMC_ELSE() } else {
642647

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
/*
2+
* This file is part of OpenModelica.
3+
*
4+
* Copyright (c) 1998-CurrentYear, Open Source Modelica Consortium (OSMC),
5+
* c/o Linköpings universitet, Department of Computer and Information Science,
6+
* SE-58183 Linköping, Sweden.
7+
*
8+
* All rights reserved.
9+
*
10+
* THIS PROGRAM IS PROVIDED UNDER THE TERMS OF THE BSD NEW LICENSE OR THE
11+
* GPL VERSION 3 LICENSE OR THE OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2.
12+
* ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES
13+
* RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3,
14+
* ACCORDING TO RECIPIENTS CHOICE.
15+
*
16+
* The OpenModelica software and the OSMC (Open Source Modelica Consortium)
17+
* Public License (OSMC-PL) are obtained from OSMC, either from the above
18+
* address, from the URLs: http://www.openmodelica.org or
19+
* http://www.ida.liu.se/projects/OpenModelica, and in the OpenModelica
20+
* distribution. GNU version 3 is obtained from:
21+
* http://www.gnu.org/copyleft/gpl.html. The New BSD License is obtained from:
22+
* http://www.opensource.org/licenses/BSD-3-Clause.
23+
*
24+
* This program is distributed WITHOUT ANY WARRANTY; without even the implied
25+
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, EXCEPT AS
26+
* EXPRESSLY SET FORTH IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE
27+
* CONDITIONS OF OSMC-PL.
28+
*
29+
*/
30+
31+
/* Stack overflow handling */
32+
#include <stdlib.h>
33+
#include <stdio.h>
34+
#include <signal.h>
35+
#include <stdio.h>
36+
#include <signal.h>
37+
#include <execinfo.h>
38+
#include <sys/time.h>
39+
#include <sys/resource.h>
40+
#include <assert.h>
41+
#include <pthread.h>
42+
#include <setjmp.h>
43+
#include <ucontext.h>
44+
45+
/* Really 64kB memory for this? Oh well... */
46+
#define TRACE_NFRAMES 65536
47+
/* If we find a SIGSEGV near the end of the stack, it is probably due to a stack overflow. 64kB for a function frame seems reasonable. */
48+
#define LIMIT_FOR_STACK_OVERFLOW 65536
49+
50+
jmp_buf *mmc_stack_overflow_jumper;
51+
static void *trace[TRACE_NFRAMES];
52+
static int trace_size;
53+
static int trace_size_skip=0; /* First index we should use; that is skip handler, etc */
54+
static void *stackBottom;
55+
static struct sigaction default_segv_action;
56+
57+
void printStacktraceMessages() {
58+
int i,j=-1,k;
59+
char **messages = (char **)NULL;
60+
messages = backtrace_symbols(trace, trace_size);
61+
fprintf(stderr,"[bt] Execution path:\n");
62+
for (i=trace_size_skip; i<trace_size; ++i)
63+
{
64+
if (i<trace_size-1 && trace[i] == trace[i+1]) {
65+
j=j==-1?i:j;
66+
} else if (j>=0) {
67+
k=19-fprintf(stderr,"[bt] #%d..%d", j-trace_size_skip, i-trace_size_skip);
68+
while (k-->0) fprintf(stderr, " ");
69+
fprintf(stderr,"%s\n", messages[i]);
70+
j=-1;
71+
} else {
72+
k=19-fprintf(stderr,"[bt] #%d ", i-trace_size_skip);
73+
while (k-->0) fprintf(stderr, " ");
74+
fprintf(stderr,"%s\n", messages[i]);
75+
}
76+
}
77+
if (trace_size==TRACE_NFRAMES) {
78+
fprintf(stderr,"[bt] [...]\n");
79+
}
80+
free(messages);
81+
}
82+
83+
static inline void setTrace(int numSkip, int numFrames) {
84+
trace_size = 0;
85+
trace_size = backtrace(trace, numFrames == 0 ? TRACE_NFRAMES : numFrames > TRACE_NFRAMES ? TRACE_NFRAMES : numFrames);
86+
trace_size_skip = numSkip;
87+
}
88+
89+
static sigset_t segvset;
90+
91+
static void handler(int signo, siginfo_t *si, void *ptr)
92+
{
93+
int isStackOverflow;
94+
ucontext_t *uc = (ucontext_t *)ptr;
95+
isStackOverflow = si->si_addr < stackBottom && (si->si_addr > stackBottom - LIMIT_FOR_STACK_OVERFLOW);
96+
if (isStackOverflow) {
97+
setTrace(3,0);
98+
sigprocmask(SIG_UNBLOCK, &segvset, NULL);
99+
longjmp(*mmc_stack_overflow_jumper,1);
100+
}
101+
/* This backtrace uses very little stack-space, and segmentation faults we always want to print... */
102+
setTrace(3,16);
103+
write(2, "\nLimited backtrace at point of segmentation fault\n", 50);
104+
backtrace_symbols_fd(trace+trace_size_skip, trace_size-trace_size_skip, 2);
105+
sigaction(SIGSEGV, &default_segv_action, 0);
106+
}
107+
108+
static void getStackBase() {
109+
struct rlimit rl;
110+
size_t stackSize = 0;
111+
pthread_attr_t sattr;
112+
pthread_attr_init(&sattr);
113+
pthread_t thread = pthread_self();
114+
pthread_getattr_np(thread, &sattr);
115+
assert(0==getrlimit(RLIMIT_STACK,&rl));
116+
stackSize = rl.rlim_cur;
117+
assert(0==pthread_attr_getstack(&sattr, &stackBottom, &stackSize));
118+
assert(stackBottom);
119+
pthread_attr_destroy(&sattr);
120+
}
121+
122+
void init_metamodelica_segv_handler()
123+
{
124+
char *stack = (char*)malloc(SIGSTKSZ);
125+
stack_t ss = {
126+
.ss_size = SIGSTKSZ,
127+
.ss_sp = stack,
128+
};
129+
struct sigaction sa = {
130+
.sa_sigaction = handler,
131+
.sa_flags = SA_ONSTACK | SA_SIGINFO
132+
};
133+
getStackBase();
134+
sigaltstack(&ss, 0);
135+
sigfillset(&sa.sa_mask);
136+
sigaction(SIGSEGV, &sa, &default_segv_action);
137+
sigfillset(&segvset);
138+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* This file is part of OpenModelica.
3+
*
4+
* Copyright (c) 1998-CurrentYear, Open Source Modelica Consortium (OSMC),
5+
* c/o Linköpings universitet, Department of Computer and Information Science,
6+
* SE-58183 Linköping, Sweden.
7+
*
8+
* All rights reserved.
9+
*
10+
* THIS PROGRAM IS PROVIDED UNDER THE TERMS OF THE BSD NEW LICENSE OR THE
11+
* GPL VERSION 3 LICENSE OR THE OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2.
12+
* ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES
13+
* RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3,
14+
* ACCORDING TO RECIPIENTS CHOICE.
15+
*
16+
* The OpenModelica software and the OSMC (Open Source Modelica Consortium)
17+
* Public License (OSMC-PL) are obtained from OSMC, either from the above
18+
* address, from the URLs: http://www.openmodelica.org or
19+
* http://www.ida.liu.se/projects/OpenModelica, and in the OpenModelica
20+
* distribution. GNU version 3 is obtained from:
21+
* http://www.gnu.org/copyleft/gpl.html. The New BSD License is obtained from:
22+
* http://www.opensource.org/licenses/BSD-3-Clause.
23+
*
24+
* This program is distributed WITHOUT ANY WARRANTY; without even the implied
25+
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, EXCEPT AS
26+
* EXPRESSLY SET FORTH IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE
27+
* CONDITIONS OF OSMC-PL.
28+
*
29+
*/
30+
31+
/* Stack overflow handling */
32+
33+
#ifndef META_MODELICA_SEGV_H_
34+
#define META_MODELICA_SEGV_H_
35+
36+
extern jmp_buf *mmc_stack_overflow_jumper;
37+
#define MMC_TRY_STACK() MMC_TRY_INTERNAL(mmc_stack_overflow_jumper)
38+
#define MMC_CATCH_STACK() MMC_CATCH_INTERNAL(mmc_stack_overflow_jumper)
39+
40+
void printStacktraceMessages();
41+
void init_metamodelica_segv_handler();
42+
43+
#endif

0 commit comments

Comments
 (0)