commit
02bcfeb3fe
@ -0,0 +1,2 @@
|
||||
/target
|
||||
Cargo.lock
|
@ -0,0 +1,14 @@
|
||||
[package]
|
||||
name = "stackalloc"
|
||||
version = "0.1.0"
|
||||
authors = ["Avril <flanchan@cumallover.me>"]
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
|
||||
|
||||
[build-dependencies]
|
||||
cc = "1.0"
|
||||
rustc_version = "0.2"
|
@ -0,0 +1,8 @@
|
||||
#include <stddef.h>
|
||||
|
||||
void _alloca_trampoline(size_t num, void (*callback)(void* restrict ptr, void* data), void* data)
|
||||
{
|
||||
unsigned char ptr[num];
|
||||
callback(ptr, data);
|
||||
}
|
||||
|
@ -0,0 +1,43 @@
|
||||
|
||||
extern crate rustc_version;
|
||||
use rustc_version::{version, version_meta, Channel};
|
||||
|
||||
fn build_tramp()
|
||||
{
|
||||
let mut builder = cc::Build::new();
|
||||
// --std=c99 -W -Wall -Werror -pedantic -O3 -flto
|
||||
builder.flag("--std=c99")
|
||||
.flag("--std=c99")
|
||||
.flag("-W")
|
||||
.flag("-Wall")
|
||||
.flag("-Werror")
|
||||
.flag("-pedantic")
|
||||
.opt_level(3)
|
||||
.flag_if_supported("-flto")
|
||||
|
||||
.file("alloca_trampoline_.c")
|
||||
.compile("calloca_trampoline");
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// Assert we haven't travelled back in time
|
||||
assert!(version().unwrap().major >= 1);
|
||||
|
||||
// Set cfg flags depending on release channel
|
||||
match version_meta().unwrap().channel {
|
||||
Channel::Stable => {
|
||||
println!("cargo:rustc-cfg=stable");
|
||||
}
|
||||
Channel::Beta => {
|
||||
println!("cargo:rustc-cfg=beta");
|
||||
}
|
||||
Channel::Nightly => {
|
||||
println!("cargo:rustc-cfg=nightly");
|
||||
}
|
||||
Channel::Dev => {
|
||||
println!("cargo:rustc-cfg=dev");
|
||||
}
|
||||
}
|
||||
|
||||
build_tramp();
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
use std::ffi::c_void;
|
||||
|
||||
pub type CallbackRaw = extern "C" fn (ptr: *mut c_void, data: *mut c_void)->();
|
||||
|
||||
extern "C" {
|
||||
fn _alloca_trampoline(size: usize, cb: Option<CallbackRaw>, data: *mut c_void);
|
||||
}
|
||||
|
||||
/// Call the `_alloca_trampoline` C function.
|
||||
///
|
||||
/// # Safety requirements & guarantees
|
||||
/// * `size` should be small enough to not overflow the stack. A size of 0 is allowed.
|
||||
/// * `cb` **must** catch any unwinds.
|
||||
/// * `data` can be `null`, it is passed as the 2nd argument to `cb` as-is.
|
||||
/// * The first argument to `cb` is guaranteed to be a non-aliased, properly aligned, and non-null pointer with `size` read+writable memory. If `size` is 0, it may dangle.
|
||||
/// * `cb` is guaranteed to be called unless allocating `size` bytes on the stack causes a stack overflow, in which case the program will terminate.
|
||||
/// * The data pointed to by `ptr` is guaranteed to be popped from the stack once `cb` returns (even in the case of a `longjmp`, but `panic!()` within the callback is still undefined behaviour).
|
||||
#[inline(always)] pub unsafe fn alloca_trampoline(size: usize, cb: CallbackRaw, data: *mut c_void)
|
||||
{
|
||||
_alloca_trampoline(size, Some(cb), data);
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
|
||||
mod ffi;
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[test]
|
||||
fn raw_trampoline()
|
||||
{
|
||||
use std::ffi::c_void;
|
||||
|
||||
let mut size: usize = 100;
|
||||
extern "C" fn callback(ptr: *mut c_void, data: *mut c_void)
|
||||
{
|
||||
let size = unsafe {&mut *(data as *mut usize)};
|
||||
println!("From callback! Size is {}", *size);
|
||||
|
||||
*size = 0;
|
||||
}
|
||||
|
||||
unsafe {
|
||||
super::ffi::alloca_trampoline(size, callback, &mut size as *mut usize as *mut _);
|
||||
}
|
||||
|
||||
assert_eq!(size, 0);
|
||||
}
|
||||
}
|
Loading…
Reference in new issue