From 69cf61f91e49c22f6dc83b6d64da0381d543f60c Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Tue, 19 May 2026 14:03:52 +0100 Subject: [PATCH 1/4] Add stat tests --- rules/stat/ir_unsafe.json | 114 ++++++++++++++++++++++ rules/stat/src.cpp | 12 +++ rules/stat/tgt_unsafe.rs | 14 +++ tests/unit/out/unsafe/sys_stat.rs | 154 ++++++++++++++++++++++++++++++ tests/unit/sys_stat.c | 53 ++++++++++ 5 files changed, 347 insertions(+) create mode 100644 rules/stat/ir_unsafe.json create mode 100644 rules/stat/src.cpp create mode 100644 rules/stat/tgt_unsafe.rs create mode 100644 tests/unit/out/unsafe/sys_stat.rs create mode 100644 tests/unit/sys_stat.c diff --git a/rules/stat/ir_unsafe.json b/rules/stat/ir_unsafe.json new file mode 100644 index 0000000..c3edc39 --- /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": ")" + } + ], + "params": { + "a0": { + "type": "*const u8", + "is_unsafe_pointer": true + }, + "a1": { + "type": "u32" + } + }, + "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..7ed43e6 --- /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: u32) -> i32 { + libc::mkdir(a0 as *const i8, a1) +} diff --git a/tests/unit/out/unsafe/sys_stat.rs b/tests/unit/out/unsafe/sys_stat.rs new file mode 100644 index 0000000..81104e9 --- /dev/null +++ b/tests/unit/out/unsafe/sys_stat.rs @@ -0,0 +1,154 @@ +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 unsafe fn test_mkdir_2() { + let mut path: *const u8 = (b"/tmp/cpp2rust_mkdir_test_dir\0".as_ptr().cast_mut()).cast_const(); + libc::rmdir(path as *const i8); + assert!(((((libc::mkdir(path as *const i8, 493_u32)) == (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_mode) & (61440_u32)) == ((16384) as u32)) as i32) != 0)); + (*libc::__errno_location()) = 0; + assert!(((((libc::mkdir(path as *const i8, 493_u32)) == (-1_i32)) as i32) != 0)); + assert!(((((*libc::__errno_location()) == (17)) as i32) != 0)); + assert!(((((libc::rmdir(path as *const i8)) == (0)) as i32) != 0)); + (*libc::__errno_location()) = 0; +} +pub fn main() { + unsafe { + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + (unsafe { test_stat_0() }); + (unsafe { test_fstat_1() }); + (unsafe { test_mkdir_2() }); + return 0; +} diff --git a/tests/unit/sys_stat.c b/tests/unit/sys_stat.c new file mode 100644 index 0000000..b54d097 --- /dev/null +++ b/tests/unit/sys_stat.c @@ -0,0 +1,53 @@ +// 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); +} + +static void test_mkdir(void) { + const char *path = "/tmp/cpp2rust_mkdir_test_dir"; + rmdir(path); + assert(mkdir(path, 0755) == 0); + struct stat st; + assert(stat(path, &st) == 0); + assert(S_ISDIR(st.st_mode)); + errno = 0; + assert(mkdir(path, 0755) == -1); + assert(errno == EEXIST); + assert(rmdir(path) == 0); + errno = 0; +} + +int main(void) { + test_stat(); + test_fstat(); + test_mkdir(); + return 0; +} From 9c455c680161756b74a6b6664719d44e45690b53 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 20 May 2026 14:36:52 +0100 Subject: [PATCH 2/4] Update tests --- rules/src/modules.rs | 2 ++ tests/unit/out/unsafe/sys_stat.rs | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) 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/tests/unit/out/unsafe/sys_stat.rs b/tests/unit/out/unsafe/sys_stat.rs index 81104e9..b347094 100644 --- a/tests/unit/out/unsafe/sys_stat.rs +++ b/tests/unit/out/unsafe/sys_stat.rs @@ -135,11 +135,11 @@ pub unsafe fn test_mkdir_2() { 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_mode) & (61440_u32)) == ((16384) as u32)) as i32) != 0)); - (*libc::__errno_location()) = 0; + (*libcc2rs::cpp2rust_errno()) = 0; assert!(((((libc::mkdir(path as *const i8, 493_u32)) == (-1_i32)) as i32) != 0)); - assert!(((((*libc::__errno_location()) == (17)) as i32) != 0)); + assert!(((((*libcc2rs::cpp2rust_errno()) == (17)) as i32) != 0)); assert!(((((libc::rmdir(path as *const i8)) == (0)) as i32) != 0)); - (*libc::__errno_location()) = 0; + (*libcc2rs::cpp2rust_errno()) = 0; } pub fn main() { unsafe { From c529f7c0fc2bfc7898b80e11902f8c66cb9e843c Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 20 May 2026 14:42:45 +0100 Subject: [PATCH 3/4] Add portable argument for mkdir --- rules/stat/ir_unsafe.json | 4 ++-- rules/stat/tgt_unsafe.rs | 4 ++-- tests/unit/out/unsafe/sys_stat.rs | 6 ++++-- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/rules/stat/ir_unsafe.json b/rules/stat/ir_unsafe.json index c3edc39..b6236de 100644 --- a/rules/stat/ir_unsafe.json +++ b/rules/stat/ir_unsafe.json @@ -95,7 +95,7 @@ } }, { - "text": ")" + "text": " as ::libc::mode_t)" } ], "params": { @@ -104,7 +104,7 @@ "is_unsafe_pointer": true }, "a1": { - "type": "u32" + "type": "::libc::mode_t" } }, "return_type": { diff --git a/rules/stat/tgt_unsafe.rs b/rules/stat/tgt_unsafe.rs index 7ed43e6..038bd70 100644 --- a/rules/stat/tgt_unsafe.rs +++ b/rules/stat/tgt_unsafe.rs @@ -9,6 +9,6 @@ unsafe fn f2(a0: i32, a1: *mut ::libc::stat) -> i32 { libc::fstat(a0, a1) } -unsafe fn f3(a0: *const u8, a1: u32) -> i32 { - libc::mkdir(a0 as *const i8, 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 index b347094..fa3efda 100644 --- a/tests/unit/out/unsafe/sys_stat.rs +++ b/tests/unit/out/unsafe/sys_stat.rs @@ -131,12 +131,14 @@ pub unsafe fn test_fstat_1() { pub unsafe fn test_mkdir_2() { let mut path: *const u8 = (b"/tmp/cpp2rust_mkdir_test_dir\0".as_ptr().cast_mut()).cast_const(); libc::rmdir(path as *const i8); - assert!(((((libc::mkdir(path as *const i8, 493_u32)) == (0)) as i32) != 0)); + assert!(((((libc::mkdir(path as *const i8, 493_u32 as ::libc::mode_t)) == (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_mode) & (61440_u32)) == ((16384) as u32)) as i32) != 0)); (*libcc2rs::cpp2rust_errno()) = 0; - assert!(((((libc::mkdir(path as *const i8, 493_u32)) == (-1_i32)) as i32) != 0)); + assert!( + ((((libc::mkdir(path as *const i8, 493_u32 as ::libc::mode_t)) == (-1_i32)) as i32) != 0) + ); assert!(((((*libcc2rs::cpp2rust_errno()) == (17)) as i32) != 0)); assert!(((((libc::rmdir(path as *const i8)) == (0)) as i32) != 0)); (*libcc2rs::cpp2rust_errno()) = 0; From 0c3476f95c4393d3681c2b5bd7c69afdc33cf444 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 20 May 2026 21:25:46 +0100 Subject: [PATCH 4/4] Delete pattern --- tests/unit/out/unsafe/sys_stat.rs | 16 ---------------- tests/unit/sys_stat.c | 15 --------------- 2 files changed, 31 deletions(-) diff --git a/tests/unit/out/unsafe/sys_stat.rs b/tests/unit/out/unsafe/sys_stat.rs index fa3efda..a90489c 100644 --- a/tests/unit/out/unsafe/sys_stat.rs +++ b/tests/unit/out/unsafe/sys_stat.rs @@ -128,21 +128,6 @@ pub unsafe fn test_fstat_1() { ); libc::unlink(path as *const i8); } -pub unsafe fn test_mkdir_2() { - let mut path: *const u8 = (b"/tmp/cpp2rust_mkdir_test_dir\0".as_ptr().cast_mut()).cast_const(); - libc::rmdir(path as *const i8); - assert!(((((libc::mkdir(path as *const i8, 493_u32 as ::libc::mode_t)) == (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_mode) & (61440_u32)) == ((16384) as u32)) as i32) != 0)); - (*libcc2rs::cpp2rust_errno()) = 0; - assert!( - ((((libc::mkdir(path as *const i8, 493_u32 as ::libc::mode_t)) == (-1_i32)) as i32) != 0) - ); - assert!(((((*libcc2rs::cpp2rust_errno()) == (17)) as i32) != 0)); - assert!(((((libc::rmdir(path as *const i8)) == (0)) as i32) != 0)); - (*libcc2rs::cpp2rust_errno()) = 0; -} pub fn main() { unsafe { std::process::exit(main_0() as i32); @@ -151,6 +136,5 @@ pub fn main() { unsafe fn main_0() -> i32 { (unsafe { test_stat_0() }); (unsafe { test_fstat_1() }); - (unsafe { test_mkdir_2() }); return 0; } diff --git a/tests/unit/sys_stat.c b/tests/unit/sys_stat.c index b54d097..a7e86ef 100644 --- a/tests/unit/sys_stat.c +++ b/tests/unit/sys_stat.c @@ -31,23 +31,8 @@ static void test_fstat(void) { unlink(path); } -static void test_mkdir(void) { - const char *path = "/tmp/cpp2rust_mkdir_test_dir"; - rmdir(path); - assert(mkdir(path, 0755) == 0); - struct stat st; - assert(stat(path, &st) == 0); - assert(S_ISDIR(st.st_mode)); - errno = 0; - assert(mkdir(path, 0755) == -1); - assert(errno == EEXIST); - assert(rmdir(path) == 0); - errno = 0; -} - int main(void) { test_stat(); test_fstat(); - test_mkdir(); return 0; }