mirror of
https://github.com/urbit/ares.git
synced 2024-11-26 09:57:56 +03:00
Enable guard page + bail:meme with stack traces
This commit is contained in:
parent
1e44565c53
commit
5efbc074e2
@ -43,15 +43,6 @@ impl<'closure> CCallback<'closure> {
|
||||
{
|
||||
let function: unsafe extern "C" fn(*mut c_void) -> *mut c_void = Self::call_closure::<F>;
|
||||
|
||||
// debug_assert_eq!(
|
||||
// std::mem::size_of::<&'closure mut F>(),
|
||||
// std::mem::size_of::<*const c_void>()
|
||||
// );
|
||||
// debug_assert_eq!(
|
||||
// std::mem::size_of_val(&function),
|
||||
// std::mem::size_of::<*const c_void>()
|
||||
// );
|
||||
|
||||
Self {
|
||||
function,
|
||||
input: closure as *mut F as *mut c_void,
|
||||
@ -91,12 +82,7 @@ pub fn call_with_guard<F: FnMut() -> Result>(
|
||||
ret_pp,
|
||||
);
|
||||
|
||||
// eprintln!("\r BEFORE:");
|
||||
// eprintln!("\r ret = {:?}", ret);
|
||||
// eprintln!("\r ret_p = {:p}, {:?}", ret_p as *mut Result, *(ret_p as *mut Result));
|
||||
// eprintln!("\r ret_pp = {:p}, {:p}, {:?}", ret_pp, *ret_pp, **(ret_pp as *mut *mut Result));
|
||||
if res == 0 {
|
||||
// TODO: come back to this
|
||||
permit_alloc(|| {
|
||||
let result_box = Box::from_raw(ret_p as *mut Result);
|
||||
*result_box
|
||||
|
@ -1191,6 +1191,7 @@ fn exit(
|
||||
Error::Deterministic(_, t) | Error::NonDeterministic(_, t) | Error::ScryCrashed(t) => {
|
||||
// Return $tang of traces
|
||||
let h = *(stack.local_noun_pointer(0));
|
||||
// XX: Small chance of clobbering something important after OOM?
|
||||
T(stack, &[h, t])
|
||||
}
|
||||
};
|
||||
|
@ -15,10 +15,10 @@
|
||||
#define GD_PAGE_MASK (GD_PAGE_SIZE - 1)
|
||||
#define GD_PAGE_ROUND_DOWN(foo) (foo & (~GD_PAGE_MASK))
|
||||
|
||||
static uintptr_t guard_p;
|
||||
static const uintptr_t *stack_pp;
|
||||
static const uintptr_t *alloc_pp;
|
||||
static jmp_buf env_buffer;
|
||||
static uintptr_t guard_p = 0;
|
||||
static const uintptr_t *stack_pp = NULL;
|
||||
static const uintptr_t *alloc_pp = NULL;
|
||||
static BufListNode *buffer_list = NULL;
|
||||
static struct sigaction prev_sa;
|
||||
|
||||
static int32_t
|
||||
@ -113,7 +113,7 @@ _signal_handler(int sig, siginfo_t *si, void *unused)
|
||||
if (sig != SIGSEGV) {
|
||||
fprintf(stderr, "guard: sig_handle: invalid signal\r\n");
|
||||
// XX: do we even want to jump? if this is fatal error, maybe just die now
|
||||
siglongjmp(env_buffer, guard_signal);
|
||||
siglongjmp(buffer_list->buffer, guard_signal);
|
||||
}
|
||||
|
||||
sig_addr = (uintptr_t)si->si_addr;
|
||||
@ -126,7 +126,7 @@ _signal_handler(int sig, siginfo_t *si, void *unused)
|
||||
err = _focus_guard();
|
||||
if (err) {
|
||||
fprintf(stderr, "guard: sig_handle: focus error\r\n");
|
||||
siglongjmp(env_buffer, err);
|
||||
siglongjmp(buffer_list->buffer, err);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@ -159,7 +159,7 @@ _register_handler()
|
||||
// sigemptyset(&sa.sa_mask);
|
||||
// sigaddset(&(sa.sa_mask), SIGSEGV);
|
||||
|
||||
// XX: should assert that prev_sa doesn't have a handler in it, but it's not a pointer so non-trivial
|
||||
// XX: should assert that prev_sa is uninitialized, but it's not a pointer so non-trivial
|
||||
if (sigaction(SIGSEGV, &sa, &prev_sa)) {
|
||||
fprintf(stderr, "guard: register: sigaction error\r\n");
|
||||
fprintf(stderr, "%s\r\n", strerror(errno));
|
||||
@ -177,51 +177,84 @@ guard(
|
||||
const uintptr_t *const a_pp,
|
||||
void ** ret
|
||||
) {
|
||||
int32_t err = 0;
|
||||
int32_t td_err;
|
||||
BufListNode *new_buffer;
|
||||
int32_t err = 0;
|
||||
int32_t td_err = 0;
|
||||
|
||||
assert(guard_p == 0);
|
||||
fprintf(stderr, "guard: setup: stack pointer at %p\r\n", (void *)(*stack_pp));
|
||||
fprintf(stderr, "guard: setup: alloc pointer at %p\r\n", (void *)(*alloc_pp));
|
||||
fprintf(stderr, "guard: setup: stack pointer at %p\r\n", (void *)(*s_pp));
|
||||
fprintf(stderr, "guard: setup: alloc pointer at %p\r\n", (void *)(*a_pp));
|
||||
|
||||
guard_p = 0;
|
||||
stack_pp = s_pp;
|
||||
alloc_pp = a_pp;
|
||||
if (guard_p == 0) {
|
||||
assert(buffer_list == NULL);
|
||||
|
||||
// Initialize the guard page
|
||||
if ((err = _focus_guard())) {
|
||||
fprintf(stderr, "guard: setup: _focus_guard error\r\n");
|
||||
goto done;
|
||||
stack_pp = s_pp;
|
||||
alloc_pp = a_pp;
|
||||
|
||||
// Initialize the guard page
|
||||
if ((err = _focus_guard())) {
|
||||
fprintf(stderr, "guard: setup _focus_guard error\r\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
// Register guard page signal handler
|
||||
if ((err = _register_handler())) {
|
||||
fprintf(stderr, "guard: setup _register_handler error\r\n");
|
||||
goto clean;
|
||||
}
|
||||
} else {
|
||||
assert(buffer_list != NULL);
|
||||
}
|
||||
|
||||
// Register guard page signal handler
|
||||
if ((err = _register_handler())) {
|
||||
fprintf(stderr, "guard: setup: _register_handler error\r\n");
|
||||
goto done;
|
||||
// Setup new longjmp buffer
|
||||
new_buffer = (BufListNode *)malloc(sizeof(BufListNode));
|
||||
if (new_buffer == NULL) {
|
||||
fprintf(stderr, "guard: malloc error\r\n");
|
||||
fprintf(stderr, "%s\r\n", strerror(errno));
|
||||
err = guard_malloc | errno;
|
||||
goto skip;
|
||||
}
|
||||
new_buffer->next = buffer_list;
|
||||
buffer_list = new_buffer;
|
||||
|
||||
// Run given closure
|
||||
fprintf(stderr, "guard: run\r\n");
|
||||
if (!(err = sigsetjmp(env_buffer, 1))) {
|
||||
if (!(err = sigsetjmp(buffer_list->buffer, 1))) {
|
||||
*ret = f(closure);
|
||||
}
|
||||
|
||||
done:
|
||||
// Clean up
|
||||
if (guard_p != 0) {
|
||||
// Restore previous longjmp buffer
|
||||
buffer_list = buffer_list->next;
|
||||
free((void *)new_buffer);
|
||||
|
||||
skip:
|
||||
// If no more guarded closures, then...
|
||||
if (buffer_list == NULL) {
|
||||
// Remove new signal handler
|
||||
if (sigaction(SIGSEGV, &prev_sa, NULL)) {
|
||||
fprintf(stderr, "guard: sigaction error\r\n");
|
||||
fprintf(stderr, "%s\r\n", strerror(errno));
|
||||
td_err = guard_sigaction | errno;
|
||||
|
||||
if (!err) {
|
||||
err = td_err;
|
||||
}
|
||||
}
|
||||
|
||||
clean:
|
||||
// Unmark guard page
|
||||
assert(guard_p != 0);
|
||||
td_err = _unmark_page((void *)guard_p);
|
||||
if (td_err) {
|
||||
fprintf(stderr, "guard: unmark error\r\n");
|
||||
fprintf(stderr, "%s\r\n", strerror(errno));
|
||||
if (!err) {
|
||||
err = td_err;
|
||||
}
|
||||
}
|
||||
guard_p = 0;
|
||||
}
|
||||
|
||||
if (sigaction(SIGSEGV, &prev_sa, NULL)) {
|
||||
fprintf(stderr, "guard: teardown: sigaction error\r\n");
|
||||
fprintf(stderr, "%s\r\n", strerror(errno));
|
||||
td_err = guard_sigaction | errno;
|
||||
}
|
||||
|
||||
if (!err) {
|
||||
err = td_err;
|
||||
}
|
||||
|
||||
exit:
|
||||
fprintf(stderr, "guard: return\r\n");
|
||||
return err;
|
||||
}
|
||||
|
@ -1,8 +1,17 @@
|
||||
#ifndef __GUARD_H__
|
||||
#define __GUARD_H__
|
||||
|
||||
#include <setjmp.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
typedef struct _buf_list_node {
|
||||
jmp_buf buffer;
|
||||
struct _buf_list_node *next;
|
||||
} BufListNode;
|
||||
|
||||
/**
|
||||
* Error codes and flags.
|
||||
*
|
||||
|
@ -91,7 +91,6 @@ pub fn assert_no_alloc<T, F: FnOnce() -> T> (func: F) -> T {
|
||||
return ret;
|
||||
}
|
||||
|
||||
#[cfg(not(all(feature = "disable_release", not(debug_assertions))))] // if not disabled
|
||||
/// Calls the `func` closure, but ensures that the forbid and permit counters
|
||||
/// are maintained accurately even if a longjmp originates and terminates
|
||||
/// within the closure. If you longjmp over this function, we can't fix
|
||||
@ -149,14 +148,6 @@ pub fn reset_violation_count() {
|
||||
ALLOC_VIOLATION_COUNT.with(|c| c.set(0));
|
||||
}
|
||||
|
||||
pub fn reset_counters() {
|
||||
ALLOC_FORBID_COUNT.with(|c| c.set(0));
|
||||
ALLOC_PERMIT_COUNT.with(|c| c.set(0));
|
||||
|
||||
#[cfg(any( all(feature="warn_debug", debug_assertions), all(feature="warn_release", not(debug_assertions)) ))]
|
||||
ALLOC_VIOLATION_COUNT.with(|c| c.set(0));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user