Skip to content

Commit 791e76d

Browse files
committed
work
1 parent 5b587b3 commit 791e76d

23 files changed

+918
-122
lines changed

.github/workflows/rust.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ jobs:
9191
- name: Run tests (Windows)
9292
if: matrix.os == 'windows-2019'
9393
run: |
94-
./out.minion-tests.exe
94+
./out/minion-tests.exe
9595
timeout-minutes: 3
9696
- name: Collect logs
9797
if: always()

Cargo.lock

Lines changed: 36 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,24 @@ authors = ["Mikail Bagishov <[email protected]>"]
55
edition = "2018"
66

77
[dependencies]
8-
98
rand = "0.7.3"
109
serde = { version = "1.0.106", features = ["derive"] }
11-
serde_json = "1.0.51"
1210
backtrace = "0.3.46"
1311
thiserror = "1.0.19"
1412
anyhow = "1.0.32"
13+
tracing = "0.1.19"
1514

1615
[target.'cfg(target_os="linux")'.dependencies]
1716
tiny-nix-ipc = { git = "https://github.com/myfreeweb/tiny-nix-ipc", features = ["ser_json", "zero_copy"] }
1817
procfs = "0.7.8"
1918
nix = {git = "https://github.com/nix-rust/nix"}
2019
libc = "0.2.68"
2120
errno = "0.2.5"
21+
serde_json = "1.0.51"
22+
23+
[target.'cfg(target_os="windows")'.dependencies]
24+
winapi = { version = "0.3.9", features = ["std", "processthreadsapi", "jobapi2", "errhandlingapi",
25+
"namedpipeapi", "fileapi", "synchapi", "winnt", "userenv", "handleapi", "securitybaseapi", "sddl"] }
2226

2327
[workspace]
2428
members = ["minion-ffi", ".", "minion-tests", "minion-cli"]

minion-ffi/src/lib.rs

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@
22
#![cfg_attr(minion_nightly, warn(unsafe_op_in_unsafe_fn))]
33
use minion::{self};
44
use std::{
5-
ffi::{CStr, OsStr, OsString},
5+
ffi::{CStr, OsString},
66
mem::{self},
77
os::raw::c_char,
8+
sync::Arc,
89
};
910

