mirror of
https://github.com/urbit/ares.git
synced 2024-12-23 21:31:57 +03:00
wip: earl-eye in the mornin
This commit is contained in:
parent
5e44f2f94f
commit
7ff1657687
@ -375,27 +375,28 @@ extern "C" fn rust_callback(arg: *mut c_void) -> *mut c_void {
|
|||||||
|
|
||||||
pub fn call_with_guard<F: FnMut() -> Result>(
|
pub fn call_with_guard<F: FnMut() -> Result>(
|
||||||
f: F,
|
f: F,
|
||||||
stack: *const c_void,
|
stack: *const *mut c_void,
|
||||||
alloc: *const c_void,
|
alloc: *const *mut c_void,
|
||||||
ret: *mut *mut c_void,
|
|
||||||
) -> Result {
|
) -> Result {
|
||||||
let boxed_f = Box::new(f);
|
let boxed_f = Box::new(f);
|
||||||
|
let res: Result = Err(Error::Deterministic(D(0)));
|
||||||
|
let mut result = Box::new(res);
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let result: *mut c_void = std::ptr::null_mut();
|
|
||||||
let raw_f = Box::into_raw(Box::new(boxed_f));
|
let raw_f = Box::into_raw(Box::new(boxed_f));
|
||||||
|
let result_ptr = &mut result as *mut _ as *mut c_void;
|
||||||
|
|
||||||
guard(
|
guard(
|
||||||
Some(rust_callback),
|
Some(rust_callback),
|
||||||
raw_f as *mut c_void,
|
raw_f as *mut c_void,
|
||||||
stack,
|
stack,
|
||||||
alloc,
|
alloc,
|
||||||
ret,
|
result_ptr,
|
||||||
);
|
);
|
||||||
|
|
||||||
let _ = Box::from_raw(raw_f);
|
let _ = Box::from_raw(raw_f);
|
||||||
|
|
||||||
if !result.is_null() {
|
if !*result.is_null() {
|
||||||
let err = *(result as *const guard_err);
|
let err = *(result as *const guard_err);
|
||||||
match err {
|
match err {
|
||||||
0 => { // sound
|
0 => { // sound
|
||||||
@ -419,6 +420,10 @@ pub fn interpret(context: &mut Context, mut subject: Noun, formula: Noun) -> Res
|
|||||||
let snapshot = context.save();
|
let snapshot = context.save();
|
||||||
let virtual_frame: *const u64 = context.stack.get_frame_pointer();
|
let virtual_frame: *const u64 = context.stack.get_frame_pointer();
|
||||||
let mut res: Noun = D(0);
|
let mut res: Noun = D(0);
|
||||||
|
let stack_ptr = context.stack.get_stack_pointer() as *mut c_void;
|
||||||
|
let stack_ptr_ptr = &stack_ptr as *const *mut c_void;
|
||||||
|
let alloc_ptr = context.stack.get_alloc_pointer() as *mut c_void;
|
||||||
|
let alloc_ptr_ptr = &alloc_ptr as *const *mut c_void;
|
||||||
|
|
||||||
// Setup stack for Nock computation
|
// Setup stack for Nock computation
|
||||||
unsafe {
|
unsafe {
|
||||||
@ -445,8 +450,6 @@ pub fn interpret(context: &mut Context, mut subject: Noun, formula: Noun) -> Res
|
|||||||
// (See https://docs.rs/assert_no_alloc/latest/assert_no_alloc/#advanced-use)
|
// (See https://docs.rs/assert_no_alloc/latest/assert_no_alloc/#advanced-use)
|
||||||
let nock = assert_no_alloc(|| {
|
let nock = assert_no_alloc(|| {
|
||||||
ensure_alloc_counters(|| {
|
ensure_alloc_counters(|| {
|
||||||
let stack_p = context.stack.get_stack_pointer();
|
|
||||||
let alloc_p = context.stack.get_alloc_pointer();
|
|
||||||
call_with_guard(|| unsafe {
|
call_with_guard(|| unsafe {
|
||||||
push_formula(&mut context.stack, formula, true)?;
|
push_formula(&mut context.stack, formula, true)?;
|
||||||
|
|
||||||
@ -987,8 +990,8 @@ pub fn interpret(context: &mut Context, mut subject: Noun, formula: Noun) -> Res
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
stack_p as *const c_void,
|
stack_ptr_ptr,
|
||||||
alloc_p as *const c_void,
|
alloc_ptr_ptr,
|
||||||
std::ptr::null_mut() as *mut *mut c_void,
|
std::ptr::null_mut() as *mut *mut c_void,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
|
#include <pthread.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "guard.h"
|
#include "guard.h"
|
||||||
|
|
||||||
@ -10,24 +12,27 @@
|
|||||||
#define GD_PAGEBITS 14ULL
|
#define GD_PAGEBITS 14ULL
|
||||||
#define GD_PAGESIZE (1ULL << GD_PAGEBITS) /* 16K */
|
#define GD_PAGESIZE (1ULL << GD_PAGEBITS) /* 16K */
|
||||||
|
|
||||||
static void *guard_p = NULL;
|
static uint64_t *guard_p = 0;
|
||||||
static void *stack_p = NULL;
|
static uint64_t **stack = 0;
|
||||||
static void *alloc_p = NULL;
|
static uint64_t **alloc = 0;
|
||||||
|
|
||||||
volatile sig_atomic_t err = guard_sound;
|
volatile sig_atomic_t err = guard_sound;
|
||||||
|
|
||||||
|
|
||||||
// Center the guard page.
|
// Center the guard page.
|
||||||
guard_err _focus_guard() {
|
guard_err _focus_guard() {
|
||||||
|
uint64_t *stack_p = *stack;
|
||||||
|
uint64_t *alloc_p = *alloc;
|
||||||
|
|
||||||
// Check for strange situations.
|
// Check for strange situations.
|
||||||
if (stack_p == NULL || alloc_p == NULL) {
|
if (stack_p == 0 || alloc_p == 0) {
|
||||||
fprintf(stderr, "guard: stack or alloc pointer is null\r\n");
|
fprintf(stderr, "guard: stack or alloc pointer is null\r\n");
|
||||||
return guard_weird;
|
return guard_weird;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unmark the old guard page.
|
// Unmark the old guard page.
|
||||||
void *old_guard_p = guard_p;
|
void *old_guard_p = guard_p;
|
||||||
if (old_guard_p != NULL && mprotect(old_guard_p, GD_PAGESIZE, PROT_READ | PROT_WRITE) == -1) {
|
if (old_guard_p != 0 && mprotect(old_guard_p, GD_PAGESIZE, PROT_READ | PROT_WRITE) == -1) {
|
||||||
return guard_armor;
|
return guard_armor;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,8 +61,10 @@ guard_err _focus_guard() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
guard_err _slash_guard(void *si_addr) {
|
guard_err _slash_guard(void *si_addr) {
|
||||||
if (si_addr >= guard_p && si_addr < guard_p + GD_PAGESIZE) {
|
// fprintf(stderr, "guard: slash at %p\r\n", si_addr);
|
||||||
fprintf(stderr, "guard: slash\r\n");
|
// fprintf(stderr, "guard: guard at %p\r\n", (void *) guard_p);
|
||||||
|
|
||||||
|
if (si_addr >= (void *)guard_p && si_addr < (void *)guard_p + GD_PAGESIZE) {
|
||||||
return _focus_guard();
|
return _focus_guard();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,8 +74,6 @@ guard_err _slash_guard(void *si_addr) {
|
|||||||
void _signal_handler(int sig, siginfo_t *si, void *unused) {
|
void _signal_handler(int sig, siginfo_t *si, void *unused) {
|
||||||
switch (sig) {
|
switch (sig) {
|
||||||
case SIGSEGV:
|
case SIGSEGV:
|
||||||
fprintf(stderr, "guard: segfault at %p\r\n", si->si_addr);
|
|
||||||
fprintf(stderr, "guard: guard at %p\r\n", guard_p);
|
|
||||||
err = _slash_guard(si->si_addr);
|
err = _slash_guard(si->si_addr);
|
||||||
break;
|
break;
|
||||||
case SIGINT:
|
case SIGINT:
|
||||||
@ -86,23 +91,24 @@ guard_err _register_handler() {
|
|||||||
sa.sa_sigaction = _signal_handler;
|
sa.sa_sigaction = _signal_handler;
|
||||||
sa.sa_mask = 0;
|
sa.sa_mask = 0;
|
||||||
|
|
||||||
if (sigaction(SIGSEGV, &sa, NULL) || sigaction(SIGINT, &sa, NULL)) {
|
if (sigaction(SIGSEGV, &sa, 0) || sigaction(SIGINT, &sa, 0)) {
|
||||||
return guard_weird;
|
return guard_weird;
|
||||||
}
|
}
|
||||||
|
|
||||||
return guard_sound;
|
return guard_sound;
|
||||||
}
|
}
|
||||||
|
|
||||||
void guard(void *(*f)(void *), void *arg, void *const stack, void *const alloc, void **ret) {
|
void guard(void *(*f)(void *), void *arg, void *const *stack_pp, void *const *alloc_pp, void *ret) {
|
||||||
stack_p = stack;
|
stack = (uint64_t**) stack_pp;
|
||||||
alloc_p = alloc;
|
alloc = (uint64_t**) alloc_pp;
|
||||||
|
|
||||||
if (_register_handler() != guard_sound) {
|
fprintf(stderr, "guard: stack at %p\r\n", (void *) stack);
|
||||||
err = guard_weird;
|
fprintf(stderr, "guard: alloc at %p\r\n", (void *) alloc);
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (guard_p == NULL) {
|
fprintf(stderr, "guard: stack pointer at %p\r\n", (void *) *stack);
|
||||||
|
fprintf(stderr, "guard: alloc pointer at %p\r\n", (void *) *alloc);
|
||||||
|
|
||||||
|
if (guard_p == 0) {
|
||||||
fprintf(stderr, "guard: installing guard page\r\n");
|
fprintf(stderr, "guard: installing guard page\r\n");
|
||||||
guard_err install_err = _focus_guard();
|
guard_err install_err = _focus_guard();
|
||||||
if (install_err != guard_sound) {
|
if (install_err != guard_sound) {
|
||||||
@ -111,18 +117,48 @@ void guard(void *(*f)(void *), void *arg, void *const stack, void *const alloc,
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fprintf(stderr, "guard: guard page installed at %p\r\n", guard_p);
|
fprintf(stderr, "guard: guard page installed at %p\r\n", (void *) guard_p);
|
||||||
|
|
||||||
*ret = f(arg);
|
if (_register_handler() != guard_sound) {
|
||||||
|
err = guard_weird;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_t thread;
|
||||||
|
int thread_err;
|
||||||
|
thread_err = pthread_create(&thread, NULL, f, arg);
|
||||||
|
if (thread_err != 0) {
|
||||||
|
err = guard_weird;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (err == guard_sound) {
|
||||||
|
if (pthread_kill(thread, 0) != 0) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
sleep(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *thread_result;
|
||||||
|
pthread_join(thread, &thread_result);
|
||||||
|
*(void **)ret = thread_result;
|
||||||
|
|
||||||
if (err != guard_sound) {
|
if (err != guard_sound) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mprotect(guard_p, GD_PAGESIZE, PROT_READ | PROT_WRITE) == -1) {
|
||||||
|
err = guard_armor;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
|
if (mprotect(guard_p, GD_PAGESIZE, PROT_READ | PROT_WRITE) == -1) {
|
||||||
|
fprintf(stderr, "guard: failed to remove guard page\r\n");
|
||||||
|
}
|
||||||
fprintf(stderr, "guard: error %d\r\n", err);
|
fprintf(stderr, "guard: error %d\r\n", err);
|
||||||
*ret = (void *) &err;
|
*(void **)ret = (void *) &err;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#ifndef __GUARD_H__
|
#ifndef __GUARD_H__
|
||||||
#define __GUARD_H__
|
#define __GUARD_H__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute the given closure `f` within the memory arena between the
|
* Execute the given closure `f` within the memory arena between the
|
||||||
@ -30,7 +31,7 @@
|
|||||||
* error will be written to the `ret` pointer. The caller is then responsible
|
* error will be written to the `ret` pointer. The caller is then responsible
|
||||||
* for handling this error and aborting with a `bail:meme`.
|
* for handling this error and aborting with a `bail:meme`.
|
||||||
*/
|
*/
|
||||||
void guard(void *(*f)(void *), void *arg, void *const stack, void *const alloc, void **ret);
|
void guard(void *(*f)(void *), void *arg, void *const *stack_pp, void *const *alloc_pp, void *ret);
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
guard_sound = 0, // job's done
|
guard_sound = 0, // job's done
|
||||||
|
@ -2,22 +2,4 @@
|
|||||||
#![allow(non_camel_case_types)]
|
#![allow(non_camel_case_types)]
|
||||||
#![allow(non_snake_case)]
|
#![allow(non_snake_case)]
|
||||||
|
|
||||||
|
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
|
||||||
extern "C" {
|
|
||||||
#[doc = " Execute the given closure `f` within the memory arena between the\n `stack` and `alloc` pointers, with guard page protection. Write either\n `f`'s succesful result or a `guard_err` to the given `ret` pointer.\n\n Memory\n ------\n The free memory arena between the `stack` and `alloc` pointers is part of a\n NockStack frame, which may either face east or west. If the frame faces\n east, the `stack` pointer will be greater than the `alloc` pointer. If it\n faces west, the `stack` pointer will be less than the `alloc` pointer.\n\n All the pages in the memory arena are marked clean (`PROT_READ | PROT_WRITE`)\n by default, with the exception of a single guard page in the middle of the\n arena, which is marked with `PROT_NONE`.\n\n Guard\n -----\n This function protects the free memory arena between the `stack` and `alloc`\n pointers with a guard page. A guard page is simply a single page of memory\n which is marked with `PROT_NONE`. Since all other pages are marked clean by\n default, a SIGSEGV will only be raised if the `f` function attempts to write\n to the guard page. When it does, the signal handler will attempt to re-center\n the guard page in the remaining free space left in the arena. If there is no\n more free space, then memory exhaustion has occurred and the `guard_spent`\n error will be written to the `ret` pointer. The caller is then responsible\n for handling this error and aborting with a `bail:meme`."]
|
|
||||||
pub fn guard(
|
|
||||||
f: ::std::option::Option<
|
|
||||||
unsafe extern "C" fn(arg1: *mut ::std::os::raw::c_void) -> *mut ::std::os::raw::c_void,
|
|
||||||
>,
|
|
||||||
arg: *mut ::std::os::raw::c_void,
|
|
||||||
stack: *const ::std::os::raw::c_void,
|
|
||||||
alloc: *const ::std::os::raw::c_void,
|
|
||||||
ret: *mut *mut ::std::os::raw::c_void,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
pub const guard_err_guard_sound: guard_err = 0;
|
|
||||||
pub const guard_err_guard_armor: guard_err = 1;
|
|
||||||
pub const guard_err_guard_weird: guard_err = 2;
|
|
||||||
pub const guard_err_guard_spent: guard_err = 3;
|
|
||||||
pub const guard_err_guard_erupt: guard_err = 4;
|
|
||||||
pub type guard_err = ::std::os::raw::c_uint;
|
|
||||||
|
Loading…
Reference in New Issue
Block a user