diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index 780bd7d8..957ba670 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -2543,6 +2543,16 @@ bool Converter::VisitMemberExpr(clang::MemberExpr *expr) { return false; } + // char* fields in libc structs are *mut i8. We represent char* as *mut u8. Do + // the i8 -> u8 conversion here. + if (IsCharPointerFieldFromLibc(member)) { + StrCat(std::format("({} as {})", str, + member->getType()->getPointeeType().isConstQualified() + ? "*const u8" + : "*mut u8")); + return false; + } + StrCat(str); return false; } diff --git a/cpp2rust/converter/converter_lib.cpp b/cpp2rust/converter/converter_lib.cpp index 051aed2d..6fd29722 100644 --- a/cpp2rust/converter/converter_lib.cpp +++ b/cpp2rust/converter/converter_lib.cpp @@ -129,6 +129,16 @@ bool IsInMainFile(const clang::Decl *decl) { return src_mgr.isInMainFile(src_mgr.getExpansionLoc(loc)); } +bool IsCharPointerFieldFromLibc(const clang::ValueDecl *decl) { + auto field = clang::dyn_cast(decl); + if (!field || !field->getType()->isPointerType() || + !field->getType()->getPointeeType()->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 c208ea1c..62089604 100644 --- a/cpp2rust/converter/converter_lib.h +++ b/cpp2rust/converter/converter_lib.h @@ -39,6 +39,8 @@ bool IsComparisonWithNullOp(const clang::BinaryOperator *expr); bool IsInMainFile(const clang::Decl *decl); +bool IsCharPointerFieldFromLibc(const clang::ValueDecl *decl); + bool IsUserDefinedDecl(const clang::Decl *decl); bool RefersToUserDefinedDecl(const clang::Expr *expr); diff --git a/tests/unit/libc_char_ptr_field.c b/tests/unit/libc_char_ptr_field.c new file mode 100644 index 00000000..8d359659 --- /dev/null +++ b/tests/unit/libc_char_ptr_field.c @@ -0,0 +1,12 @@ +// no-compile: refcount +#include +#include + +int main(void) { + struct passwd *pw = getpwuid(geteuid()); + if (!pw) { + return 0; + } + char *home = pw->pw_dir; + return home == 0; +} diff --git a/tests/unit/out/unsafe/libc_char_ptr_field.rs b/tests/unit/out/unsafe/libc_char_ptr_field.rs new file mode 100644 index 00000000..1e0df56e --- /dev/null +++ b/tests/unit/out/unsafe/libc_char_ptr_field.rs @@ -0,0 +1,21 @@ +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 fn main() { + unsafe { + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut pw: *mut passwd = libc::getpwuid(libc::geteuid()); + if !!(pw).is_null() { + return 0; + } + let mut home: *mut u8 = ((*pw).pw_dir as *mut u8); + return (((home).is_null()) as i32); +}