1011
#[repr(i32)]
@@ -42,11 +43,23 @@ pub enum WaitOutcome {
4243

4344
/// # Safety
4445
/// `buf` must be valid, readable pointer
46+
#[cfg(target_os = "linux")]
4547
unsafe fn get_string(buf: *const c_char) -> OsString {
4648
use std::os::unix::ffi::OsStrExt;
4749
let buf = unsafe { CStr::from_ptr(buf) };
4850
let buf = buf.to_bytes();
49-
let s = OsStr::from_bytes(buf);
51+
let s = std::ffi::OsStr::from_bytes(buf);
52+
s.to_os_string()
53+
}
54+
/// # Safety
55+
/// `buf` must be valid, readable pointer
56+
#[cfg(target_os = "windows")]
57+
unsafe fn get_string(buf: *const c_char) -> OsString {
58+
use std::os::windows::ffi::OsStringExt;
59+
let buf = unsafe { CStr::from_ptr(buf) };
60+
let buf = buf.to_bytes();
61+
assert!(buf.len() % 2 == 0);
62+
let s = OsString::from_wide(unsafe { buf.align_to::<u16>().1 });
5063
s.to_os_string()
5164
}
5265

@@ -107,7 +120,7 @@ pub struct SandboxOptions {
107120
}
108121

109122
#[derive(Clone)]
110-
pub struct Sandbox(Box<dyn minion::erased::Sandbox>);
123+
pub struct Sandbox(Arc<dyn minion::erased::Sandbox>);
111124

112125
/// # Safety
113126
/// `out` must be valid

minion-tests/Cargo.toml

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,14 @@ version = "0.1.0"
44
authors = ["Mikail Bagishov <[email protected]>"]
55
edition = "2018"
66

7-
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
8-
97
[dependencies]
108
once_cell = "1.4.0"
119
minion = {path = ".."}
1210
clap = "2.33.1"
13-
nix = "0.17.0"
1411
tempfile = "3.1.0"
12+
13+
[target.'cfg(target_os="linux")'.dependencies]
14+
nix = "0.17.0"
15+
16+
[target.'cfg(target_os="windows")'.dependencies]
17+
winapi = { version = "0.3.9", features = ["processthreadsapi"] }

minion-tests/src/tests/simple.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,19 @@ impl crate::TestCase for TTlFork {
5050
(TODO: verify this is not wall-clock time limit)"
5151
}
5252
fn test(&self) -> ! {
53+
#[cfg(target_os = "linux")]
5354
nix::unistd::fork().unwrap();
55+
#[cfg(target_os = "winfows")]
56+
unsafe {
57+
winapi::um::processthreadsapi::CreateThread(
58+
std::ptr::null_mut(),
59+
0,
60+
exceed_time_limit,
61+
self,
62+
0,
63+
std::ptr::null_mut(),
64+
);
65+
}
5466
exceed_time_limit()
5567
}
5668
fn check(&self, cp: &mut dyn ChildProcess, _: &dyn Sandbox) {
@@ -71,7 +83,12 @@ impl crate::TestCase for TIdle {
7183
checks that it still will be killed"
7284
}
7385
fn test(&self) -> ! {
86+
#[cfg(target_os = "linux")]
7487
nix::unistd::sleep(1_000_000_000);
88+
#[cfg(target_os = "windows")]
89+
unsafe {
90+
winapi::um::synchapi::Sleep(1_000_000_000);
91+
};
7592
std::process::exit(0)
7693
}
7794
fn check(&self, cp: &mut dyn ChildProcess, _: &dyn Sandbox) {
@@ -147,6 +164,7 @@ impl crate::TestCase for TSecurity {
147164
fn description(&self) -> &'static str {
148165
"verifies that isolated program can not make certain bad things"
149166
}
167+
#[cfg(target_os = "linux")]
150168
fn test(&self) -> ! {
151169
// Check we can not read pid1's environment.
152170
let err = std::fs::read("/proc/1/environ").unwrap_err();
@@ -164,6 +182,11 @@ impl crate::TestCase for TSecurity {
164182
assert!(matches!(err, nix::Error::Sys(nix::errno::Errno::EPERM)));
165183
std::process::exit(24)
166184
}
185+
#[cfg(target_os = "windows")]
186+
fn test(&self) -> ! {
187+
// TODO
188+
std::process::exit(24)
189+
}
167190
fn check(&self, cp: &mut dyn ChildProcess, _sb: &dyn Sandbox) {
168191
super::assert_exit_code(cp, 24);
169192
super::assert_empty(&mut cp.stdout().unwrap());

rustfmt.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
merge_imports = true

src/command.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@ use crate::{erased, InputSpecification, OutputSpecification, StdioSpecification}
22
use std::{
33
ffi::{OsStr, OsString},
44
path::{Path, PathBuf},
5+
sync::Arc,
56
};
67

78
/// Child process builder
89
#[derive(Default, Debug)]
910
pub struct Command {
10-
sandbox: Option<Box<dyn erased::Sandbox>>,
11+
sandbox: Option<Arc<dyn erased::Sandbox>>,
1112
exe: Option<PathBuf>,
1213
argv: Vec<OsString>,
1314
env: Vec<OsString>,
@@ -56,7 +57,7 @@ impl Command {
5657
backend.spawn(options)
5758
}
5859

59-
pub fn sandbox(&mut self, sandbox: Box<dyn erased::Sandbox>) -> &mut Self {
60+
pub fn sandbox(&mut self, sandbox: Arc<dyn erased::Sandbox>) -> &mut Self {
6061
self.sandbox.replace(sandbox);
6162
self
6263
}

src/erased.rs

Lines changed: 22 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -3,28 +3,20 @@
33
//!
44
//! Please note that this API is not type-safe. For example, if you pass
55
//! `Sandbox` instance to another backend, it will panic.
6+
use std::{any::Any, sync::Arc};
67

78
/// Type-erased `Sandbox`
89
pub trait Sandbox: std::fmt::Debug {
9-
fn id(&self) -> String;
10+
fn id(&self) -> &str;
1011
fn check_cpu_tle(&self) -> anyhow::Result<bool>;
1112
fn check_real_tle(&self) -> anyhow::Result<bool>;
1213
fn kill(&self) -> anyhow::Result<()>;
1314
fn resource_usage(&self) -> anyhow::Result<crate::ResourceUsageData>;
14-
#[doc(hidden)]
15-
fn clone_to_box(&self) -> Box<dyn Sandbox>;
16-
#[doc(hidden)]
17-
fn clone_into_box_any(&self) -> Box<dyn std::any::Any>;
18-
}
19-
20-
impl Clone for Box<dyn Sandbox> {
21-
fn clone(&self) -> Self {
22-
self.clone_to_box()
23-
}
15+
fn into_arc_any(self: Arc<Self>) -> Arc<dyn Any + Send + Sync + 'static>;
2416
}
2517

2618
impl<S: crate::Sandbox> Sandbox for S {
27-
fn id(&self) -> String {
19+
fn id(&self) -> &str {
2820
self.id()
2921
}
3022
fn check_cpu_tle(&self) -> anyhow::Result<bool> {
@@ -39,12 +31,8 @@ impl<S: crate::Sandbox> Sandbox for S {
3931
fn resource_usage(&self) -> anyhow::Result<crate::ResourceUsageData> {
4032
self.resource_usage().map_err(Into::into)
4133
}
42-
fn clone_to_box(&self) -> Box<dyn Sandbox> {
43-
Box::new(self.clone())
44-
}
45-
46-
fn clone_into_box_any(&self) -> Box<dyn std::any::Any> {
47-
Box::new(self.clone())
34+
fn into_arc_any(self: Arc<Self>) -> Arc<dyn Any + Send + Sync + 'static> {
35+
self
4836
}
4937
}
5038

@@ -58,8 +46,7 @@ pub trait ChildProcess {
5846
&self,
5947
timeout: Option<std::time::Duration>,
6048
) -> anyhow::Result<crate::WaitOutcome>;
61-
fn poll(&self) -> anyhow::Result<()>;
62-
fn is_finished(&self) -> anyhow::Result<bool>;
49+
fn is_finished(&self) -> bool;
6350
}
6451

6552
impl<C: crate::ChildProcess> ChildProcess for C {
@@ -90,50 +77,48 @@ impl<C: crate::ChildProcess> ChildProcess for C {
9077
) -> anyhow::Result<crate::WaitOutcome> {
9178
self.wait_for_exit(timeout).map_err(Into::into)
9279
}
93-
fn poll(&self) -> anyhow::Result<()> {
94-
self.poll().map_err(Into::into)
95-
}
96-
fn is_finished(&self) -> anyhow::Result<bool> {
97-
self.is_finished().map_err(Into::into)
80+
fn is_finished(&self) -> bool {
81+
self.is_finished()
9882
}
9983
}
10084

10185
/// Type-erased `Backend`
10286
pub trait Backend {
103-
fn new_sandbox(&self, options: crate::SandboxOptions) -> anyhow::Result<Box<dyn Sandbox>>;
87+
fn new_sandbox(&self, options: crate::SandboxOptions) -> anyhow::Result<Arc<dyn Sandbox>>;
10488
fn spawn(&self, options: ChildProcessOptions) -> anyhow::Result<Box<dyn ChildProcess>>;
10589
}
10690

10791
impl<B: crate::Backend> Backend for B {
108-
fn new_sandbox(&self, options: crate::SandboxOptions) -> anyhow::Result<Box<dyn Sandbox>> {
92+
fn new_sandbox(&self, options: crate::SandboxOptions) -> anyhow::Result<Arc<dyn Sandbox>> {
10993
let sb = <Self as crate::Backend>::new_sandbox(&self, options)?;
110-
Ok(Box::new(sb))
94+
Ok(Arc::new(sb))
11195
}
11296

11397
fn spawn(&self, options: ChildProcessOptions) -> anyhow::Result<Box<dyn ChildProcess>> {
114-
let down_sandbox = options
115-
.sandbox
116-
.clone_into_box_any()
117-
.downcast()
118-
.expect("sandbox type mismatch");
98+
let any_sandbox = options.sandbox.clone().into_arc_any();
99+
let down_sandbox = any_sandbox.downcast().expect("sandbox type mismatch");
119100
let down_options = crate::ChildProcessOptions {
120101
arguments: options.arguments,
121102
environment: options.environment,
122103
path: options.path,
123104
pwd: options.pwd,
124105
stdio: options.stdio,
125-
sandbox: *down_sandbox,
106+
sandbox: down_sandbox,
126107
};
127108
let cp = <Self as crate::Backend>::spawn(&self, down_options)?;
128109
Ok(Box::new(cp))
129110
}
130111
}
131112

132-
pub type ChildProcessOptions = crate::ChildProcessOptions<Box<dyn Sandbox>>;
113+
pub type ChildProcessOptions = crate::ChildProcessOptions<dyn Sandbox>;
133114

134115
/// Returns backend instance
135116
pub fn setup() -> anyhow::Result<Box<dyn Backend>> {
136-
Ok(Box::new(crate::linux::LinuxBackend::new(
117+
#[cfg(target_os = "linux")]
118+
return Ok(Box::new(crate::linux::LinuxBackend::new(
137119
crate::linux::Settings::new(),
138-
)?))
120+
)?));
121+
122+
#[cfg(target_os = "windows")]
123+
return Ok(Box::new(crate::windows::WindowsBackend::new()));
139124
}

0 commit comments

Comments
 (0)