Skip to content

Commit

Permalink
Add more tests, rework UnixStr-apis, add locked print (#22)
Browse files Browse the repository at this point in the history
* Add more tests, rework `UnixStr`-apis, add locked print

* Fixup epoll expect since using stdout in ci

* Run CI on any push
  • Loading branch information
MarcusGrass authored Oct 1, 2023
1 parent 1ff7df1 commit b8c9e90
Show file tree
Hide file tree
Showing 61 changed files with 1,205 additions and 1,182 deletions.
5 changes: 1 addition & 4 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
name: "CI"

on:
push:
branches:
- main
pull_request: {}
push

env:
CI: true
Expand Down
14 changes: 2 additions & 12 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion rusl/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "rusl"
version = "0.1.0"
version = "0.2.0"
edition = "2021"
license = "MPL-2.0"
readme = "../Readme.md"
Expand All @@ -15,6 +15,7 @@ keywords = ["ffi", "bindings", "operating", "system", "linux"]
[features]
default = ["alloc"]
alloc = []
integration-test = []

[dependencies]
linux-rust-bindings = { version = "0.1.1", features = ["all"] }
Expand Down
9 changes: 9 additions & 0 deletions rusl/Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,22 @@ All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).

## [Unreleased]
### Fixed

### Added

### Changed

## [v0.2.0] - 2023-10-01

### Changed
- API-breakage from removing AsRefUnixStr and replacing with
`&UnixStr`. Propagates down to all things containing `&UnixStr`. Main reason
is making allocation more explicit on the user's side, inviting opportunities for
const-evaluation of null-terminated strings.

## [v0.1.0] - 2023-07-25

### Added
Expand Down
32 changes: 22 additions & 10 deletions rusl/src/io_uring/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,11 @@ fn uring_register_files() {
let Some(uring_fd) = setup_io_poll_uring() else {
return;
};
let open_fd = open("test-files/can_open.txt\0", OpenFlags::O_RDWR).unwrap();
let open_fd = open(
UnixStr::try_from_str("test-files/can_open.txt\0").unwrap(),
OpenFlags::O_RDWR,
)
.unwrap();
io_uring_register_files(uring_fd, &[open_fd]).unwrap();
}

