diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index 359210aa..c8fc5947 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -1430,7 +1430,7 @@ void Converter::EmitFnPtrCall(clang::Expr *callee) { void Converter::ConvertFunctionToFunctionPointer( const clang::FunctionDecl *fn_decl) { - StrCat(std::format("Some({})", GetNamedDeclAsString(fn_decl))); + StrCat(std::format("Some({})", Mapper::MapFunctionName(fn_decl))); } void Converter::ConvertGenericCallExpr(clang::CallExpr *expr) { @@ -2070,7 +2070,7 @@ std::string Converter::ConvertDeclRefExpr(clang::DeclRefExpr *expr) { } auto *decl = expr->getDecl(); - if (Mapper::Contains(expr)) { + if (ShouldReplaceWithMappedBody(expr)) { return GetMappedAsString(expr); } else if (auto *function = decl->getAsFunction()) { if (auto method = clang::dyn_cast(function)) { @@ -3472,6 +3472,13 @@ bool Converter::isCallee() const { return !curr_expr_kind_.empty() && curr_expr_kind_.back() == ExprKind::Callee; } +bool Converter::ShouldReplaceWithMappedBody(clang::DeclRefExpr *expr) const { + if (clang::isa(expr->getDecl()) && isAddrOf()) { + return false; + } + return Mapper::Contains(expr); +} + void Converter::SetFresh() { switch (computed_expr_type_) { case ComputedExprType::Value: diff --git a/cpp2rust/converter/converter.h b/cpp2rust/converter/converter.h index 74e8e750..78b54d55 100644 --- a/cpp2rust/converter/converter.h +++ b/cpp2rust/converter/converter.h @@ -459,6 +459,8 @@ class Converter : public clang::RecursiveASTVisitor { virtual bool RecordDerivesDefault(const clang::RecordDecl *decl); + bool ShouldReplaceWithMappedBody(clang::DeclRefExpr *expr) const; + std::string *rs_code_; clang::ASTContext &ctx_; clang::FunctionDecl *curr_function_ = nullptr; diff --git a/cpp2rust/converter/converter_lib.cpp b/cpp2rust/converter/converter_lib.cpp index d493ad74..a7f12c8d 100644 --- a/cpp2rust/converter/converter_lib.cpp +++ b/cpp2rust/converter/converter_lib.cpp @@ -8,7 +8,9 @@ #include #include +#include #include +#include #include #include @@ -660,4 +662,22 @@ clang::Expr *CreateConversionToBool(clang::Expr *expr, clang::ASTContext &ctx) { /*BasePath=*/nullptr, clang::VK_PRValue, clang::FPOptionsOverride()); } +static std::string_view Trim(std::string_view s) { + auto is_space = [](unsigned char c) { return std::isspace(c); }; + auto b = std::find_if_not(s.begin(), s.end(), is_space); + auto e = std::find_if_not(s.rbegin(), s.rend(), is_space).base(); + return {b, e}; +} + +void Unwrap(std::string &s, std::string_view prefix, std::string_view suffix) { + auto trimmed = Trim(s); + if (trimmed.starts_with(prefix) && trimmed.ends_with(suffix)) { + assert(trimmed.size() >= prefix.size() + suffix.size() && + "prefix and suffix overlap in s"); + trimmed.remove_prefix(prefix.size()); + trimmed.remove_suffix(suffix.size()); + s = std::string(trimmed); + } +} + } // namespace cpp2rust diff --git a/cpp2rust/converter/converter_lib.h b/cpp2rust/converter/converter_lib.h index 36776336..a5c8d692 100644 --- a/cpp2rust/converter/converter_lib.h +++ b/cpp2rust/converter/converter_lib.h @@ -12,6 +12,7 @@ #include #include #include +#include #include namespace cpp2rust { @@ -154,4 +155,6 @@ bool ContainsVAArgExpr(const clang::Stmt *stmt); clang::Expr *CreateConversionToBool(clang::Expr *expr, clang::ASTContext &ctx); +void Unwrap(std::string &s, std::string_view prefix, std::string_view suffix); + } // namespace cpp2rust diff --git a/cpp2rust/converter/mapper.cpp b/cpp2rust/converter/mapper.cpp index f3a4af9a..fe36fc16 100644 --- a/cpp2rust/converter/mapper.cpp +++ b/cpp2rust/converter/mapper.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -581,6 +582,15 @@ const TranslationRule::ExprTgt *GetExprTgt(const clang::Expr *expr) { return nullptr; } +std::string MapFunctionName(const clang::FunctionDecl *decl) { + assert(decl); + if (exprs_.contains(ToString(decl))) { + return std::format("libcc2rs::{}_{}", decl->getNameAsString(), + model_ == Model::kRefCount ? "refcount" : "unsafe"); + } + return GetNamedDeclAsString(decl->getCanonicalDecl()); +} + std::string InstantiateTemplate(const clang::Expr *expr, const std::string &text) { auto it = search(expr); diff --git a/cpp2rust/converter/mapper.h b/cpp2rust/converter/mapper.h index f2b706ab..19adf3cb 100644 --- a/cpp2rust/converter/mapper.h +++ b/cpp2rust/converter/mapper.h @@ -31,6 +31,7 @@ bool Contains(const clang::Expr *expr); std::string Map(clang::QualType qual_type); const TranslationRule::ExprTgt *GetExprTgt(const clang::Expr *expr); +std::string MapFunctionName(const clang::FunctionDecl *decl); std::string InstantiateTemplate(const clang::Expr *expr, const std::string &text); bool ReturnsPointer(const clang::Expr *expr); diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index 97c3d84f..460d8479 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -195,7 +195,7 @@ std::string ConverterRefCount::BuildFnAdapter( closure += "{ "; // Build adapter body: src_fn(convert(a0), convert(a1), ...) - closure += GetNamedDeclAsString(src_fn) + "("; + closure += Mapper::MapFunctionName(src_fn) + '('; for (unsigned i = 0; i < src_proto->getNumParams(); ++i) { auto src_pty = src_proto->getParamType(i); auto tgt_pty = target_proto->getParamType(i); @@ -204,12 +204,12 @@ std::string ConverterRefCount::BuildFnAdapter( } else if (src_pty->isPointerType() && tgt_pty->isPointerType()) { if (tgt_pty->isVoidPointerType()) { closure += std::format("a{}.cast::<{}>().unwrap()", i, - ToString(src_pty->getPointeeType())); + ConvertPointeeType(src_pty)); } else if (src_pty->isVoidPointerType()) { closure += std::format("a{}.to_any()", i); } else if (tgt_pty->getPointeeType()->isCharType()) { closure += std::format("a{}.reinterpret_cast::<{}>()", i, - ToString(src_pty->getPointeeType())); + ConvertPointeeType(src_pty)); } else if (src_pty->getPointeeType()->isCharType()) { closure += std::format("a{}.reinterpret_cast::()", i); } @@ -625,7 +625,7 @@ bool ConverterRefCount::VisitDeclRefExpr(clang::DeclRefExpr *expr) { } } - if (Mapper::Contains(expr)) { + if (ShouldReplaceWithMappedBody(expr)) { StrCat(GetMappedAsString(expr)); return false; } @@ -1037,7 +1037,7 @@ void ConverterRefCount::ConvertFunctionToFunctionPointer( StrCat(std::format("FnPtr::<{}>::new({})", ConvertFunctionPointerType( fn_decl->getType()->getAs()), - GetNamedDeclAsString(fn_decl))); + Mapper::MapFunctionName(fn_decl))); } void ConverterRefCount::ConvertEqualsNullPtr(clang::Expr *expr) { @@ -2155,4 +2155,18 @@ std::string ConverterRefCount::ConvertMappedMethodCall( return std::format("{}.with_mut(|__v: {}| __v{})", ptr, param_type, body); } +std::string ConverterRefCount::ConvertPointeeType(clang::QualType ptr_type) { + if (ptr_type->getPointeeType()->isIntegerType()) { + return ToString(ptr_type->getPointeeType()); + } + + // Pointee of a pointer to incomplete type is an incomplete type that does + // not have a translation rule. Hence ToString(ptr_type->getPointeeType()) is + // not enough + assert(ptr_type->isPointerType()); + auto str = ToString(ptr_type); + Unwrap(str, "Ptr<", ">"); + return str; +} + } // namespace cpp2rust diff --git a/cpp2rust/converter/models/converter_refcount.h b/cpp2rust/converter/models/converter_refcount.h index 26ba88a3..cfb22aa8 100644 --- a/cpp2rust/converter/models/converter_refcount.h +++ b/cpp2rust/converter/models/converter_refcount.h @@ -204,6 +204,7 @@ class ConverterRefCount final : public Converter { std::string ConvertFreshPointer(clang::Expr *expr) override; std::string ConvertPtrType(clang::QualType type); + std::string ConvertPointeeType(clang::QualType ptr_type); /// The kind of conversion that should be performed. enum class ConversionKind : uint8_t { diff --git a/libcc2rs/src/io.rs b/libcc2rs/src/io.rs index 664b3d86..e1f77112 100644 --- a/libcc2rs/src/io.rs +++ b/libcc2rs/src/io.rs @@ -1,7 +1,7 @@ // Copyright (c) 2022-present INESC-ID. // Distributed under the MIT license that can be found in the LICENSE file. -use crate::{AsPointer, Ptr, Value}; +use crate::{AnyPtr, AsPointer, Ptr, Value}; use std::cell::{RefCell, UnsafeCell}; use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; use std::rc::Rc; @@ -58,3 +58,83 @@ pub unsafe fn cout_unsafe() -> *mut std::fs::File { pub unsafe fn cerr_unsafe() -> *mut std::fs::File { UNSAFE_STDERR.with(UnsafeCell::get) } + +pub fn fread_refcount(a0: AnyPtr, a1: u64, a2: u64, a3: Ptr<::std::fs::File>) -> u64 { + let total = a1.saturating_mul(a2) as usize; + let mut dst = a0 + .cast::() + .expect("fread: only supporting u8 pointers") + .clone(); + + let f = (*a3.upgrade().deref()) + .try_clone() + .expect("try_clone failed"); + let mut reader = std::io::BufReader::with_capacity(64 * 1024, f); + + let mut read_bytes: usize = 0; + let mut buffer: [u8; 8192] = [0; 8192]; + + while read_bytes < total { + let remaining = total - read_bytes; + let to_read = std::cmp::min(buffer.len(), remaining); + + let n = match std::io::Read::read(&mut reader, &mut buffer[..to_read]) { + Ok(0) => break, + Ok(n) => n, + Err(ref e) if e.kind() == std::io::ErrorKind::Interrupted => continue, + Err(e) => panic!("Unhandled error in fread: {e}"), + }; + + for &byte in &buffer[..n] { + dst.write(byte); + dst = dst.offset(1); + } + + read_bytes += n; + } + + (read_bytes / a1 as usize) as u64 +} + +/// # Safety +/// +/// `a0` must point to a writable buffer of at least `a1 * a2` bytes, and `a3` +/// must point to a valid, open `std::fs::File`. +pub unsafe fn fread_unsafe( + a0: *mut ::std::ffi::c_void, + a1: u64, + a2: u64, + a3: *mut ::std::fs::File, +) -> u64 { + let total = a1.saturating_mul(a2) as usize; + let mut dst = a0 as *mut u8; + + let f = unsafe { (*a3).try_clone().expect("try_clone failed") }; + let mut reader = std::io::BufReader::with_capacity(64 * 1024, f); + + let mut read_bytes: usize = 0; + let mut buffer: [u8; 8192] = [0; 8192]; + + while read_bytes < total { + let remaining = total - read_bytes; + let to_read = std::cmp::min(buffer.len(), remaining); + + let n = match std::io::Read::read(&mut reader, &mut buffer[..to_read]) { + Ok(0) => break, + Ok(n) => n, + Err(ref e) if e.kind() == std::io::ErrorKind::Interrupted => continue, + Err(e) => panic!("Unhandled error in fread: {e}"), + }; + + for &byte in &buffer[..n] { + unsafe { + *dst = byte; + dst = dst.offset(1); + } + } + + read_bytes += n; + } + + (read_bytes / a1 as usize) as u64 +} diff --git a/rules/stdio/ir_refcount.json b/rules/stdio/ir_refcount.json index 4a588a5e..736057e2 100644 --- a/rules/stdio/ir_refcount.json +++ b/rules/stdio/ir_refcount.json @@ -420,217 +420,56 @@ "f5": { "body": [ { - "text": "let total = " - }, - { - "method_call": { - "receiver": [ - { - "placeholder": { - "arg": "a1", - "access": "read" - } - } - ], - "body": [ - { - "text": ".saturating_mul(" - }, - { - "placeholder": { - "arg": "a2", - "access": "read" - } - }, - { - "text": ")" - } - ] - } - }, - { - "text": " as usize;\n let mut dst = " + "text": "libcc2rs::fread_refcount(" }, { - "method_call": { - "receiver": [ - { - "method_call": { - "receiver": [ - { - "method_call": { - "receiver": [ - { - "placeholder": { - "arg": "a0", - "access": "read" - } - } - ], - "body": [ - { - "text": ".cast::()" - } - ] - } - } - ], - "body": [ - { - "text": ".expect(\"fread: only supporting u8 pointers\")" - } - ] - } - } - ], - "body": [ - { - "text": ".clone()" - } - ] - } - }, - { - "text": ";\n\n let mut f = " - }, - { - "method_call": { - "receiver": [ - { - "method_call": { - "receiver": [ - { - "text": "(*" - }, - { - "method_call": { - "receiver": [ - { - "method_call": { - "receiver": [ - { - "placeholder": { - "arg": "a3", - "access": "read" - } - } - ], - "body": [ - { - "text": ".upgrade()" - } - ] - } - } - ], - "body": [ - { - "text": ".deref()" - } - ] - } - }, - { - "text": ")" - } - ], - "body": [ - { - "text": ".try_clone()" - } - ] - } - } - ], - "body": [ - { - "text": ".expect(\"try_clone failed\")" - } - ] - } - }, - { - "text": ";\n let mut reader = std::io::BufReader::with_capacity(64 * 1024, f);\n\n let mut read_bytes: usize = 0;\n let mut buffer: [u8; 8192] = [0; 8192];\n\n while read_bytes < total {\n let remaining = total - read_bytes;\n let to_read = std::cmp::min(" - }, - { - "method_call": { - "receiver": [ - { - "text": "buffer" - } - ], - "body": [ - { - "text": ".len()" - } - ] + "placeholder": { + "arg": "a0", + "access": "read" } }, { - "text": ", remaining);\n\n let n = match std::io::Read::read(&mut reader, &mut buffer[..to_read]) {\n Ok(0) => break,\n Ok(n) => n,\n Err(ref e) if " + "text": ", " }, { - "method_call": { - "receiver": [ - { - "text": "e" - } - ], - "body": [ - { - "text": ".kind()" - } - ] + "placeholder": { + "arg": "a1", + "access": "read" } }, { - "text": " == std::io::ErrorKind::Interrupted => continue,\n Err(e) => panic!(\"Unhandled error in fread: {e}\"),\n };\n\n for i in 0..n {\n " + "text": ", " }, { - "method_call": { - "receiver": [ - { - "text": "dst" - } - ], - "body": [ - { - "text": ".write(buffer[i])" - } - ] + "placeholder": { + "arg": "a2", + "access": "read" } }, { - "text": ";\n dst = " + "text": ", " }, { "method_call": { "receiver": [ { - "text": "dst" + "placeholder": { + "arg": "a3", + "access": "read" + } } ], "body": [ { - "text": ".offset(1)" + "text": ".clone()" } ] } }, { - "text": ";\n }\n\n read_bytes += n;\n }\n\n (read_bytes / " - }, - { - "placeholder": { - "arg": "a1", - "access": "read" - } - }, - { - "text": " as usize) as u64" + "text": ")" } ], - "multi_statement": true, "params": { "a0": { "type": "AnyPtr" diff --git a/rules/stdio/ir_unsafe.json b/rules/stdio/ir_unsafe.json index 81d8f440..314394d0 100644 --- a/rules/stdio/ir_unsafe.json +++ b/rules/stdio/ir_unsafe.json @@ -477,36 +477,7 @@ "f5": { "body": [ { - "text": "let total = " - }, - { - "method_call": { - "receiver": [ - { - "placeholder": { - "arg": "a1", - "access": "read" - } - } - ], - "body": [ - { - "text": ".saturating_mul(" - }, - { - "placeholder": { - "arg": "a2", - "access": "read" - } - }, - { - "text": ")" - } - ] - } - }, - { - "text": " as usize;\n let mut dst = " + "text": "unsafe { libcc2rs::fread_unsafe(" }, { "placeholder": { @@ -515,110 +486,39 @@ } }, { - "text": " as *mut u8;\n\n let mut f = " + "text": " as *mut ::std::ffi::c_void, " }, { - "method_call": { - "receiver": [ - { - "method_call": { - "receiver": [ - { - "text": "(*" - }, - { - "placeholder": { - "arg": "a3", - "access": "read" - } - }, - { - "text": ")" - } - ], - "body": [ - { - "text": ".try_clone()" - } - ] - } - } - ], - "body": [ - { - "text": ".expect(\"try_clone failed\")" - } - ] - } - }, - { - "text": ";\n let mut reader = std::io::BufReader::with_capacity(64 * 1024, f);\n\n let mut read_bytes: usize = 0;\n let mut buffer: [u8; 8192] = [0; 8192];\n\n while read_bytes < total {\n let remaining = total - read_bytes;\n let to_read = std::cmp::min(" - }, - { - "method_call": { - "receiver": [ - { - "text": "buffer" - } - ], - "body": [ - { - "text": ".len()" - } - ] - } - }, - { - "text": ", remaining);\n\n let n = match std::io::Read::read(&mut reader, &mut buffer[..to_read]) {\n Ok(0) => break,\n Ok(n) => n,\n Err(ref e) if " - }, - { - "method_call": { - "receiver": [ - { - "text": "e" - } - ], - "body": [ - { - "text": ".kind()" - } - ] + "placeholder": { + "arg": "a1", + "access": "read" } }, { - "text": " == std::io::ErrorKind::Interrupted => continue,\n Err(e) => panic!(\"Unhandled error in fread: {e}\"),\n };\n\n for i in 0..n {\n *dst = buffer[i];\n dst = " + "text": ", " }, { - "method_call": { - "receiver": [ - { - "text": "dst" - } - ], - "body": [ - { - "text": ".offset(1)" - } - ] + "placeholder": { + "arg": "a2", + "access": "read" } }, { - "text": ";\n }\n\n read_bytes += n;\n }\n\n (read_bytes / " + "text": ", " }, { "placeholder": { - "arg": "a1", + "arg": "a3", "access": "read" } }, { - "text": " as usize) as u64" + "text": ") }" } ], - "multi_statement": true, "params": { "a0": { - "type": "*mut u8", + "type": "*mut ::libc::c_void", "is_unsafe_pointer": true }, "a1": { @@ -797,7 +697,7 @@ "multi_statement": true, "params": { "a0": { - "type": "*mut u8", + "type": "*const ::libc::c_void", "is_unsafe_pointer": true }, "a1": { diff --git a/rules/stdio/tgt_refcount.rs b/rules/stdio/tgt_refcount.rs index ea7174fd..98659d76 100644 --- a/rules/stdio/tgt_refcount.rs +++ b/rules/stdio/tgt_refcount.rs @@ -56,40 +56,7 @@ fn f4(a0: &mut ::std::fs::File, a1: i64, a2: i32) -> i32 { } fn f5(a0: AnyPtr, a1: u64, a2: u64, a3: Ptr<::std::fs::File>) -> u64 { - let total = a1.saturating_mul(a2) as usize; - let mut dst = a0 - .cast::() - .expect("fread: only supporting u8 pointers") - .clone(); - - let mut f = (*a3.upgrade().deref()) - .try_clone() - .expect("try_clone failed"); - let mut reader = std::io::BufReader::with_capacity(64 * 1024, f); - - let mut read_bytes: usize = 0; - let mut buffer: [u8; 8192] = [0; 8192]; - - while read_bytes < total { - let remaining = total - read_bytes; - let to_read = std::cmp::min(buffer.len(), remaining); - - let n = match std::io::Read::read(&mut reader, &mut buffer[..to_read]) { - Ok(0) => break, - Ok(n) => n, - Err(ref e) if e.kind() == std::io::ErrorKind::Interrupted => continue, - Err(e) => panic!("Unhandled error in fread: {e}"), - }; - - for i in 0..n { - dst.write(buffer[i]); - dst = dst.offset(1); - } - - read_bytes += n; - } - - (read_bytes / a1 as usize) as u64 + libcc2rs::fread_refcount(a0, a1, a2, a3.clone()) } fn f6(a0: AnyPtr, a1: u64, a2: u64, a3: Ptr<::std::fs::File>) -> u64 { diff --git a/rules/stdio/tgt_unsafe.rs b/rules/stdio/tgt_unsafe.rs index adc05652..1bd1b6e7 100644 --- a/rules/stdio/tgt_unsafe.rs +++ b/rules/stdio/tgt_unsafe.rs @@ -65,39 +65,11 @@ unsafe fn f4(a0: *mut ::std::fs::File, a1: i64, a2: i32) -> i32 { } } -unsafe fn f5(a0: *mut u8, a1: u64, a2: u64, a3: *mut ::std::fs::File) -> u64 { - let total = a1.saturating_mul(a2) as usize; - let mut dst = a0 as *mut u8; - - let mut f = (*a3).try_clone().expect("try_clone failed"); - let mut reader = std::io::BufReader::with_capacity(64 * 1024, f); - - let mut read_bytes: usize = 0; - let mut buffer: [u8; 8192] = [0; 8192]; - - while read_bytes < total { - let remaining = total - read_bytes; - let to_read = std::cmp::min(buffer.len(), remaining); - - let n = match std::io::Read::read(&mut reader, &mut buffer[..to_read]) { - Ok(0) => break, - Ok(n) => n, - Err(ref e) if e.kind() == std::io::ErrorKind::Interrupted => continue, - Err(e) => panic!("Unhandled error in fread: {e}"), - }; - - for i in 0..n { - *dst = buffer[i]; - dst = dst.offset(1); - } - - read_bytes += n; - } - - (read_bytes / a1 as usize) as u64 +unsafe fn f5(a0: *mut ::libc::c_void, a1: u64, a2: u64, a3: *mut ::std::fs::File) -> u64 { + unsafe { libcc2rs::fread_unsafe(a0 as *mut ::std::ffi::c_void, a1, a2, a3) } } -unsafe fn f6(a0: *mut u8, a1: u64, a2: u64, a3: *mut ::std::fs::File) -> u64 { +unsafe fn f6(a0: *const ::libc::c_void, a1: u64, a2: u64, a3: *mut ::std::fs::File) -> u64 { let total = a1.saturating_mul(a2) as usize; let mut src = a0 as *mut u8; diff --git a/tests/unit/fn_ptr_stdlib_compare.cpp b/tests/unit/fn_ptr_stdlib_compare.cpp new file mode 100644 index 00000000..38f2e134 --- /dev/null +++ b/tests/unit/fn_ptr_stdlib_compare.cpp @@ -0,0 +1,44 @@ +#include +#include +#include +#include + +typedef size_t (*fread_t)(void *, size_t, size_t, FILE *); + +typedef size_t (*fread_alternative_t)(char *, size_t, size_t, void *); + +size_t my_alternative_fread(char *p, size_t n, size_t m, void *f) { return 22; } + +#define CHECK_FREAD(call) \ + do { \ + FILE *stream = fopen("/dev/zero", "rb"); \ + assert(stream != nullptr); \ + char buf[16]; \ + memset(buf, 'X', sizeof(buf)); \ + size_t n = (call)(buf, 1, 10, stream); \ + assert(n == 10); \ + for (int i = 0; i < 10; ++i) { \ + assert(buf[i] == 0); \ + } \ + for (int i = 10; i < 16; ++i) { \ + assert(buf[i] == 'X'); \ + } \ + fclose(stream); \ + } while (0) + +int main() { + fread_t fn1 = fread; + assert(fn1 == fread); + assert(fn1 != nullptr); + + fread_alternative_t fn2 = (fread_alternative_t)fread; + assert(fn1 == (fread_t)fn2); + + fread_t f3 = (fread_t)my_alternative_fread; + assert((*f3)(nullptr, 0, 0, nullptr) == 22); + + CHECK_FREAD(fread); + CHECK_FREAD((*fn1)); + + return 0; +} diff --git a/tests/unit/out/refcount/fn_ptr_stdlib_compare.rs b/tests/unit/out/refcount/fn_ptr_stdlib_compare.rs new file mode 100644 index 00000000..b71cb285 --- /dev/null +++ b/tests/unit/out/refcount/fn_ptr_stdlib_compare.rs @@ -0,0 +1,181 @@ +extern crate libcc2rs; +use libcc2rs::*; +use std::cell::RefCell; +use std::collections::BTreeMap; +use std::io::prelude::*; +use std::io::{Read, Seek, Write}; +use std::os::fd::AsFd; +use std::rc::{Rc, Weak}; +pub fn my_alternative_fread_0(p: Ptr, n: u64, m: u64, f: AnyPtr) -> u64 { + let p: Value> = Rc::new(RefCell::new(p)); + let n: Value = Rc::new(RefCell::new(n)); + let m: Value = Rc::new(RefCell::new(m)); + let f: Value = Rc::new(RefCell::new(f)); + return 22_u64; +} +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let fn1: Value) -> u64>> = + Rc::new(RefCell::new(FnPtr::< + fn(AnyPtr, u64, u64, Ptr<::std::fs::File>) -> u64, + >::new(libcc2rs::fread_refcount))); + assert!({ + let _lhs = (*fn1.borrow()).clone(); + _lhs == FnPtr::) -> u64>::new( + libcc2rs::fread_refcount, + ) + }); + assert!(!((*fn1.borrow()).is_null())); + let fn2: Value, u64, u64, AnyPtr) -> u64>> = Rc::new(RefCell::new( + FnPtr::) -> u64>::new(libcc2rs::fread_refcount) + .cast::, u64, u64, AnyPtr) -> u64>(Some( + (|a0: Ptr, a1: u64, a2: u64, a3: AnyPtr| -> u64 { + libcc2rs::fread_refcount(a0.to_any(), a1, a2, a3.cast::<::std::fs::File>().unwrap()) + }) as fn(Ptr, u64, u64, AnyPtr) -> u64, + )), + )); + assert!({ + let _lhs = (*fn1.borrow()).clone(); + _lhs == ((*fn2.borrow()).cast::) -> u64>(None)) + .clone() + }); + let f3: Value) -> u64>> = + Rc::new(RefCell::new( + FnPtr::, u64, u64, AnyPtr) -> u64>::new(my_alternative_fread_0).cast::, + ) + -> u64>( + Some( + (|a0: AnyPtr, a1: u64, a2: u64, a3: Ptr<::std::fs::File>| -> u64 { + my_alternative_fread_0(a0.cast::().unwrap(), a1, a2, a3.to_any()) + }) as fn(AnyPtr, u64, u64, Ptr<::std::fs::File>) -> u64, + ), + ), + )); + assert!( + (({ + let _arg0: AnyPtr = Default::default(); + let _arg1: u64 = 0_u64; + let _arg2: u64 = 0_u64; + let _arg3: Ptr<::std::fs::File> = Default::default(); + (*(*f3.borrow()))(_arg0, _arg1, _arg2, _arg3) + }) == 22_u64) + ); + 'loop_: loop { + let stream: Value> = Rc::new(RefCell::new( + match Ptr::from_string_literal("rb").to_rust_string() { + v if v == "rb" => std::fs::OpenOptions::new() + .read(true) + .open(Ptr::from_string_literal("/dev/zero").to_rust_string()) + .ok() + .map_or(Ptr::null(), |f| Ptr::alloc(f)), + v if v == "wb" => std::fs::OpenOptions::new() + .write(true) + .create(true) + .truncate(true) + .open(Ptr::from_string_literal("/dev/zero").to_rust_string()) + .ok() + .map_or(Ptr::null(), |f| Ptr::alloc(f)), + _ => panic!("unsupported mode"), + }, + )); + assert!(!((*stream.borrow()).is_null())); + let buf: Value> = Rc::new(RefCell::new( + (0..16).map(|_| ::default()).collect::>(), + )); + { + ((buf.as_pointer() as Ptr) as Ptr).to_any().memset( + (('X' as u8) as i32) as u8, + ::std::mem::size_of::<[u8; 16]>() as u64 as usize, + ); + ((buf.as_pointer() as Ptr) as Ptr).to_any().clone() + }; + let n: Value = Rc::new(RefCell::new(libcc2rs::fread_refcount( + ((buf.as_pointer() as Ptr) as Ptr).to_any(), + 1_u64, + 10_u64, + (*stream.borrow()).clone(), + ))); + assert!(((*n.borrow()) == 10_u64)); + let i: Value = Rc::new(RefCell::new(0)); + 'loop_: while ((*i.borrow()) < 10) { + assert!((((*buf.borrow())[(*i.borrow()) as usize] as i32) == 0)); + (*i.borrow_mut()).prefix_inc(); + } + let i: Value = Rc::new(RefCell::new(10)); + 'loop_: while ((*i.borrow()) < 16) { + assert!((((*buf.borrow())[(*i.borrow()) as usize] as i32) == (('X' as u8) as i32))); + (*i.borrow_mut()).prefix_inc(); + } + { + (*stream.borrow()).delete(); + 0 + }; + if !(0 != 0) { + break; + } + } + 'loop_: loop { + let stream: Value> = Rc::new(RefCell::new( + match Ptr::from_string_literal("rb").to_rust_string() { + v if v == "rb" => std::fs::OpenOptions::new() + .read(true) + .open(Ptr::from_string_literal("/dev/zero").to_rust_string()) + .ok() + .map_or(Ptr::null(), |f| Ptr::alloc(f)), + v if v == "wb" => std::fs::OpenOptions::new() + .write(true) + .create(true) + .truncate(true) + .open(Ptr::from_string_literal("/dev/zero").to_rust_string()) + .ok() + .map_or(Ptr::null(), |f| Ptr::alloc(f)), + _ => panic!("unsupported mode"), + }, + )); + assert!(!((*stream.borrow()).is_null())); + let buf: Value> = Rc::new(RefCell::new( + (0..16).map(|_| ::default()).collect::>(), + )); + { + ((buf.as_pointer() as Ptr) as Ptr).to_any().memset( + (('X' as u8) as i32) as u8, + ::std::mem::size_of::<[u8; 16]>() as u64 as usize, + ); + ((buf.as_pointer() as Ptr) as Ptr).to_any().clone() + }; + let n: Value = Rc::new(RefCell::new( + ({ + let _arg0: AnyPtr = ((buf.as_pointer() as Ptr) as Ptr).to_any(); + let _arg1: u64 = 1_u64; + let _arg2: u64 = 10_u64; + let _arg3: Ptr<::std::fs::File> = (*stream.borrow()).clone(); + (*(*fn1.borrow()))(_arg0, _arg1, _arg2, _arg3) + }), + )); + assert!(((*n.borrow()) == 10_u64)); + let i: Value = Rc::new(RefCell::new(0)); + 'loop_: while ((*i.borrow()) < 10) { + assert!((((*buf.borrow())[(*i.borrow()) as usize] as i32) == 0)); + (*i.borrow_mut()).prefix_inc(); + } + let i: Value = Rc::new(RefCell::new(10)); + 'loop_: while ((*i.borrow()) < 16) { + assert!((((*buf.borrow())[(*i.borrow()) as usize] as i32) == (('X' as u8) as i32))); + (*i.borrow_mut()).prefix_inc(); + } + { + (*stream.borrow()).delete(); + 0 + }; + if !(0 != 0) { + break; + } + } + return 0; +} diff --git a/tests/unit/out/unsafe/fn_ptr_stdlib_compare.rs b/tests/unit/out/unsafe/fn_ptr_stdlib_compare.rs new file mode 100644 index 00000000..c0e91c0f --- /dev/null +++ b/tests/unit/out/unsafe/fn_ptr_stdlib_compare.rs @@ -0,0 +1,181 @@ +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 my_alternative_fread_0( + mut p: *mut u8, + mut n: u64, + mut m: u64, + mut f: *mut ::libc::c_void, +) -> u64 { + return 22_u64; +} +pub fn main() { + unsafe { + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut fn1: Option u64> = + Some(libcc2rs::fread_unsafe); + assert!(((fn1) == (Some(libcc2rs::fread_unsafe)))); + assert!(!((fn1).is_none())); + let mut fn2: Option u64> = + std::mem::transmute::< + Option u64>, + Option u64>, + >(Some(libcc2rs::fread_unsafe)); + assert!( + ((fn1) + == (std::mem::transmute::< + Option u64>, + Option u64>, + >(fn2))) + ); + let mut f3: Option u64> = + std::mem::transmute::< + Option u64>, + Option u64>, + >(Some(my_alternative_fread_0)); + assert!( + ((unsafe { + let _arg0: *mut ::libc::c_void = Default::default(); + let _arg1: u64 = 0_u64; + let _arg2: u64 = 0_u64; + let _arg3: *mut ::std::fs::File = Default::default(); + (f3).unwrap()(_arg0, _arg1, _arg2, _arg3) + }) == (22_u64)) + ); + 'loop_: loop { + let mut stream: *mut ::std::fs::File = + match std::ffi::CStr::from_ptr(b"rb\0".as_ptr() 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(b"/dev/zero\0".as_ptr() 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(b"/dev/zero\0".as_ptr() 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!(!((stream).is_null())); + let mut buf: [u8; 16] = [0_u8; 16]; + { + let byte_0 = (buf.as_mut_ptr() as *mut u8 as *mut ::libc::c_void) as *mut u8; + for offset in 0..::std::mem::size_of::<[u8; 16]>() as u64 { + *byte_0.offset(offset as isize) = (('X' as u8) as i32) as u8; + } + (buf.as_mut_ptr() as *mut u8 as *mut ::libc::c_void) + }; + let mut n: u64 = unsafe { + libcc2rs::fread_unsafe( + (buf.as_mut_ptr() as *mut u8 as *mut ::libc::c_void) as *mut ::std::ffi::c_void, + 1_u64, + 10_u64, + stream, + ) + }; + assert!(((n) == (10_u64))); + let mut i: i32 = 0; + 'loop_: while ((i) < (10)) { + assert!(((buf[(i) as usize] as i32) == (0))); + i.prefix_inc(); + } + let mut i: i32 = 10; + 'loop_: while ((i) < (16)) { + assert!(((buf[(i) as usize] as i32) == (('X' as u8) as i32))); + i.prefix_inc(); + } + { + Box::from_raw(stream); + 0 + }; + if !(0 != 0) { + break; + } + } + 'loop_: loop { + let mut stream: *mut ::std::fs::File = + match std::ffi::CStr::from_ptr(b"rb\0".as_ptr() 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(b"/dev/zero\0".as_ptr() 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(b"/dev/zero\0".as_ptr() 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!(!((stream).is_null())); + let mut buf: [u8; 16] = [0_u8; 16]; + { + let byte_0 = (buf.as_mut_ptr() as *mut u8 as *mut ::libc::c_void) as *mut u8; + for offset in 0..::std::mem::size_of::<[u8; 16]>() as u64 { + *byte_0.offset(offset as isize) = (('X' as u8) as i32) as u8; + } + (buf.as_mut_ptr() as *mut u8 as *mut ::libc::c_void) + }; + let mut n: u64 = (unsafe { + let _arg0: *mut ::libc::c_void = (buf.as_mut_ptr() as *mut u8 as *mut ::libc::c_void); + let _arg1: u64 = 1_u64; + let _arg2: u64 = 10_u64; + let _arg3: *mut ::std::fs::File = stream; + (fn1).unwrap()(_arg0, _arg1, _arg2, _arg3) + }); + assert!(((n) == (10_u64))); + let mut i: i32 = 0; + 'loop_: while ((i) < (10)) { + assert!(((buf[(i) as usize] as i32) == (0))); + i.prefix_inc(); + } + let mut i: i32 = 10; + 'loop_: while ((i) < (16)) { + assert!(((buf[(i) as usize] as i32) == (('X' as u8) as i32))); + i.prefix_inc(); + } + { + Box::from_raw(stream); + 0 + }; + if !(0 != 0) { + break; + } + } + return 0; +}