1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
use errors::Error;
use libloading;
use regex::Regex;
use std::marker::PhantomData;
use std::rc::Rc;
use std::{self, io};
pub(crate) const EVCXR_IS_RUNTIME_VAR: &str = "EVCXR_IS_RUNTIME";
pub(crate) const EVCXR_EXECUTION_COMPLETE: &str = "EVCXR_EXECUTION_COMPLETE";
pub fn runtime_hook() {
if std::env::var(EVCXR_IS_RUNTIME_VAR).is_ok() {
Runtime::new().run_loop();
}
}
struct Runtime {
shared_objects: Vec<libloading::Library>,
variable_store_ptr: *mut std::os::raw::c_void,
_phantom_rc: PhantomData<Rc<()>>,
}
impl Runtime {
fn new() -> Runtime {
Runtime {
shared_objects: Vec::new(),
variable_store_ptr: std::ptr::null_mut(),
_phantom_rc: PhantomData,
}
}
fn run_loop(&mut self) -> ! {
use std::io::BufRead;
self.install_crash_handlers();
let stdin = std::io::stdin();
for line in stdin.lock().lines() {
if let Err(error) = self.handle_line(&line) {
eprintln!(
"While processing instruction `{:?}`, got error: {:?}",
line, error
);
std::process::exit(99);
}
}
std::process::exit(0);
}
fn handle_line(&mut self, line: &io::Result<String>) -> Result<(), Error> {
let line = line.as_ref()?;
lazy_static! {
static ref LOAD_AND_RUN: Regex = Regex::new("LOAD_AND_RUN ([^ ]+) ([^ ]+)").unwrap();
}
if let Some(captures) = LOAD_AND_RUN.captures(&line) {
self.load_and_run(&captures[1], &captures[2])
} else {
bail!("Unrecognised line: {}", line);
}
}
fn load_and_run(&mut self, so_path: &str, fn_name: &str) -> Result<(), Error> {
use std::os::raw::c_void;
let shared_object = libloading::Library::new(so_path)?;
unsafe {
let user_fn = shared_object
.get::<extern "C" fn(*mut c_void) -> *mut c_void>(fn_name.as_bytes())?;
self.variable_store_ptr = user_fn(self.variable_store_ptr);
}
println!("{}", EVCXR_EXECUTION_COMPLETE);
self.shared_objects.push(shared_object);
Ok(())
}
#[cfg(unix)]
pub fn install_crash_handlers(&self) {
use backtrace::Backtrace;
use sig::ffi::Sig;
extern "C" fn segfault_handler(signal: i32) {
eprintln!(
"{}",
match signal {
Sig::SEGV => "Segmentation fault.",
Sig::ILL => "Illegal instruction.",
Sig::BUS => "Bus error.",
_ => "Unexpected signal.",
}
);
eprintln!("{:?}", Backtrace::new());
std::process::abort();
}
signal!(Sig::SEGV, segfault_handler);
signal!(Sig::ILL, segfault_handler);
signal!(Sig::BUS, segfault_handler);
}
#[cfg(not(unix))]
pub fn install_crash_handlers(&self) {}
}
impl Drop for Runtime {
fn drop(&mut self) {
for shared_object in self.shared_objects.drain(..) {
std::mem::forget(shared_object);
}
}
}