diff options
author | Ben Gamari <ben@smart-cactus.org> | 2016-04-11 00:49:06 +0200 |
---|---|---|
committer | Ben Gamari <ben@smart-cactus.org> | 2016-04-18 22:30:59 +0200 |
commit | 350ffc3e4c6b3aefd6ae621991564cc28f585d46 (patch) | |
tree | 79356a97282be911f056376fa8838d1906dd90e0 /rts/Libdw.c | |
parent | 32ddd96972301a03dc0d594bda76da426785e722 (diff) | |
download | haskell-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.c | 16 |
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, |