From e47eaa9f4bd39f338e06ae5cfae7b8b398c391b5 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Thu, 21 May 2026 10:14:32 +0100 Subject: [PATCH 1/5] Misc rules --- rules/arpa_inet/ir_unsafe.json | 48 ++++++ rules/arpa_inet/src.cpp | 2 + rules/arpa_inet/tgt_unsafe.rs | 6 + rules/cstdlib/ir_unsafe.json | 133 ++++++++++++++++ rules/cstdlib/src.cpp | 10 ++ rules/cstdlib/tgt_unsafe.rs | 36 +++++ rules/cstring/ir_unsafe.json | 57 +++++++ rules/cstring/src.c | 4 + rules/cstring/tgt_unsafe.rs | 5 + rules/socket/ir_unsafe.json | 212 +++++++++++++++++++++++++ rules/socket/src.cpp | 18 +++ rules/socket/tgt_unsafe.rs | 17 ++ rules/src/modules.rs | 2 + rules/time/ir_unsafe.json | 281 +++++++++++++++++++++++++++++++++ rules/time/src.c | 31 ++++ rules/time/tgt_unsafe.rs | 30 ++++ rules/xattr/ir_unsafe.json | 77 +++++++++ rules/xattr/src.c | 11 ++ rules/xattr/tgt_unsafe.rs | 7 + 19 files changed, 987 insertions(+) create mode 100644 rules/time/ir_unsafe.json create mode 100644 rules/time/src.c create mode 100644 rules/time/tgt_unsafe.rs create mode 100644 rules/xattr/ir_unsafe.json create mode 100644 rules/xattr/src.c create mode 100644 rules/xattr/tgt_unsafe.rs diff --git a/rules/arpa_inet/ir_unsafe.json b/rules/arpa_inet/ir_unsafe.json index c494512a..181d20a1 100644 --- a/rules/arpa_inet/ir_unsafe.json +++ b/rules/arpa_inet/ir_unsafe.json @@ -46,5 +46,53 @@ "return_type": { "type": "u16" } + }, + "f3": { + "body": [ + { + "text": "u16::to_be(" + }, + { + "placeholder": { + "arg": 0, + "access": "read" + } + }, + { + "text": ")" + } + ], + "params": { + "a0": { + "type": "u16" + } + }, + "return_type": { + "type": "u16" + } + }, + "f4": { + "body": [ + { + "text": "u32::to_be(" + }, + { + "placeholder": { + "arg": 0, + "access": "read" + } + }, + { + "text": ")" + } + ], + "params": { + "a0": { + "type": "u32" + } + }, + "return_type": { + "type": "u32" + } } } diff --git a/rules/arpa_inet/src.cpp b/rules/arpa_inet/src.cpp index c321aeeb..aec5ecd3 100644 --- a/rules/arpa_inet/src.cpp +++ b/rules/arpa_inet/src.cpp @@ -5,3 +5,5 @@ uint32_t f1(uint32_t x) { return ntohl(x); } uint16_t f2(uint16_t x) { return ntohs(x); } +uint16_t f3(uint16_t x) { return htons(x); } +uint32_t f4(uint32_t x) { return htonl(x); } diff --git a/rules/arpa_inet/tgt_unsafe.rs b/rules/arpa_inet/tgt_unsafe.rs index 785aec66..5824ba7e 100644 --- a/rules/arpa_inet/tgt_unsafe.rs +++ b/rules/arpa_inet/tgt_unsafe.rs @@ -7,3 +7,9 @@ unsafe fn f1(a0: u32) -> u32 { unsafe fn f2(a0: u16) -> u16 { u16::from_be(a0) } +unsafe fn f3(a0: u16) -> u16 { + u16::to_be(a0) +} +unsafe fn f4(a0: u32) -> u32 { + u32::to_be(a0) +} diff --git a/rules/cstdlib/ir_unsafe.json b/rules/cstdlib/ir_unsafe.json index 7bb7bb57..a394a08a 100644 --- a/rules/cstdlib/ir_unsafe.json +++ b/rules/cstdlib/ir_unsafe.json @@ -203,5 +203,138 @@ "return_type": { "type": "i32" } + }, + "f8": { + "body": [ + { + "text": "libc::bsearch(\n " + }, + { + "placeholder": { + "arg": 0, + "access": "read" + } + }, + { + "text": ",\n " + }, + { + "placeholder": { + "arg": 1, + "access": "read" + } + }, + { + "text": ",\n " + }, + { + "placeholder": { + "arg": 2, + "access": "read" + } + }, + { + "text": " as ::libc::size_t,\n " + }, + { + "placeholder": { + "arg": 3, + "access": "read" + } + }, + { + "text": " as ::libc::size_t,\n Some(std::mem::transmute::<\n *const (),\n unsafe extern \"C\" fn(*const ::libc::c_void, *const ::libc::c_void) -> i32,\n >(" + }, + { + "placeholder": { + "arg": 4, + "access": "read" + } + }, + { + "text": " as *const ())),\n )" + } + ], + "params": { + "a0": { + "type": "*const ::libc::c_void", + "is_unsafe_pointer": true + }, + "a1": { + "type": "*const ::libc::c_void", + "is_unsafe_pointer": true + }, + "a2": { + "type": "u64" + }, + "a3": { + "type": "u64" + }, + "a4": { + "type": "unsafe fn(*const ::libc::c_void, *const ::libc::c_void) -> i32" + } + }, + "return_type": { + "type": "*mut ::libc::c_void", + "is_unsafe_pointer": true + } + }, + "f9": { + "body": [ + { + "text": "libc::qsort(\n " + }, + { + "placeholder": { + "arg": 0, + "access": "read" + } + }, + { + "text": ",\n " + }, + { + "placeholder": { + "arg": 1, + "access": "read" + } + }, + { + "text": " as ::libc::size_t,\n " + }, + { + "placeholder": { + "arg": 2, + "access": "read" + } + }, + { + "text": " as ::libc::size_t,\n Some(std::mem::transmute::<\n *const (),\n unsafe extern \"C\" fn(*const ::libc::c_void, *const ::libc::c_void) -> i32,\n >(" + }, + { + "placeholder": { + "arg": 3, + "access": "read" + } + }, + { + "text": " as *const ())),\n )" + } + ], + "params": { + "a0": { + "type": "*mut ::libc::c_void", + "is_unsafe_pointer": true + }, + "a1": { + "type": "u64" + }, + "a2": { + "type": "u64" + }, + "a3": { + "type": "unsafe fn(*const ::libc::c_void, *const ::libc::c_void) -> i32" + } + } } } diff --git a/rules/cstdlib/src.cpp b/rules/cstdlib/src.cpp index d81139f3..b800f02f 100644 --- a/rules/cstdlib/src.cpp +++ b/rules/cstdlib/src.cpp @@ -18,3 +18,13 @@ char *f6(const char *name) { return getenv(name); } int f7(const char *name, const char *value, int overwrite) { return setenv(name, value, overwrite); } + +void *f8(const void *key, const void *base, size_t nmemb, size_t size, + int (*compar)(const void *, const void *)) { + return bsearch(key, base, nmemb, size, compar); +} + +void f9(void *base, size_t nmemb, size_t size, + int (*compar)(const void *, const void *)) { + return qsort(base, nmemb, size, compar); +} diff --git a/rules/cstdlib/tgt_unsafe.rs b/rules/cstdlib/tgt_unsafe.rs index 953b07ef..aedeb411 100644 --- a/rules/cstdlib/tgt_unsafe.rs +++ b/rules/cstdlib/tgt_unsafe.rs @@ -28,3 +28,39 @@ unsafe fn f6(a0: *const u8) -> *mut u8 { unsafe fn f7(a0: *const u8, a1: *const u8, a2: i32) -> i32 { libc::setenv(a0 as *const i8, a1 as *const i8, a2) } + +unsafe fn f8( + a0: *const ::libc::c_void, + a1: *const ::libc::c_void, + a2: u64, + a3: u64, + a4: unsafe fn(*const ::libc::c_void, *const ::libc::c_void) -> i32, +) -> *mut ::libc::c_void { + libc::bsearch( + a0, + a1, + a2 as ::libc::size_t, + a3 as ::libc::size_t, + Some(std::mem::transmute::< + *const (), + unsafe extern "C" fn(*const ::libc::c_void, *const ::libc::c_void) -> i32, + >(a4 as *const ())), + ) +} + +unsafe fn f9( + a0: *mut ::libc::c_void, + a1: u64, + a2: u64, + a3: unsafe fn(*const ::libc::c_void, *const ::libc::c_void) -> i32, +) { + libc::qsort( + a0, + a1 as ::libc::size_t, + a2 as ::libc::size_t, + Some(std::mem::transmute::< + *const (), + unsafe extern "C" fn(*const ::libc::c_void, *const ::libc::c_void) -> i32, + >(a3 as *const ())), + ) +} diff --git a/rules/cstring/ir_unsafe.json b/rules/cstring/ir_unsafe.json index c39d8459..fbd18617 100644 --- a/rules/cstring/ir_unsafe.json +++ b/rules/cstring/ir_unsafe.json @@ -882,6 +882,63 @@ "type": "i32" } }, + "f28": { + "body": [ + { + "text": "libc::strerror_r(" + }, + { + "placeholder": { + "arg": 0, + "access": "read" + } + }, + { + "text": ", " + }, + { + "placeholder": { + "arg": 1, + "access": "read" + } + }, + { + "text": " as *mut i8, " + }, + { + "placeholder": { + "arg": 2, + "access": "read" + } + }, + { + "text": " as ::libc::size_t);\n " + }, + { + "placeholder": { + "arg": 1, + "access": "read" + } + } + ], + "multi_statement": true, + "params": { + "a0": { + "type": "i32" + }, + "a1": { + "type": "*mut u8", + "is_unsafe_pointer": true + }, + "a2": { + "type": "u64" + } + }, + "return_type": { + "type": "*mut u8", + "is_unsafe_pointer": true + } + }, "f3": { "body": [ { diff --git a/rules/cstring/src.c b/rules/cstring/src.c index be329a8e..7f82340c 100644 --- a/rules/cstring/src.c +++ b/rules/cstring/src.c @@ -40,3 +40,7 @@ void *f24(const void *a0, int a1, size_t a2) { return memrchr(a0, a1, a2); } #endif int f27(const char *a0, const char *a1) { return strcasecmp(a0, a1); } + +char* f28(int errnum, char *buf, size_t buflen) { + return strerror_r(errnum, buf, buflen); +} diff --git a/rules/cstring/tgt_unsafe.rs b/rules/cstring/tgt_unsafe.rs index 9ab40a81..5a54ecaa 100644 --- a/rules/cstring/tgt_unsafe.rs +++ b/rules/cstring/tgt_unsafe.rs @@ -130,3 +130,8 @@ unsafe fn f26(a0: *mut u8, a1: i32, a2: usize) -> *mut ::libc::c_void { unsafe fn f27(a0: *const u8, a1: *const u8) -> i32 { libc::strcasecmp(a0 as *const i8, a1 as *const i8) } + +unsafe fn f28(a0: i32, a1: *mut u8, a2: u64) -> *mut u8 { + libc::strerror_r(a0, a1 as *mut i8, a2 as ::libc::size_t); + a1 +} diff --git a/rules/socket/ir_unsafe.json b/rules/socket/ir_unsafe.json index d5af4452..b13e512b 100644 --- a/rules/socket/ir_unsafe.json +++ b/rules/socket/ir_unsafe.json @@ -131,6 +131,218 @@ "type": "i32" } }, + "f12": { + "body": [ + { + "text": "libc::getsockname(" + }, + { + "placeholder": { + "arg": 0, + "access": "read" + } + }, + { + "text": ", " + }, + { + "placeholder": { + "arg": 1, + "access": "read" + } + }, + { + "text": ", " + }, + { + "placeholder": { + "arg": 2, + "access": "read" + } + }, + { + "text": ")" + } + ], + "params": { + "a0": { + "type": "i32" + }, + "a1": { + "type": "*mut ::libc::sockaddr", + "is_unsafe_pointer": true + }, + "a2": { + "type": "*mut u32", + "is_unsafe_pointer": true + } + }, + "return_type": { + "type": "i32" + } + }, + "f13": { + "body": [ + { + "text": "libc::connect(" + }, + { + "placeholder": { + "arg": 0, + "access": "read" + } + }, + { + "text": ", " + }, + { + "placeholder": { + "arg": 1, + "access": "read" + } + }, + { + "text": ", " + }, + { + "placeholder": { + "arg": 2, + "access": "read" + } + }, + { + "text": ")" + } + ], + "params": { + "a0": { + "type": "i32" + }, + "a1": { + "type": "*const ::libc::sockaddr", + "is_unsafe_pointer": true + }, + "a2": { + "type": "u32" + } + }, + "return_type": { + "type": "i32" + } + }, + "f14": { + "body": [ + { + "text": "libc::getpeername(" + }, + { + "placeholder": { + "arg": 0, + "access": "read" + } + }, + { + "text": ", " + }, + { + "placeholder": { + "arg": 1, + "access": "read" + } + }, + { + "text": ", " + }, + { + "placeholder": { + "arg": 2, + "access": "read" + } + }, + { + "text": ")" + } + ], + "params": { + "a0": { + "type": "i32" + }, + "a1": { + "type": "*mut ::libc::sockaddr", + "is_unsafe_pointer": true + }, + "a2": { + "type": "*mut u32", + "is_unsafe_pointer": true + } + }, + "return_type": { + "type": "i32" + } + }, + "f15": { + "body": [ + { + "text": "libc::accept4(" + }, + { + "placeholder": { + "arg": 0, + "access": "read" + } + }, + { + "text": ", " + }, + { + "placeholder": { + "arg": 1, + "access": "read" + } + }, + { + "text": ", " + }, + { + "placeholder": { + "arg": 2, + "access": "read" + } + }, + { + "text": ", " + }, + { + "placeholder": { + "arg": 3, + "access": "read" + } + }, + { + "text": ")" + } + ], + "params": { + "a0": { + "type": "i32" + }, + "a1": { + "type": "*mut ::libc::sockaddr", + "is_unsafe_pointer": true + }, + "a2": { + "type": "*mut u32", + "is_unsafe_pointer": true + }, + "a3": { + "type": "i32" + } + }, + "return_type": { + "type": "i32" + }, + "target_os": "linux" + }, "f2": { "body": [ { diff --git a/rules/socket/src.cpp b/rules/socket/src.cpp index 3a511c15..f9654352 100644 --- a/rules/socket/src.cpp +++ b/rules/socket/src.cpp @@ -46,3 +46,21 @@ ssize_t f10(int sockfd, const void *buf, size_t len, int flags) { int f11(int domain, int type, int protocol, int sv[2]) { return socketpair(domain, type, protocol, sv); } + +int f12(int sockfd, struct sockaddr *addr, socklen_t *addrlen) { + return getsockname(sockfd, addr, addrlen); +} + +int f13(int sockfd, const struct sockaddr *addr, socklen_t addrlen) { + return connect(sockfd, addr, addrlen); +} + +int f14(int sockfd, struct sockaddr *addr, socklen_t *addrlen) { + return getpeername(sockfd, addr, addrlen); +} + +#ifdef __linux__ +int f15(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags) { + return accept4(sockfd, addr, addrlen, flags); +} +#endif diff --git a/rules/socket/tgt_unsafe.rs b/rules/socket/tgt_unsafe.rs index d07d4b2b..05bc972e 100644 --- a/rules/socket/tgt_unsafe.rs +++ b/rules/socket/tgt_unsafe.rs @@ -43,3 +43,20 @@ unsafe fn f10(a0: i32, a1: *const ::libc::c_void, a2: u64, a3: i32) -> i64 { unsafe fn f11(a0: i32, a1: i32, a2: i32, a3: *mut i32) -> i32 { libc::socketpair(a0, a1, a2, a3) } + +unsafe fn f12(a0: i32, a1: *mut ::libc::sockaddr, a2: *mut u32) -> i32 { + libc::getsockname(a0, a1, a2) +} + +unsafe fn f13(a0: i32, a1: *const ::libc::sockaddr, a2: u32) -> i32 { + libc::connect(a0, a1, a2) +} + +unsafe fn f14(a0: i32, a1: *mut ::libc::sockaddr, a2: *mut u32) -> i32 { + libc::getpeername(a0, a1, a2) +} + +#[cfg(target_os = "linux")] +unsafe fn f15(a0: i32, a1: *mut ::libc::sockaddr, a2: *mut u32, a3: i32) -> i32 { + libc::accept4(a0, a1, a2, a3) +} diff --git a/rules/src/modules.rs b/rules/src/modules.rs index b04c66fa..bd539543 100644 --- a/rules/src/modules.rs +++ b/rules/src/modules.rs @@ -98,3 +98,5 @@ pub mod unistd_tgt_unsafe; pub mod vector_tgt_refcount; #[path = r#"../vector/tgt_unsafe.rs"#] pub mod vector_tgt_unsafe; +#[path = r#"../xattr/tgt_unsafe.rs"#] +pub mod xattr_tgt_unsafe; diff --git a/rules/time/ir_unsafe.json b/rules/time/ir_unsafe.json new file mode 100644 index 00000000..2229c587 --- /dev/null +++ b/rules/time/ir_unsafe.json @@ -0,0 +1,281 @@ +{ + "f1": { + "body": [ + { + "text": "libc::time(" + }, + { + "placeholder": { + "arg": 0, + "access": "read" + } + }, + { + "text": ")" + } + ], + "params": { + "a0": { + "type": "*mut ::libc::time_t", + "is_unsafe_pointer": true + } + }, + "return_type": { + "type": "::libc::time_t" + } + }, + "f2": { + "body": [ + { + "text": "libc::clock_gettime(" + }, + { + "placeholder": { + "arg": 0, + "access": "read" + } + }, + { + "text": ", " + }, + { + "placeholder": { + "arg": 1, + "access": "read" + } + }, + { + "text": ")" + } + ], + "params": { + "a0": { + "type": "::libc::clockid_t" + }, + "a1": { + "type": "*mut ::libc::timespec", + "is_unsafe_pointer": true + } + }, + "return_type": { + "type": "i32" + } + }, + "f3": { + "body": [ + { + "text": "libc::gettimeofday(" + }, + { + "placeholder": { + "arg": 0, + "access": "read" + } + }, + { + "text": ", " + }, + { + "placeholder": { + "arg": 1, + "access": "read" + } + }, + { + "text": " as *mut ::libc::timezone)" + } + ], + "params": { + "a0": { + "type": "*mut ::libc::timeval", + "is_unsafe_pointer": true + }, + "a1": { + "type": "*mut ::libc::timezone", + "is_unsafe_pointer": true + } + }, + "return_type": { + "type": "i32" + } + }, + "f4": { + "body": [ + { + "text": "libc::gmtime_r(" + }, + { + "placeholder": { + "arg": 0, + "access": "read" + } + }, + { + "text": ", " + }, + { + "placeholder": { + "arg": 1, + "access": "read" + } + }, + { + "text": ")" + } + ], + "params": { + "a0": { + "type": "*const ::libc::time_t", + "is_unsafe_pointer": true + }, + "a1": { + "type": "*mut ::libc::tm", + "is_unsafe_pointer": true + } + }, + "return_type": { + "type": "*mut ::libc::tm", + "is_unsafe_pointer": true + } + }, + "f5": { + "body": [ + { + "text": "libc::localtime_r(" + }, + { + "placeholder": { + "arg": 0, + "access": "read" + } + }, + { + "text": ", " + }, + { + "placeholder": { + "arg": 1, + "access": "read" + } + }, + { + "text": ")" + } + ], + "params": { + "a0": { + "type": "*const ::libc::time_t", + "is_unsafe_pointer": true + }, + "a1": { + "type": "*mut ::libc::tm", + "is_unsafe_pointer": true + } + }, + "return_type": { + "type": "*mut ::libc::tm", + "is_unsafe_pointer": true + } + }, + "f6": { + "body": [ + { + "text": "libc::strftime(" + }, + { + "placeholder": { + "arg": 0, + "access": "read" + } + }, + { + "text": " as *mut i8, " + }, + { + "placeholder": { + "arg": 1, + "access": "read" + } + }, + { + "text": " as ::libc::size_t, " + }, + { + "placeholder": { + "arg": 2, + "access": "read" + } + }, + { + "text": " as *const i8, " + }, + { + "placeholder": { + "arg": 3, + "access": "read" + } + }, + { + "text": ") as u64" + } + ], + "params": { + "a0": { + "type": "*mut u8", + "is_unsafe_pointer": true + }, + "a1": { + "type": "u64" + }, + "a2": { + "type": "*const u8", + "is_unsafe_pointer": true + }, + "a3": { + "type": "*const ::libc::tm", + "is_unsafe_pointer": true + } + }, + "return_type": { + "type": "u64" + } + }, + "f7": { + "body": [ + { + "text": "libc::utimes(" + }, + { + "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": "*const ::libc::timeval", + "is_unsafe_pointer": true + } + }, + "return_type": { + "type": "i32" + } + } +} diff --git a/rules/time/src.c b/rules/time/src.c new file mode 100644 index 00000000..ba669d0c --- /dev/null +++ b/rules/time/src.c @@ -0,0 +1,31 @@ +// Copyright (c) 2022-present INESC-ID. +// Distributed under the MIT license that can be found in the LICENSE file. + +#include +#include + +time_t f1(time_t *t) { return time(t); } + +int f2(clockid_t clk_id, struct timespec *tp) { + return clock_gettime(clk_id, tp); +} + +int f3(struct timeval *tv, struct timezone *tz) { + return gettimeofday(tv, tz); +} + +struct tm *f4(const time_t *timer, struct tm *result) { + return gmtime_r(timer, result); +} + +struct tm *f5(const time_t *timer, struct tm *result) { + return localtime_r(timer, result); +} + +size_t f6(char *s, size_t maxsize, const char *format, const struct tm *tp) { + return strftime(s, maxsize, format, tp); +} + +int f7(const char *file, const struct timeval tvp[2]) { + return utimes(file, tvp); +} diff --git a/rules/time/tgt_unsafe.rs b/rules/time/tgt_unsafe.rs new file mode 100644 index 00000000..d5789ff4 --- /dev/null +++ b/rules/time/tgt_unsafe.rs @@ -0,0 +1,30 @@ +// Copyright (c) 2022-present INESC-ID. +// Distributed under the MIT license that can be found in the LICENSE file. + +unsafe fn f1(a0: *mut ::libc::time_t) -> ::libc::time_t { + libc::time(a0) +} + +unsafe fn f2(a0: ::libc::clockid_t, a1: *mut ::libc::timespec) -> i32 { + libc::clock_gettime(a0, a1) +} + +unsafe fn f3(a0: *mut ::libc::timeval, a1: *mut ::libc::timezone) -> i32 { + libc::gettimeofday(a0, a1 as *mut ::libc::timezone) +} + +unsafe fn f4(a0: *const ::libc::time_t, a1: *mut ::libc::tm) -> *mut ::libc::tm { + libc::gmtime_r(a0, a1) +} + +unsafe fn f5(a0: *const ::libc::time_t, a1: *mut ::libc::tm) -> *mut ::libc::tm { + libc::localtime_r(a0, a1) +} + +unsafe fn f6(a0: *mut u8, a1: u64, a2: *const u8, a3: *const ::libc::tm) -> u64 { + libc::strftime(a0 as *mut i8, a1 as ::libc::size_t, a2 as *const i8, a3) as u64 +} + +unsafe fn f7(a0: *const u8, a1: *const ::libc::timeval) -> i32 { + libc::utimes(a0 as *const i8, a1) +} diff --git a/rules/xattr/ir_unsafe.json b/rules/xattr/ir_unsafe.json new file mode 100644 index 00000000..fccd3b47 --- /dev/null +++ b/rules/xattr/ir_unsafe.json @@ -0,0 +1,77 @@ +{ + "f1": { + "body": [ + { + "text": "libc::fsetxattr(" + }, + { + "placeholder": { + "arg": 0, + "access": "read" + } + }, + { + "text": ", " + }, + { + "placeholder": { + "arg": 1, + "access": "read" + } + }, + { + "text": " as *const i8, " + }, + { + "placeholder": { + "arg": 2, + "access": "read" + } + }, + { + "text": ", " + }, + { + "placeholder": { + "arg": 3, + "access": "read" + } + }, + { + "text": " as ::libc::size_t, " + }, + { + "placeholder": { + "arg": 4, + "access": "read" + } + }, + { + "text": ")" + } + ], + "params": { + "a0": { + "type": "i32" + }, + "a1": { + "type": "*const u8", + "is_unsafe_pointer": true + }, + "a2": { + "type": "*const ::libc::c_void", + "is_unsafe_pointer": true + }, + "a3": { + "type": "u64" + }, + "a4": { + "type": "i32" + } + }, + "return_type": { + "type": "i32" + }, + "target_os": "linux" + } +} diff --git a/rules/xattr/src.c b/rules/xattr/src.c new file mode 100644 index 00000000..67707445 --- /dev/null +++ b/rules/xattr/src.c @@ -0,0 +1,11 @@ +// Copyright (c) 2022-present INESC-ID. +// Distributed under the MIT license that can be found in the LICENSE file. + +#ifdef __linux__ +#include +#include + +int f1(int fd, const char *name, const void *value, size_t size, int flags) { + return fsetxattr(fd, name, value, size, flags); +} +#endif diff --git a/rules/xattr/tgt_unsafe.rs b/rules/xattr/tgt_unsafe.rs new file mode 100644 index 00000000..c628eb17 --- /dev/null +++ b/rules/xattr/tgt_unsafe.rs @@ -0,0 +1,7 @@ +// Copyright (c) 2022-present INESC-ID. +// Distributed under the MIT license that can be found in the LICENSE file. + +#[cfg(target_os = "linux")] +unsafe fn f1(a0: i32, a1: *const u8, a2: *const ::libc::c_void, a3: u64, a4: i32) -> i32 { + libc::fsetxattr(a0, a1 as *const i8, a2, a3 as ::libc::size_t, a4) +} From a4a2b27ab6f5b40fba2796a171065916d7d0d39e Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Thu, 21 May 2026 15:03:41 +0100 Subject: [PATCH 2/5] Add bsearch and qsort tests --- tests/unit/out/unsafe/qsort_bsearch.rs | 61 ++++++++++++++++++++++++++ tests/unit/qsort_bsearch.c | 29 ++++++++++++ 2 files changed, 90 insertions(+) create mode 100644 tests/unit/out/unsafe/qsort_bsearch.rs create mode 100644 tests/unit/qsort_bsearch.c diff --git a/tests/unit/out/unsafe/qsort_bsearch.rs b/tests/unit/out/unsafe/qsort_bsearch.rs new file mode 100644 index 00000000..5cf5437c --- /dev/null +++ b/tests/unit/out/unsafe/qsort_bsearch.rs @@ -0,0 +1,61 @@ +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 cmp_int_0(mut a: *const ::libc::c_void, mut b: *const ::libc::c_void) -> i32 { + let mut x: i32 = (*(a as *const i32)); + let mut y: i32 = (*(b as *const i32)); + return ((((x) > (y)) as i32) - (((x) < (y)) as i32)); +} +pub fn main() { + unsafe { + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut arr: [i32; 8] = [5, 2, 9, 1, 7, 3, 8, 4]; + libc::qsort( + (arr.as_mut_ptr() as *mut i32 as *mut ::libc::c_void), + 8_u64 as ::libc::size_t, + ::std::mem::size_of::() as u64 as ::libc::size_t, + Some(std::mem::transmute::< + *const (), + unsafe extern "C" fn(*const ::libc::c_void, *const ::libc::c_void) -> i32, + >(cmp_int_0 as *const ())), + ); + let mut i: i32 = 0; + 'loop_: while ((((i) < (7)) as i32) != 0) { + assert!(((((arr[(i) as usize]) <= (arr[((i) + (1)) as usize])) as i32) != 0)); + i.prefix_inc(); + } + let mut key: i32 = 7; + let mut hit: *mut i32 = (libc::bsearch( + ((&mut key as *mut i32) as *const i32 as *const ::libc::c_void), + (arr.as_mut_ptr() as *const i32 as *const ::libc::c_void), + 8_u64 as ::libc::size_t, + ::std::mem::size_of::() as u64 as ::libc::size_t, + Some(std::mem::transmute::< + *const (), + unsafe extern "C" fn(*const ::libc::c_void, *const ::libc::c_void) -> i32, + >(cmp_int_0 as *const ())), + ) as *mut i32); + assert!((((!((hit).is_null())) as i32) != 0)); + assert!(((((*hit) == (7)) as i32) != 0)); + let mut miss_key: i32 = 42; + let mut miss: *mut i32 = (libc::bsearch( + ((&mut miss_key as *mut i32) as *const i32 as *const ::libc::c_void), + (arr.as_mut_ptr() as *const i32 as *const ::libc::c_void), + 8_u64 as ::libc::size_t, + ::std::mem::size_of::() as u64 as ::libc::size_t, + Some(std::mem::transmute::< + *const (), + unsafe extern "C" fn(*const ::libc::c_void, *const ::libc::c_void) -> i32, + >(cmp_int_0 as *const ())), + ) as *mut i32); + assert!(((((miss).is_null()) as i32) != 0)); + return 0; +} diff --git a/tests/unit/qsort_bsearch.c b/tests/unit/qsort_bsearch.c new file mode 100644 index 00000000..4b394120 --- /dev/null +++ b/tests/unit/qsort_bsearch.c @@ -0,0 +1,29 @@ +// no-compile: refcount +#include +#include +#include + +static int cmp_int(const void *a, const void *b) { + int x = *(const int *)a; + int y = *(const int *)b; + return (x > y) - (x < y); +} + +int main(void) { + int arr[8] = {5, 2, 9, 1, 7, 3, 8, 4}; + qsort(arr, 8, sizeof(int), cmp_int); + for (int i = 0; i < 7; ++i) { + assert(arr[i] <= arr[i + 1]); + } + + int key = 7; + int *hit = (int *)bsearch(&key, arr, 8, sizeof(int), cmp_int); + assert(hit != NULL); + assert(*hit == 7); + + int miss_key = 42; + int *miss = (int *)bsearch(&miss_key, arr, 8, sizeof(int), cmp_int); + assert(miss == NULL); + + return 0; +} From 9f32fb9f2d1e9d5771b9ae6173a56a05aa760148 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Thu, 21 May 2026 15:07:59 +0100 Subject: [PATCH 3/5] Update modules --- rules/src/modules.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/rules/src/modules.rs b/rules/src/modules.rs index bd539543..3431518a 100644 --- a/rules/src/modules.rs +++ b/rules/src/modules.rs @@ -68,12 +68,8 @@ pub mod pair_tgt_refcount; pub mod pair_tgt_unsafe; #[path = r#"../poll/tgt_unsafe.rs"#] pub mod poll_tgt_unsafe; -#[path = r#"../pwd/tgt_unsafe.rs"#] -pub mod pwd_tgt_unsafe; #[path = r#"../select/tgt_unsafe.rs"#] pub mod select_tgt_unsafe; -#[path = r#"../signal/tgt_unsafe.rs"#] -pub mod signal_tgt_unsafe; #[path = r#"../socket/tgt_unsafe.rs"#] pub mod socket_tgt_unsafe; #[path = r#"../stat/tgt_unsafe.rs"#] @@ -88,6 +84,8 @@ pub mod string_tgt_refcount; pub mod string_tgt_unsafe; #[path = r#"../termios/tgt_unsafe.rs"#] pub mod termios_tgt_unsafe; +#[path = r#"../time/tgt_unsafe.rs"#] +pub mod time_tgt_unsafe; #[path = r#"../unique_ptr/tgt_refcount.rs"#] pub mod unique_ptr_tgt_refcount; #[path = r#"../unique_ptr/tgt_unsafe.rs"#] From 55d63a05f7a21fa6061562886629564788c02287 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Thu, 21 May 2026 15:26:51 +0100 Subject: [PATCH 4/5] Delete unportable functions --- rules/cstring/ir_unsafe.json | 57 ------------------------------------ rules/cstring/src.c | 4 --- rules/cstring/tgt_unsafe.rs | 5 ---- rules/time/ir_unsafe.json | 38 ------------------------ rules/time/src.c | 4 --- rules/time/tgt_unsafe.rs | 4 --- 6 files changed, 112 deletions(-) diff --git a/rules/cstring/ir_unsafe.json b/rules/cstring/ir_unsafe.json index fbd18617..c39d8459 100644 --- a/rules/cstring/ir_unsafe.json +++ b/rules/cstring/ir_unsafe.json @@ -882,63 +882,6 @@ "type": "i32" } }, - "f28": { - "body": [ - { - "text": "libc::strerror_r(" - }, - { - "placeholder": { - "arg": 0, - "access": "read" - } - }, - { - "text": ", " - }, - { - "placeholder": { - "arg": 1, - "access": "read" - } - }, - { - "text": " as *mut i8, " - }, - { - "placeholder": { - "arg": 2, - "access": "read" - } - }, - { - "text": " as ::libc::size_t);\n " - }, - { - "placeholder": { - "arg": 1, - "access": "read" - } - } - ], - "multi_statement": true, - "params": { - "a0": { - "type": "i32" - }, - "a1": { - "type": "*mut u8", - "is_unsafe_pointer": true - }, - "a2": { - "type": "u64" - } - }, - "return_type": { - "type": "*mut u8", - "is_unsafe_pointer": true - } - }, "f3": { "body": [ { diff --git a/rules/cstring/src.c b/rules/cstring/src.c index 7f82340c..be329a8e 100644 --- a/rules/cstring/src.c +++ b/rules/cstring/src.c @@ -40,7 +40,3 @@ void *f24(const void *a0, int a1, size_t a2) { return memrchr(a0, a1, a2); } #endif int f27(const char *a0, const char *a1) { return strcasecmp(a0, a1); } - -char* f28(int errnum, char *buf, size_t buflen) { - return strerror_r(errnum, buf, buflen); -} diff --git a/rules/cstring/tgt_unsafe.rs b/rules/cstring/tgt_unsafe.rs index 5a54ecaa..9ab40a81 100644 --- a/rules/cstring/tgt_unsafe.rs +++ b/rules/cstring/tgt_unsafe.rs @@ -130,8 +130,3 @@ unsafe fn f26(a0: *mut u8, a1: i32, a2: usize) -> *mut ::libc::c_void { unsafe fn f27(a0: *const u8, a1: *const u8) -> i32 { libc::strcasecmp(a0 as *const i8, a1 as *const i8) } - -unsafe fn f28(a0: i32, a1: *mut u8, a2: u64) -> *mut u8 { - libc::strerror_r(a0, a1 as *mut i8, a2 as ::libc::size_t); - a1 -} diff --git a/rules/time/ir_unsafe.json b/rules/time/ir_unsafe.json index 2229c587..207e6902 100644 --- a/rules/time/ir_unsafe.json +++ b/rules/time/ir_unsafe.json @@ -61,44 +61,6 @@ "type": "i32" } }, - "f3": { - "body": [ - { - "text": "libc::gettimeofday(" - }, - { - "placeholder": { - "arg": 0, - "access": "read" - } - }, - { - "text": ", " - }, - { - "placeholder": { - "arg": 1, - "access": "read" - } - }, - { - "text": " as *mut ::libc::timezone)" - } - ], - "params": { - "a0": { - "type": "*mut ::libc::timeval", - "is_unsafe_pointer": true - }, - "a1": { - "type": "*mut ::libc::timezone", - "is_unsafe_pointer": true - } - }, - "return_type": { - "type": "i32" - } - }, "f4": { "body": [ { diff --git a/rules/time/src.c b/rules/time/src.c index ba669d0c..c01540b1 100644 --- a/rules/time/src.c +++ b/rules/time/src.c @@ -10,10 +10,6 @@ int f2(clockid_t clk_id, struct timespec *tp) { return clock_gettime(clk_id, tp); } -int f3(struct timeval *tv, struct timezone *tz) { - return gettimeofday(tv, tz); -} - struct tm *f4(const time_t *timer, struct tm *result) { return gmtime_r(timer, result); } diff --git a/rules/time/tgt_unsafe.rs b/rules/time/tgt_unsafe.rs index d5789ff4..571b2482 100644 --- a/rules/time/tgt_unsafe.rs +++ b/rules/time/tgt_unsafe.rs @@ -9,10 +9,6 @@ unsafe fn f2(a0: ::libc::clockid_t, a1: *mut ::libc::timespec) -> i32 { libc::clock_gettime(a0, a1) } -unsafe fn f3(a0: *mut ::libc::timeval, a1: *mut ::libc::timezone) -> i32 { - libc::gettimeofday(a0, a1 as *mut ::libc::timezone) -} - unsafe fn f4(a0: *const ::libc::time_t, a1: *mut ::libc::tm) -> *mut ::libc::tm { libc::gmtime_r(a0, a1) } From 6c692581fbf009fc9e0f1885cf41b1cd86ab12fb Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Fri, 22 May 2026 08:14:37 +0100 Subject: [PATCH 5/5] Update modules --- rules/src/modules.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/rules/src/modules.rs b/rules/src/modules.rs index 3431518a..0da0327e 100644 --- a/rules/src/modules.rs +++ b/rules/src/modules.rs @@ -68,8 +68,12 @@ pub mod pair_tgt_refcount; pub mod pair_tgt_unsafe; #[path = r#"../poll/tgt_unsafe.rs"#] pub mod poll_tgt_unsafe; +#[path = r#"../pwd/tgt_unsafe.rs"#] +pub mod pwd_tgt_unsafe; #[path = r#"../select/tgt_unsafe.rs"#] pub mod select_tgt_unsafe; +#[path = r#"../signal/tgt_unsafe.rs"#] +pub mod signal_tgt_unsafe; #[path = r#"../socket/tgt_unsafe.rs"#] pub mod socket_tgt_unsafe; #[path = r#"../stat/tgt_unsafe.rs"#]