diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index b4016158..7a7c36b4 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -1942,9 +1942,18 @@ bool Converter::VisitImplicitCastExpr(clang::ImplicitCastExpr *expr) { Convert(sub_expr); break; } - Convert(sub_expr); bool dest_pointee_const = expr->getType()->getPointeeType().isConstQualified(); + if (const auto *member = + clang::dyn_cast(sub_expr->IgnoreParenImpCasts()); + member && IsCharArrayFieldFromLibc(member->getMemberDecl())) { + PushParen paren(*this); + Convert(sub_expr); + StrCat(dest_pointee_const ? ".as_ptr()" : ".as_mut_ptr()"); + StrCat(keyword::kAs, dest_pointee_const ? "*const u8" : "*mut u8"); + break; + } + Convert(sub_expr); if (clang::isa(sub_expr) || clang::isa(sub_expr)) { StrCat(".as_ptr()"); diff --git a/cpp2rust/converter/converter_lib.cpp b/cpp2rust/converter/converter_lib.cpp index 6b85a6ff..474eaecd 100644 --- a/cpp2rust/converter/converter_lib.cpp +++ b/cpp2rust/converter/converter_lib.cpp @@ -139,6 +139,16 @@ bool IsCharPointerFieldFromLibc(const clang::ValueDecl *decl) { field->getParent()->getLocation()); } +bool IsCharArrayFieldFromLibc(const clang::ValueDecl *decl) { + auto field = clang::dyn_cast(decl); + if (!field || !field->getType()->isArrayType() || + !field->getType()->getArrayElementTypeNoTypeQual()->isCharType()) { + return false; + } + return field->getASTContext().getSourceManager().isInSystemHeader( + field->getParent()->getLocation()); +} + bool IsUserDefinedDecl(const clang::Decl *decl) { const auto &ctx = decl->getASTContext(); const auto &src_mgr = ctx.getSourceManager(); diff --git a/cpp2rust/converter/converter_lib.h b/cpp2rust/converter/converter_lib.h index bcd6e50c..34c94da4 100644 --- a/cpp2rust/converter/converter_lib.h +++ b/cpp2rust/converter/converter_lib.h @@ -41,6 +41,8 @@ bool IsInMainFile(const clang::Decl *decl); bool IsCharPointerFieldFromLibc(const clang::ValueDecl *decl); +bool IsCharArrayFieldFromLibc(const clang::ValueDecl *decl); + bool IsUserDefinedDecl(const clang::Decl *decl); bool RefersToUserDefinedDecl(const clang::Expr *expr); diff --git a/rules/dirent/src.cpp b/rules/dirent/src.cpp new file mode 100644 index 00000000..9f76ffba --- /dev/null +++ b/rules/dirent/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 + +using t1 = DIR *; + +DIR *f1(const char *name) { return opendir(name); } + +struct dirent *f2(DIR *dirp) { return readdir(dirp); } + +int f3(DIR *dirp) { return closedir(dirp); } diff --git a/rules/dirent/tgt_unsafe.rs b/rules/dirent/tgt_unsafe.rs new file mode 100644 index 00000000..de16e9e0 --- /dev/null +++ b/rules/dirent/tgt_unsafe.rs @@ -0,0 +1,18 @@ +// Copyright (c) 2022-present INESC-ID. +// Distributed under the MIT license that can be found in the LICENSE file. + +fn t1() -> *mut ::libc::DIR { + std::ptr::null_mut() +} + +unsafe fn f1(a0: *const u8) -> *mut ::libc::DIR { + libc::opendir(a0 as *const i8) +} + +unsafe fn f2(a0: *mut ::libc::DIR) -> *mut ::libc::dirent { + libc::readdir(a0) +} + +unsafe fn f3(a0: *mut ::libc::DIR) -> i32 { + libc::closedir(a0) +} diff --git a/rules/fnmatch/src.cpp b/rules/fnmatch/src.cpp new file mode 100644 index 00000000..7700031c --- /dev/null +++ b/rules/fnmatch/src.cpp @@ -0,0 +1,8 @@ +// Copyright (c) 2022-present INESC-ID. +// Distributed under the MIT license that can be found in the LICENSE file. + +#include + +int f1(const char *pattern, const char *string, int flags) { + return fnmatch(pattern, string, flags); +} diff --git a/rules/fnmatch/tgt_unsafe.rs b/rules/fnmatch/tgt_unsafe.rs new file mode 100644 index 00000000..9be3d0cd --- /dev/null +++ b/rules/fnmatch/tgt_unsafe.rs @@ -0,0 +1,6 @@ +// 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: *const u8, a2: i32) -> i32 { + libc::fnmatch(a0 as *const i8, a1 as *const i8, a2) +} diff --git a/rules/ifaddrs/src.cpp b/rules/ifaddrs/src.cpp new file mode 100644 index 00000000..8e699671 --- /dev/null +++ b/rules/ifaddrs/src.cpp @@ -0,0 +1,10 @@ +#include +#include + +int f1(struct ifaddrs **ifap) { + return getifaddrs(ifap); +} + +void f2(struct ifaddrs *ifa) { + return freeifaddrs(ifa); +} diff --git a/rules/ifaddrs/tgt_unsafe.rs b/rules/ifaddrs/tgt_unsafe.rs new file mode 100644 index 00000000..6ab1ad75 --- /dev/null +++ b/rules/ifaddrs/tgt_unsafe.rs @@ -0,0 +1,7 @@ +unsafe fn f1(a0: *mut *mut libc::ifaddrs) -> i32 { + libc::getifaddrs(a0) +} + +unsafe fn f2(a0: *mut libc::ifaddrs) { + libc::freeifaddrs(a0) +} diff --git a/rules/net_if/src.cpp b/rules/net_if/src.cpp new file mode 100644 index 00000000..ed86058d --- /dev/null +++ b/rules/net_if/src.cpp @@ -0,0 +1,6 @@ +// Copyright (c) 2022-present INESC-ID. +// Distributed under the MIT license that can be found in the LICENSE file. + +#include + +unsigned int f1(const char *ifname) { return if_nametoindex(ifname); } diff --git a/rules/net_if/tgt_unsafe.rs b/rules/net_if/tgt_unsafe.rs new file mode 100644 index 00000000..f87fdccb --- /dev/null +++ b/rules/net_if/tgt_unsafe.rs @@ -0,0 +1,6 @@ +// 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) -> u32 { + libc::if_nametoindex(a0 as *const i8) +} diff --git a/rules/pwd/src.cpp b/rules/pwd/src.cpp index 5836bac9..e398ff71 100644 --- a/rules/pwd/src.cpp +++ b/rules/pwd/src.cpp @@ -4,3 +4,8 @@ #include struct passwd *f1(uid_t uid) { return getpwuid(uid); } + +int f2(uid_t uid, struct passwd *pwd, char *buf, size_t buflen, + struct passwd **result) { + return getpwuid_r(uid, pwd, buf, buflen, result); +} diff --git a/rules/pwd/tgt_unsafe.rs b/rules/pwd/tgt_unsafe.rs index 275499a2..9aac30ba 100644 --- a/rules/pwd/tgt_unsafe.rs +++ b/rules/pwd/tgt_unsafe.rs @@ -4,3 +4,13 @@ unsafe fn f1(a0: u32) -> *mut ::libc::passwd { libc::getpwuid(a0) } + +unsafe fn f2( + a0: u32, + a1: *mut ::libc::passwd, + a2: *mut u8, + a3: u64, + a4: *mut *mut ::libc::passwd, +) -> i32 { + libc::getpwuid_r(a0, a1, a2 as *mut i8, a3 as usize, a4) +} diff --git a/rules/socket/src.c b/rules/socket/src.c index 9be2c1c8..25ee0d0a 100644 --- a/rules/socket/src.c +++ b/rules/socket/src.c @@ -65,3 +65,21 @@ int f15(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags) { return accept4(sockfd, addr, addrlen, flags); } #endif + +int f16(int sockfd, const struct sockaddr *addr, socklen_t addrlen) { + return bind(sockfd, addr, addrlen); +} + +int f17(int sockfd, int backlog) { + return listen(sockfd, backlog); +} + +ssize_t f18(int sockfd, void *buf, size_t len, int flags, + struct sockaddr *src_addr, socklen_t *addrlen) { + return recvfrom(sockfd, buf, len, flags, src_addr, addrlen); +} + +ssize_t f19(int sockfd, const void *buf, size_t len, int flags, + const struct sockaddr *dest_addr, socklen_t addrlen) { + return sendto(sockfd, buf, len, flags, dest_addr, addrlen); +} diff --git a/rules/socket/tgt_unsafe.rs b/rules/socket/tgt_unsafe.rs index 05bc972e..9a632f2f 100644 --- a/rules/socket/tgt_unsafe.rs +++ b/rules/socket/tgt_unsafe.rs @@ -60,3 +60,33 @@ unsafe fn f14(a0: i32, a1: *mut ::libc::sockaddr, a2: *mut u32) -> i32 { unsafe fn f15(a0: i32, a1: *mut ::libc::sockaddr, a2: *mut u32, a3: i32) -> i32 { libc::accept4(a0, a1, a2, a3) } + +unsafe fn f16(a0: i32, a1: *const ::libc::sockaddr, a2: u32) -> i32 { + libc::bind(a0, a1, a2) +} + +unsafe fn f17(a0: i32, a1: i32) -> i32 { + libc::listen(a0, a1) +} + +unsafe fn f18( + a0: i32, + a1: *mut ::libc::c_void, + a2: u64, + a3: i32, + a4: *mut ::libc::sockaddr, + a5: *mut u32, +) -> i64 { + libc::recvfrom(a0, a1, a2 as usize, a3, a4, a5) as i64 +} + +unsafe fn f19( + a0: i32, + a1: *const ::libc::c_void, + a2: u64, + a3: i32, + a4: *const ::libc::sockaddr, + a5: u32, +) -> i64 { + libc::sendto(a0, a1, a2 as usize, a3, a4, a5) as i64 +} diff --git a/rules/src/modules.rs b/rules/src/modules.rs index 2b5d751c..efd63874 100644 --- a/rules/src/modules.rs +++ b/rules/src/modules.rs @@ -36,12 +36,18 @@ pub mod cstring_tgt_unsafe; pub mod deque_tgt_refcount; #[path = r#"../deque/tgt_unsafe.rs"#] pub mod deque_tgt_unsafe; +#[path = r#"../dirent/tgt_unsafe.rs"#] +pub mod dirent_tgt_unsafe; #[path = r#"../errno/tgt_unsafe.rs"#] pub mod errno_tgt_unsafe; +#[path = r#"../fnmatch/tgt_unsafe.rs"#] +pub mod fnmatch_tgt_unsafe; #[path = r#"../fstream/tgt_refcount.rs"#] pub mod fstream_tgt_refcount; #[path = r#"../fstream/tgt_unsafe.rs"#] pub mod fstream_tgt_unsafe; +#[path = r#"../ifaddrs/tgt_unsafe.rs"#] +pub mod ifaddrs_tgt_unsafe; #[path = r#"../initializer_list/tgt_unsafe.rs"#] pub mod initializer_list_tgt_unsafe; #[path = r#"../iomanip/tgt_unsafe.rs"#] @@ -62,6 +68,8 @@ pub mod map_tgt_refcount; pub mod map_tgt_unsafe; #[path = r#"../math/tgt_unsafe.rs"#] pub mod math_tgt_unsafe; +#[path = r#"../net_if/tgt_unsafe.rs"#] +pub mod net_if_tgt_unsafe; #[path = r#"../netdb/tgt_unsafe.rs"#] pub mod netdb_tgt_unsafe; #[path = r#"../pair/tgt_refcount.rs"#] diff --git a/rules/stdio/src.cpp b/rules/stdio/src.cpp index b4a62ea4..c172b5fd 100644 --- a/rules/stdio/src.cpp +++ b/rules/stdio/src.cpp @@ -56,3 +56,9 @@ int f19(FILE *stream, off_t offset, int whence) { } FILE *f20(int fd, const char *mode) { return fdopen(fd, mode); } + +int f22(const char *a0, const char *a1) { + return rename(a0, a1); +} + +int f23(FILE *stream) { return getc(stream); } diff --git a/rules/stdio/tgt_unsafe.rs b/rules/stdio/tgt_unsafe.rs index 91216fef..72aacd08 100644 --- a/rules/stdio/tgt_unsafe.rs +++ b/rules/stdio/tgt_unsafe.rs @@ -84,3 +84,11 @@ unsafe fn f19(a0: *mut ::libc::FILE, a1: i64, a2: i32) -> i32 { unsafe fn f20(a0: i32, a1: *const u8) -> *mut ::libc::FILE { libc::fdopen(a0, a1 as *const i8) } + +unsafe fn f22(a0: *const i8, a1: *const i8) -> i32 { + libc::rename(a0 as *const i8, a1 as *const i8) +} + +unsafe fn f23(a0: *mut ::libc::FILE) -> i32 { + libc::fgetc(a0) +} diff --git a/tests/unit/libc_char_ptr_field.c b/tests/unit/libc_char_ptr_field.c index 8d359659..dd37e238 100644 --- a/tests/unit/libc_char_ptr_field.c +++ b/tests/unit/libc_char_ptr_field.c @@ -1,4 +1,5 @@ // no-compile: refcount +#include #include #include @@ -8,5 +9,11 @@ int main(void) { return 0; } char *home = pw->pw_dir; - return home == 0; + + struct dirent *d = readdir(opendir("/tmp")); + // d_name is a char array which gets translated as i8. We model chars as u8 in + // Rust. + char *dname = d->d_name; + + return 0; } diff --git a/tests/unit/out/unsafe/libc_char_ptr_field.rs b/tests/unit/out/unsafe/libc_char_ptr_field.rs index 1e0df56e..9018c046 100644 --- a/tests/unit/out/unsafe/libc_char_ptr_field.rs +++ b/tests/unit/out/unsafe/libc_char_ptr_field.rs @@ -17,5 +17,9 @@ unsafe fn main_0() -> i32 { return 0; } let mut home: *mut u8 = ((*pw).pw_dir as *mut u8); - return (((home).is_null()) as i32); + let mut d: *mut dirent = libc::readdir(libc::opendir( + (b"/tmp\0".as_ptr().cast_mut()).cast_const() as *const i8, + )); + let mut dname: *mut u8 = ((*d).d_name.as_mut_ptr() as *mut u8); + return 0; }