pass struct to code

This commit is contained in:
nora 2023-04-04 11:39:00 +02:00
parent 159e8271fe
commit bf8f13c62a
2 changed files with 70 additions and 20 deletions

View file

@ -135,7 +135,7 @@ impl Build {
});
}
let (is_ice, output) = match &inner.mode {
let (is_ice, cmd_status, output) = match &inner.mode {
BuildMode::Cargo { subcommand } => {
let mut cmd = self.cmd("cargo");
@ -158,6 +158,7 @@ impl Build {
(
// Cargo always exits with 101 when rustc has an error.
output.contains("internal compiler error") || output.contains("' panicked at"),
outputs.status,
output,
)
}
@ -183,6 +184,7 @@ impl Build {
(
outputs.status.code() == Some(101)
|| output.contains("internal compiler error"),
outputs.status,
output,
)
}
@ -201,14 +203,14 @@ impl Build {
let output = String::from_utf8(outputs.stderr)?;
(outputs.status.success(), output)
(outputs.status.success(), outputs.status, output)
}
};
let reproduces_issue = match inner.verify {
Verify::None => unreachable!("handled ealier"),
Verify::Ice => is_ice,
Verify::Custom(func) => func.call(&output),
Verify::Custom(func) => func.call(&output, cmd_status.code()),
};
Ok(BuildResult {

View file

@ -5,7 +5,15 @@ use std::{fmt::Debug, str::FromStr};
use anyhow::{Context, Result};
type CheckerCFn = unsafe extern "C" fn(*const u8, usize) -> bool;
#[repr(C)]
pub struct RawOutput {
out_ptr: *const u8,
out_len: usize,
out_has_status: bool,
out_status: i32,
}
type CheckerCFn = unsafe extern "C" fn(*const RawOutput) -> bool;
#[derive(Clone, Copy)]
pub struct RustFunction {
@ -24,23 +32,50 @@ fn wrap_func_body(func: &str) -> Result<String> {
let closure = syn::parse_str::<syn::ExprClosure>(func).context("invalid rust syntax")?;
let syn_file = syn::parse_quote! {
#[repr(C)]
pub struct __RawOutput {
out_ptr: *const u8,
out_len: usize,
out_has_status: bool,
out_status: i32,
}
impl __RawOutput {
unsafe fn as_output<'a>(&self) -> __Output<'a> {
let slice = unsafe { std::slice::from_raw_parts(self.out_ptr, self.out_len) };
let out = std::str::from_utf8(slice).unwrap();
let status = self.out_has_status.then_some(self.out_status);
__Output {
out,
status,
}
}
}
#[derive(Debug, Clone, Copy)]
struct __Output<'a> {
out: &'a str,
status: Option<i32>,
}
#[no_mangle]
pub extern "C" fn cargo_minimize_ffi_function(ptr: *const u8, len: usize) -> bool {
match std::panic::catch_unwind(|| __cargo_minimize_inner(ptr, len)) {
pub unsafe extern "C" fn cargo_minimize_ffi_function(raw: *const __RawOutput) -> bool {
match std::panic::catch_unwind(|| __cargo_minimize_inner(raw)) {
Ok(bool) => bool,
Err(_) => std::process::abort(),
}
}
fn __cargo_minimize_inner(__ptr: *const u8, __len: usize) -> bool {
let __slice = unsafe { std::slice::from_raw_parts(__ptr, __len) };
let __str = std::str::from_utf8(__slice).unwrap();
#[allow(unused_parens)]
unsafe fn __cargo_minimize_inner(__raw: *const __RawOutput) -> bool {
let __output = __raw.read();
let __output = __output.as_output();
fn ascribe_type<F: FnOnce(&str) -> bool>(f: F, output: &str) -> bool {
fn ascribe_type<'a, F: FnOnce(__Output<'a>) -> bool>(f: F, output: __Output<'a>) -> bool {
f(output)
}
ascribe_type((#closure), __str)
ascribe_type((#closure), __output)
}
};
@ -104,11 +139,22 @@ impl RustFunction {
Ok(Self { func })
}
pub fn call(&self, output: &str) -> bool {
let ptr = output.as_ptr();
let len = output.len();
pub fn call(&self, output: &str, code: Option<i32>) -> bool {
let out_ptr = output.as_ptr();
let out_len = output.len();
let (out_has_status, out_status) = match code {
Some(status) => (true, status),
None => (false, 0),
};
unsafe { (self.func)(ptr, len) }
let output = RawOutput {
out_ptr,
out_len,
out_has_status,
out_status,
};
unsafe { (self.func)(&output) }
}
}
@ -125,14 +171,16 @@ mod tests {
#[test]
#[cfg_attr(not(target_os = "linux"), ignore)]
fn basic_contains_work() {
let code = r#"|output| output.contains("test")"#;
let code = r#"|output| output.out.contains("test")"#;
let function = RustFunction::compile(code).unwrap();
let input = "this is a test";
let not_input = "this is not a tst";
let output = "this is a test";
let not_output = "this is not a tst";
assert!(function.call(input));
assert!(!function.call(not_input));
let code = None;
assert!(function.call(output, code));
assert!(!function.call(not_output, code));
}
}