diff --git a/rules/src/modules.rs b/rules/src/modules.rs index 9920f88..a686480 100644 --- a/rules/src/modules.rs +++ b/rules/src/modules.rs @@ -64,6 +64,8 @@ pub mod pair_tgt_refcount; pub mod pair_tgt_unsafe; #[path = r#"../socket/tgt_unsafe.rs"#] pub mod socket_tgt_unsafe; +#[path = r#"../stat/tgt_unsafe.rs"#] +pub mod stat_tgt_unsafe; #[path = r#"../stdio/tgt_refcount.rs"#] pub mod stdio_tgt_refcount; #[path = r#"../stdio/tgt_unsafe.rs"#] diff --git a/rules/stat/ir_unsafe.json b/rules/stat/ir_unsafe.json new file mode 100644 index 0000000..b6236de --- /dev/null +++ b/rules/stat/ir_unsafe.json @@ -0,0 +1,114 @@ +{ + "f1": { + "body": [ + { + "text": "libc::stat(" + }, + { + "placeholder": { + "arg": 0, + "access": "read" + } + }, + { + "text": " as *const i8, " + }, + { + "placeholder": { + "arg": 1, + "access": "read" + } + }, + { + "text": ")" + } + ], + "params": { + "a0": { + "type": "*const u8", + "is_unsafe_pointer": true + }, + "a1": { + "type": "*mut ::libc::stat", + "is_unsafe_pointer": true + } + }, + "return_type": { + "type": "i32" + } + }, + "f2": { + "body": [ + { + "text": "libc::fstat(" + }, + { + "placeholder": { + "arg": 0, + "access": "read" + } + }, + { + "text": ", " + }, + { + "placeholder": { + "arg": 1, + "access": "read" + } + }, + { + "text": ")" + } + ], + "params": { + "a0": { + "type": "i32" + }, + "a1": { + "type": "*mut ::libc::stat", + "is_unsafe_pointer": true + } + }, + "return_type": { + "type": "i32" + } + }, + "f3": { + "body": [ + { + "text": "libc::mkdir(" + }, + { + "placeholder": { + "arg": 0, + "access": "read" + } + }, + { + "text": " as *const i8, " + }, + { + "placeholder": { + "arg": 1, + "access": "read" + } + }, + { + "text": " as ::libc::mode_t)" + } + ], + "params": { + "a0": { + "type": "*const u8", + "is_unsafe_pointer": true + }, + "a1": { + "type": "::libc::mode_t" + } + }, + "return_type": { + "type": "i32" + } + } +} diff --git a/rules/stat/src.cpp b/rules/stat/src.cpp new file mode 100644 index 0000000..960278a --- /dev/null +++ b/rules/stat/src.cpp @@ -0,0 +1,12 @@ +// Copyright (c) 2022-present INESC-ID. +// Distributed under the MIT license that can be found in the LICENSE file. + +#include + +int f1(const char *pathname, struct stat *statbuf) { + return stat(pathname, statbuf); +} + +int f2(int fd, struct stat *statbuf) { return fstat(fd, statbuf); } + +int f3(const char *pathname, mode_t mode) { return mkdir(pathname, mode); } diff --git a/rules/stat/tgt_unsafe.rs b/rules/stat/tgt_unsafe.rs new file mode 100644 index 0000000..038bd70 --- /dev/null +++ b/rules/stat/tgt_unsafe.rs @@ -0,0 +1,14 @@ +// Copyright (c) 2022-present INESC-ID. +// Distributed under the MIT license that can be found in the LICENSE file. + +unsafe fn f1(a0: *const u8, a1: *mut ::libc::stat) -> i32 { + libc::stat(a0 as *const i8, a1) +} + +unsafe fn f2(a0: i32, a1: *mut ::libc::stat) -> i32 { + libc::fstat(a0, a1) +} + +unsafe fn f3(a0: *const u8, a1: ::libc::mode_t) -> i32 { + libc::mkdir(a0 as *const i8, a1 as ::libc::mode_t) +} diff --git a/tests/unit/out/unsafe/sys_stat.rs b/tests/unit/out/unsafe/sys_stat.rs new file mode 100644 index 0000000..a90489c --- /dev/null +++ b/tests/unit/out/unsafe/sys_stat.rs @@ -0,0 +1,140 @@ +extern crate libc; +use libc::*; +extern crate libcc2rs; +use libcc2rs::*; +use std::collections::BTreeMap; +use std::io::{Read, Seek, Write}; +use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; +use std::rc::Rc; +pub unsafe fn test_stat_0() { + let mut path: *const u8 = (b"/tmp/cpp2rust_stat_test.tmp\0".as_ptr().cast_mut()).cast_const(); + let mut fp: *mut ::std::fs::File = + match std::ffi::CStr::from_ptr((b"wb\0".as_ptr().cast_mut()).cast_const() as *const i8) + .to_str() + .expect("invalid c-string") + { + v if v == "rb" => std::fs::OpenOptions::new() + .read(true) + .open( + std::ffi::CStr::from_ptr(path as *const i8) + .to_str() + .expect("invalid c-string"), + ) + .ok() + .map_or(std::ptr::null_mut(), |f| Box::into_raw(Box::new(f))), + v if v == "wb" => std::fs::OpenOptions::new() + .write(true) + .create(true) + .truncate(true) + .open( + std::ffi::CStr::from_ptr(path as *const i8) + .to_str() + .expect("invalid c-string"), + ) + .ok() + .map_or(std::ptr::null_mut(), |f| Box::into_raw(Box::new(f))), + _ => panic!("unsupported mode"), + }; + assert!((((!((fp).is_null())) as i32) != 0)); + { + let bytes = + std::ffi::CStr::from_ptr((b"hello\0".as_ptr().cast_mut()).cast_const() as *const i8) + .to_bytes(); + match (*fp).write_all(bytes) { + Ok(()) => 0, + Err(_) => -1, + } + }; + assert!( + (((({ + Box::from_raw(fp); + 0 + }) == (0)) as i32) + != 0) + ); + let mut st: stat = std::mem::zeroed::(); + assert!(((((libc::stat(path as *const i8, (&mut st as *mut stat))) == (0)) as i32) != 0)); + assert!(((((st.st_size) == (5_i64)) as i32) != 0)); + libc::unlink(path as *const i8); +} +pub unsafe fn test_fstat_1() { + let mut path: *const u8 = (b"/tmp/cpp2rust_fstat_test.tmp\0".as_ptr().cast_mut()).cast_const(); + let mut fp: *mut ::std::fs::File = + match std::ffi::CStr::from_ptr((b"wb\0".as_ptr().cast_mut()).cast_const() as *const i8) + .to_str() + .expect("invalid c-string") + { + v if v == "rb" => std::fs::OpenOptions::new() + .read(true) + .open( + std::ffi::CStr::from_ptr(path as *const i8) + .to_str() + .expect("invalid c-string"), + ) + .ok() + .map_or(std::ptr::null_mut(), |f| Box::into_raw(Box::new(f))), + v if v == "wb" => std::fs::OpenOptions::new() + .write(true) + .create(true) + .truncate(true) + .open( + std::ffi::CStr::from_ptr(path as *const i8) + .to_str() + .expect("invalid c-string"), + ) + .ok() + .map_or(std::ptr::null_mut(), |f| Box::into_raw(Box::new(f))), + _ => panic!("unsupported mode"), + }; + assert!((((!((fp).is_null())) as i32) != 0)); + { + let bytes = std::ffi::CStr::from_ptr( + (b"hello world\0".as_ptr().cast_mut()).cast_const() as *const i8 + ) + .to_bytes(); + match (*fp).write_all(bytes) { + Ok(()) => 0, + Err(_) => -1, + } + }; + if !(fp).is_null() { + match (*fp).sync_all() { + Ok(_) => 0, + Err(_) => -1, + } + } else { + ::std::io::stdout().flush().unwrap(); + ::std::io::stderr().flush().unwrap(); + 0 + }; + let mut fd: i32 = if fp == libcc2rs::cin_unsafe() { + 0 + } else if fp == libcc2rs::cout_unsafe() { + 1 + } else if fp == libcc2rs::cerr_unsafe() { + 2 + } else { + ::std::os::fd::AsRawFd::as_raw_fd(&*fp) + }; + let mut st: stat = std::mem::zeroed::(); + assert!(((((libc::fstat(fd, (&mut st as *mut stat))) == (0)) as i32) != 0)); + assert!(((((st.st_size) == (11_i64)) as i32) != 0)); + assert!( + (((({ + Box::from_raw(fp); + 0 + }) == (0)) as i32) + != 0) + ); + libc::unlink(path as *const i8); +} +pub fn main() { + unsafe { + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + (unsafe { test_stat_0() }); + (unsafe { test_fstat_1() }); + return 0; +} diff --git a/tests/unit/sys_stat.c b/tests/unit/sys_stat.c new file mode 100644 index 0000000..a7e86ef --- /dev/null +++ b/tests/unit/sys_stat.c @@ -0,0 +1,38 @@ +// no-compile: refcount +#include +#include +#include +#include +#include + +static void test_stat(void) { + const char *path = "/tmp/cpp2rust_stat_test.tmp"; + FILE *fp = fopen(path, "wb"); + assert(fp != NULL); + fputs("hello", fp); + assert(fclose(fp) == 0); + struct stat st; + assert(stat(path, &st) == 0); + assert(st.st_size == 5); + unlink(path); +} + +static void test_fstat(void) { + const char *path = "/tmp/cpp2rust_fstat_test.tmp"; + FILE *fp = fopen(path, "wb"); + assert(fp != NULL); + fputs("hello world", fp); + fflush(fp); + int fd = fileno(fp); + struct stat st; + assert(fstat(fd, &st) == 0); + assert(st.st_size == 11); + assert(fclose(fp) == 0); + unlink(path); +} + +int main(void) { + test_stat(); + test_fstat(); + return 0; +}