From bf8f13c62ad6260bdadfa8046605c62a7e7c19d9 Mon Sep 17 00:00:00 2001 From: nils <48135649+Nilstrieb@users.noreply.github.com> Date: Tue, 4 Apr 2023 11:39:00 +0200 Subject: [PATCH] pass struct to code --- src/build.rs | 8 +++-- src/dylib_flag.rs | 82 +++++++++++++++++++++++++++++++++++++---------- 2 files changed, 70 insertions(+), 20 deletions(-) diff --git a/src/build.rs b/src/build.rs index f57a603..97f01f3 100644 --- a/src/build.rs +++ b/src/build.rs @@ -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 { diff --git a/src/dylib_flag.rs b/src/dylib_flag.rs index 801b56e..97870d5 100644 --- a/src/dylib_flag.rs +++ b/src/dylib_flag.rs @@ -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 { let closure = syn::parse_str::(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, + } + #[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 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) -> 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)); } }