Expand Down Expand Up @@ -103,7 +107,11 @@ fn uring_single_read() {
let mut bytes = [0u8; 1024];
let buf = IoSliceMut::new(&mut bytes);
let mut slices = [buf];
let fd = open("test-files/can_open.txt\0", OpenFlags::O_RDONLY).unwrap();
let fd = open(
UnixStr::try_from_str("test-files/can_open.txt\0").unwrap(),
OpenFlags::O_RDONLY,
)
.unwrap();
let user_data = 15;
let entry = unsafe {
IoUringSubmissionQueueEntry::new_readv(
Expand Down Expand Up @@ -193,7 +201,11 @@ fn uring_single_close() {
let Some(mut uring) = setup_ignore_enosys(8, IoUringParamFlags::empty()) else {
return;
};
let fd = open("test-files/can_open.txt\0", OpenFlags::O_RDONLY).unwrap();
let fd = open(
UnixStr::try_from_str("test-files/can_open.txt\0").unwrap(),
OpenFlags::O_RDONLY,
)
.unwrap();
let user_data = 35;
let entry = IoUringSubmissionQueueEntry::new_close(fd, user_data, IoUringSQEFlags::empty());
write_await_single_entry(&mut uring, entry, user_data);
Expand Down Expand Up @@ -317,7 +329,7 @@ fn uring_single_mkdir_at() {
IoUringSubmissionQueueEntry::new_mkdirat(
None,
new_dir_path,
Mode::empty(),
Mode(0o755),
user_data,
IoUringSQEFlags::empty(),
)
Expand Down Expand Up @@ -495,17 +507,17 @@ fn uring_read_registered_buffers_and_fds() {
.unwrap();
}
let fd1 = open(
"test-files/io_uring/uring_register_read1\0",
UnixStr::try_from_str("test-files/io_uring/uring_register_read1\0").unwrap(),
OpenFlags::O_RDONLY,
)
.unwrap();
let fd2 = open(
"test-files/io_uring/uring_register_read2\0",
UnixStr::try_from_str("test-files/io_uring/uring_register_read2\0").unwrap(),
OpenFlags::O_RDONLY,
)
.unwrap();
let fd3 = open(
"test-files/io_uring/uring_register_read3\0",
UnixStr::try_from_str("test-files/io_uring/uring_register_read3\0").unwrap(),
OpenFlags::O_RDONLY,
)
.unwrap();
Expand Down Expand Up @@ -594,9 +606,9 @@ fn uring_write_registered_buffers_and_fds() {
)
.unwrap();
}
let path1 = "test-files/io_uring/tmp_uring_register_write1\0";
let path2 = "test-files/io_uring/tmp_uring_register_write2\0";
let path3 = "test-files/io_uring/tmp_uring_register_write3\0";
let path1 = UnixStr::try_from_str("test-files/io_uring/tmp_uring_register_write1\0").unwrap();
let path2 = UnixStr::try_from_str("test-files/io_uring/tmp_uring_register_write2\0").unwrap();
let path3 = UnixStr::try_from_str("test-files/io_uring/tmp_uring_register_write3\0").unwrap();
let fd1 = open_mode(
path1,
OpenFlags::O_RDWR | OpenFlags::O_CREAT | OpenFlags::O_TRUNC,
Expand Down
14 changes: 7 additions & 7 deletions rusl/src/platform/compat/socket.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! These are not defined in the uapi which is a bit hairy, if they change, that's obviously
use crate::string::unix_str::UnixStr;
/// a problem.
use crate::string::unix_str::AsUnixStr;
use crate::Error;

#[derive(Debug, Copy, Clone)]
Expand Down Expand Up @@ -122,14 +122,14 @@ impl SocketAddress {
self.0.sun_path
}

/// Tries to construct a `SocketAddress` from an `AsUnixStr` path
/// Tries to construct a `SocketAddress` from a `UnixStr` path
/// # Errors
/// The path is longer than 108 bytes (null termination included)
pub fn try_from_unix<P: AsUnixStr>(path: P) -> crate::Result<SocketArg> {
pub fn try_from_unix(path: &UnixStr) -> crate::Result<SocketArg> {
let mut ind = 0;
let buf = path.exec_with_self_as_ptr(|ptr| unsafe {
let buf = unsafe {
let mut buf = [0; 108];
let mut ptr = ptr;
let mut ptr = path.as_ptr();
while !ptr.is_null() {
buf[ind] = ptr.read() as core::ffi::c_char;
if ind == 107 && buf[ind] != 0 {
Expand All @@ -141,8 +141,8 @@ impl SocketAddress {
ptr = ptr.add(1);
ind += 1;
}
Ok(buf)
})?;
buf
};
let addr = Self(linux_rust_bindings::socket::sockaddr_un {
sun_family: AddressFamily::AF_UNIX.0,
sun_path: buf,
Expand Down
18 changes: 8 additions & 10 deletions rusl/src/process/execve.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use sc::syscall;

use crate::string::unix_str::AsUnixStr;
use crate::string::unix_str::UnixStr;
use crate::Error;

/// Executes provided binary `bin` with arguments `arg_v` and environment `env_p`.
Expand All @@ -14,16 +14,14 @@ use crate::Error;
/// # Safety
/// See above
#[inline]
pub unsafe fn execve<B: AsUnixStr>(
bin: B,
pub unsafe fn execve(
bin: &UnixStr,
arg_v: *const *const u8,
env_p: *const *const u8,
) -> Result<(), Error> {
bin.exec_with_self_as_ptr(|ptr| {
let res = syscall!(EXECVE, ptr, arg_v, env_p);
// EXECVE doesn't return on success, on err it returns an error code
// [docs](https://man7.org/linux/man-pages/man2/execve.2.html#RETURN_VALUE)
#[allow(clippy::cast_possible_truncation, clippy::cast_possible_wrap)]
Err(Error::with_code("`EXECVE` syscall failed", res as i32))
})
let res = syscall!(EXECVE, bin.as_ptr(), arg_v, env_p);
// EXECVE doesn't return on success, on err it returns an error code
// [docs](https://man7.org/linux/man-pages/man2/execve.2.html#RETURN_VALUE)
#[allow(clippy::cast_possible_truncation, clippy::cast_possible_wrap)]
Err(Error::with_code("`EXECVE` syscall failed", res as i32))
}
1 change: 1 addition & 0 deletions rusl/src/select/poll.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ mod tests {
fn poll_stdout_ready() {
// Stdout should essentially always be ready for output
let mut poll_fds = [PollFd::new(STDOUT, PollEvents::POLLOUT)];
println!("Dummy out");
let num_rdy = ppoll(&mut poll_fds, Some(&TimeSpec::new(1, 0)), None).unwrap();
// Get one changed revents
assert_eq!(1, num_rdy);
Expand Down
21 changes: 0 additions & 21 deletions rusl/src/string.rs
Original file line number Diff line number Diff line change
@@ -1,25 +1,4 @@
use crate::platform::NULL_BYTE;

pub mod strlen;
#[cfg(test)]
mod test;
pub mod unix_str;

/// Basic compare two null terminated strings
/// # Safety
/// Instant UB if these pointers are not null terminated
#[inline]
#[must_use]
pub unsafe fn null_term_ptr_cmp_up_to(a: *const u8, b: *const u8) -> usize {
let mut it = 0;
loop {
let a_val = a.add(it).read();
let b_val = b.add(it).read();
if a_val != b_val || a_val == NULL_BYTE {
// Not equal, or terminated
return it;
}
// Equal continue
it += 1;
}
}
91 changes: 0 additions & 91 deletions rusl/src/string/test.rs
Original file line number Diff line number Diff line change
@@ -1,88 +1,4 @@
use crate::platform::NULL_BYTE;
use crate::string::strlen::{buf_strlen, strlen};
use crate::string::unix_str::{AsUnixStr, UnixStr};

#[test]
#[cfg(not(feature = "alloc"))]
fn errs_on_not_null_without_alloc() {
let use_with_non_null_without_allocator = "Hello".exec_with_self_as_ptr(|_| Ok(()));
assert!(use_with_non_null_without_allocator.is_err());
}

#[test]
#[cfg(feature = "alloc")]
fn accepts_not_null_on_alloc() {
let use_with_non_null_without_allocator = "Hello".exec_with_self_as_ptr(|_| Ok(()));
assert!(use_with_non_null_without_allocator.is_ok());
}

#[test]
fn errs_on_many_null() {
let raw = "Hello\0oh no\0";
let many_non_null_res = raw.exec_with_self_as_ptr(|_| Ok(()));
assert!(many_non_null_res.is_err());
}

#[test]
fn accepts_empty() {
let empty = "".exec_with_self_as_ptr(|ptr| {
let null_byte = unsafe { ptr.read() };
assert_eq!(NULL_BYTE, null_byte);
Ok(())
});
assert!(empty.is_ok());
}

#[test]
#[cfg(feature = "alloc")]
fn accepts_non_null_terminated_with_allocator() {
use alloc::borrow::ToOwned;
let owned = "Hello".to_owned();
let non_null_term_with_alloc = owned.exec_with_self_as_ptr(|_| Ok(()));
assert!(non_null_term_with_alloc.is_ok());
}

#[test]
#[cfg(feature = "alloc")]
fn can_convert_into_unix_string() {
use crate::string::unix_str::UnixString;
let template = UnixString::try_from("Hello!\0").unwrap();
let owned_with_null = b"Hello!\0".to_vec();
assert_eq!(
template,
UnixString::try_from(owned_with_null.clone()).unwrap()
);
let owned_non_null = b"Hello!".to_vec();
assert_eq!(
template,
UnixString::try_from(owned_non_null.clone()).unwrap()
);
let owned_empty = b"".to_vec();
let template_empty = UnixString::try_from("\0").unwrap();
assert_eq!(
template_empty,
UnixString::try_from(owned_empty.clone()).unwrap()
);
let bad_input = "Hi!\0Hello!\0";
assert!(UnixString::try_from(bad_input).is_err());
}

#[test]
fn can_match_up_to() {
let haystack = "haystack\0";
unsafe {
let needle = "\0";
assert_eq!(0, haystack.match_up_to(needle.as_ptr()));
let needle = "h\0";
assert_eq!(1, haystack.match_up_to(needle.as_ptr()));
let needle = "haystac\0";
assert_eq!(7, haystack.match_up_to(needle.as_ptr()));
let needle = "haystack\0";
assert_eq!(8, haystack.match_up_to(needle.as_ptr()));
let needle = "haystack2\0";
assert_eq!(8, haystack.match_up_to(needle.as_ptr()));
}
}

#[test]
fn can_check_strlen() {
Expand All @@ -107,10 +23,3 @@ fn can_check_buf_strlen() {
let bad = b"10_000_000";
assert!(buf_strlen(bad).is_err());
}

#[test]
fn can_const_instantiate_unix_str() {
// Const eval would fail here.
const MY_CONST_UNIX_STR: &UnixStr = UnixStr::from_str_checked("Hello!\0");
assert_eq!(MY_CONST_UNIX_STR, UnixStr::from_str_checked("Hello!\0"));
}
Loading

0 comments on commit b8c9e90

Please sign in to comment.