summaryrefslogtreecommitdiff
path: root/rts/Libdw.c
diff options
context:
space:
mode:
authorBen Gamari <ben@smart-cactus.org>2016-04-11 00:49:06 +0200
committerBen Gamari <ben@smart-cactus.org>2016-04-18 22:30:59 +0200
commit350ffc3e4c6b3aefd6ae621991564cc28f585d46 (patch)
tree79356a97282be911f056376fa8838d1906dd90e0 /rts/Libdw.c
parent32ddd96972301a03dc0d594bda76da426785e722 (diff)
downloadhaskell-350ffc3e4c6b3aefd6ae621991564cc28f585d46.tar.gz
rts: Limit maximum backtrace depth
This prevents us from entering an infinite loop in the event of a hitting bad unwinding information.
Diffstat (limited to 'rts/Libdw.c')
-rw-r--r--rts/Libdw.c16
1 files changed, 13 insertions, 3 deletions
diff --git a/rts/Libdw.c b/rts/Libdw.c
index 8c3c58156a..e7968407a6 100644
--- a/rts/Libdw.c
+++ b/rts/Libdw.c
@@ -16,6 +16,8 @@
#include <dwarf.h>
#include <unistd.h>
+const int max_backtrace_depth = 5000;
+
static BacktraceChunk *backtraceAllocChunk(BacktraceChunk *next) {
BacktraceChunk *chunk = stgMallocBytes(sizeof(BacktraceChunk),
"backtraceAllocChunk");
@@ -57,7 +59,10 @@ void backtraceFree(Backtrace *bt) {
struct LibdwSession_ {
Dwfl *dwfl;
- Backtrace *cur_bt; // The current backtrace we are collecting (if any)
+
+ // The current backtrace we are collecting (if any)
+ Backtrace *cur_bt;
+ int max_depth;
};
static const Dwfl_Thread_Callbacks thread_cbs;
@@ -230,8 +235,12 @@ static int getBacktraceFrameCb(Dwfl_Frame *frame, void *arg) {
pc -= 1; // TODO: is this right?
backtracePush(session->cur_bt, (StgPtr) (uintptr_t) pc);
}
-
- return DWARF_CB_OK;
+ session->max_depth--;
+ if (session->max_depth == 0) {
+ return DWARF_CB_ABORT;
+ } else {
+ return DWARF_CB_OK;
+ }
}
Backtrace *libdwGetBacktrace(LibdwSession *session) {
@@ -242,6 +251,7 @@ Backtrace *libdwGetBacktrace(LibdwSession *session) {
Backtrace *bt = backtraceAlloc();
session->cur_bt = bt;
+ session->max_depth = max_backtrace_depth;
int pid = getpid();
int ret = dwfl_getthread_frames(session->dwfl, pid,