hare

[hare] The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

commit 72ad4065cac0d5c4e8f82ad5d41087c190e8021b
parent 3493a954cec6e8a4dc43794c6ba324a567d8f64f
Author: Drew DeVault <sir@cmpwn.com>
Date:   Thu,  4 Apr 2024 11:45:21 +0200

debug: fix issues with invalid frame pointers

If we link to code which is built without frame pointers, walking the
stack can crash the debug runtime. This tests each address in the
backtrace for validity before continuing the walk.

Fixes: https://todo.sr.ht/~sircmpwn/hare/935
Signed-off-by: Drew DeVault <sir@cmpwn.com>

Diffstat:
Mdebug/+aarch64/walk.ha | 3+++
Mdebug/+riscv64/walk.ha | 5++++-
Mdebug/+x86_64/walk.ha | 3+++
Mdebug/fault.ha | 1+
Adebug/testaddr.ha | 25+++++++++++++++++++++++++
5 files changed, 36 insertions(+), 1 deletion(-)

diff --git a/debug/+aarch64/walk.ha b/debug/+aarch64/walk.ha @@ -18,6 +18,9 @@ export fn next(frame: stackframe) (stackframe | done) = { case null => return done; case let next: *stackframe => + if (!isaddrmapped(next)) { + return done; + }; if (next.fp == null) { return done; }; diff --git a/debug/+riscv64/walk.ha b/debug/+riscv64/walk.ha @@ -18,7 +18,10 @@ export fn next(frame: stackframe) (stackframe | done) = { case null => return done; case let next: *stackframe => - if (next.fp == done) { + if (!isaddrmapped(next)) { + return done; + }; + if (next.fp == null) { return done; }; return *next; diff --git a/debug/+x86_64/walk.ha b/debug/+x86_64/walk.ha @@ -18,6 +18,9 @@ export fn next(frame: stackframe) (stackframe | done) = { case null => return done; case let next: *stackframe => + if (!isaddrmapped(next)) { + return done; + }; if (next.fp == null) { return done; }; diff --git a/debug/fault.ha b/debug/fault.ha @@ -59,6 +59,7 @@ fn signal_handler(sig: sig, info: *signal::siginfo, uctx: *opaque) void = { }; defer image::close(&self); + fmt::errorln("Backtrace:")!; backtrace(&self, frame); halt(); diff --git a/debug/testaddr.ha b/debug/testaddr.ha @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: MPL-2.0 +// (c) Hare authors <https://harelang.org> + +use rt; + +fn isaddrmapped(addr: *opaque) bool = { + // This is a hack, but it's a common pattern on POSIX for testing the + // validity of an address. + static let pipefd: [2]int = [0, 0]; + if (pipefd[0] == 0) { + match (rt::pipe2(&pipefd, 0)) { + case rt::errno => + return false; + case void => yield; + }; + }; + + match (rt::write(pipefd[1], addr, 1)) { + case let err: rt::errno => + assert(err == rt::EFAULT); + return false; + case size => + return true; + }; +};