diff --git a/libcc2rs/src/io.rs b/libcc2rs/src/io.rs index a9f3ce49..3756f4b4 100644 --- a/libcc2rs/src/io.rs +++ b/libcc2rs/src/io.rs @@ -112,7 +112,7 @@ pub fn fread_refcount(a0: AnyPtr, a1: u64, a2: u64, a3: Ptr<::std::fs::File>) -> for &byte in &buffer[..n] { dst.write(byte); - dst = dst.offset(1); + dst += 1; } read_bytes += n; @@ -121,6 +121,100 @@ pub fn fread_refcount(a0: AnyPtr, a1: u64, a2: u64, a3: Ptr<::std::fs::File>) -> (read_bytes / a1 as usize) as u64 } +pub fn fwrite_refcount(a0: AnyPtr, a1: u64, a2: u64, a3: Ptr<::std::fs::File>) -> u64 { + let total = a1.saturating_mul(a2) as usize; + let mut src = a0 + .cast::() + .expect("fwrite: only supporting u8 pointers") + .clone(); + + let f = (*a3.upgrade().deref()) + .try_clone() + .expect("try_clone failed"); + let mut writer = std::io::BufWriter::with_capacity(64 * 1024, f); + + let mut written_bytes: usize = 0; + let mut buffer: [u8; 8192] = [0; 8192]; + + while written_bytes < total { + let remaining = total - written_bytes; + let to_fill = std::cmp::min(buffer.len(), remaining); + + for b in buffer.iter_mut().take(to_fill) { + *b = src.read(); + src += 1; + } + + let mut off = 0; + while off < to_fill { + match std::io::Write::write(&mut writer, &buffer[off..to_fill]) { + Ok(0) => break, + Ok(n) => off += n, + Err(ref e) if e.kind() == std::io::ErrorKind::Interrupted => continue, + Err(e) => panic!("Unhandled error in fwrite: {e}"), + } + } + + if off == 0 { + break; + } + + written_bytes += off; + } + + (written_bytes / a1 as usize) as u64 +} + +/// # Safety +/// +/// `a0` must point to a readable buffer of at least `a1 * a2` bytes, and `a3` +/// must point to a valid, open `std::fs::File`. +pub unsafe fn fwrite_unsafe( + a0: *const ::std::ffi::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 *const u8; + + let f = unsafe { (*a3).try_clone().expect("try_clone failed") }; + let mut writer = std::io::BufWriter::with_capacity(64 * 1024, f); + + let mut written_bytes: usize = 0; + let mut buffer: [u8; 8192] = [0; 8192]; + + while written_bytes < total { + let remaining = total - written_bytes; + let to_fill = std::cmp::min(buffer.len(), remaining); + + for b in buffer.iter_mut().take(to_fill) { + unsafe { + *b = *src; + src = src.offset(1); + } + } + + let mut off = 0; + while off < to_fill { + match std::io::Write::write(&mut writer, &buffer[off..to_fill]) { + Ok(0) => break, + Ok(n) => off += n, + Err(ref e) if e.kind() == std::io::ErrorKind::Interrupted => continue, + Err(e) => panic!("Unhandled error in fwrite: {e}"), + } + } + + if off == 0 { + break; + } + + written_bytes += off; + } + + (written_bytes / a1 as usize) as u64 +} + /// # Safety /// /// `a0` must point to a writable buffer of at least `a1 * a2` bytes, and `a3` diff --git a/rules/stdio/ir_refcount.json b/rules/stdio/ir_refcount.json index 8f47ab89..da8fd01a 100644 --- a/rules/stdio/ir_refcount.json +++ b/rules/stdio/ir_refcount.json @@ -503,234 +503,56 @@ "f6": { "body": [ { - "text": "let total = " + "text": "libcc2rs::fwrite_refcount(" }, { - "method_call": { - "receiver": [ - { - "placeholder": { - "arg": 1, - "access": "read" - } - } - ], - "body": [ - { - "text": ".saturating_mul(" - }, - { - "placeholder": { - "arg": 2, - "access": "read" - } - }, - { - "text": ")" - } - ] - } - }, - { - "text": " as usize;\n let mut src = " - }, - { - "method_call": { - "receiver": [ - { - "method_call": { - "receiver": [ - { - "method_call": { - "receiver": [ - { - "placeholder": { - "arg": 0, - "access": "read" - } - } - ], - "body": [ - { - "text": ".cast::()" - } - ] - } - } - ], - "body": [ - { - "text": ".expect(\"fwrite: 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": 3, - "access": "read" - } - } - ], - "body": [ - { - "text": ".upgrade()" - } - ] - } - } - ], - "body": [ - { - "text": ".deref()" - } - ] - } - }, - { - "text": ")" - } - ], - "body": [ - { - "text": ".try_clone()" - } - ] - } - } - ], - "body": [ - { - "text": ".expect(\"try_clone failed\")" - } - ] - } - }, - { - "text": ";\n let mut writer = std::io::BufWriter::with_capacity(64 * 1024, f);\n\n let mut written_bytes: usize = 0;\n let mut buffer: [u8; 8192] = [0; 8192];\n\n while written_bytes < total {\n let remaining = total - written_bytes;\n let to_fill = std::cmp::min(" - }, - { - "method_call": { - "receiver": [ - { - "text": "buffer" - } - ], - "body": [ - { - "text": ".len()" - } - ] - } - }, - { - "text": ", remaining);\n\n for i in 0..to_fill {\n buffer[i] = " - }, - { - "method_call": { - "receiver": [ - { - "text": "src" - } - ], - "body": [ - { - "text": ".read()" - } - ] + "placeholder": { + "arg": 0, + "access": "read" } }, { - "text": ";\n src = " + "text": ", " }, { - "method_call": { - "receiver": [ - { - "text": "src" - } - ], - "body": [ - { - "text": ".offset(1)" - } - ] + "placeholder": { + "arg": 1, + "access": "read" } }, { - "text": ";\n }\n\n let mut off = 0;\n while off < to_fill {\n match std::io::Write::write(&mut writer, &buffer[off..to_fill]) {\n Ok(0) => break,\n Ok(n) => off += n,\n Err(ref e) if " + "text": ", " }, { - "method_call": { - "receiver": [ - { - "text": "e" - } - ], - "body": [ - { - "text": ".kind()" - } - ] + "placeholder": { + "arg": 2, + "access": "read" } }, { - "text": " == std::io::ErrorKind::Interrupted => continue,\n Err(e) => panic!(\"Unhandled error in fwrite: {e}\"),\n }\n }\n\n if off == 0 {\n break;\n }\n\n written_bytes += off;\n }\n\n " + "text": ", " }, { "method_call": { "receiver": [ { - "text": "std::io::Write::flush(&mut writer)" + "placeholder": { + "arg": 3, + "access": "read" + } } ], "body": [ { - "text": ".expect(\"flush failed\")" + "text": ".clone()" } ] } }, { - "text": ";\n\n (written_bytes / " - }, - { - "placeholder": { - "arg": 1, - "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 368dc3b9..b1f04054 100644 --- a/rules/stdio/ir_unsafe.json +++ b/rules/stdio/ir_unsafe.json @@ -488,7 +488,7 @@ "f5": { "body": [ { - "text": "unsafe { libcc2rs::fread_unsafe(" + "text": "libcc2rs::fread_unsafe(" }, { "placeholder": { @@ -524,7 +524,7 @@ } }, { - "text": ") }" + "text": ")" } ], "params": { @@ -550,36 +550,7 @@ "f6": { "body": [ { - "text": "let total = " - }, - { - "method_call": { - "receiver": [ - { - "placeholder": { - "arg": 1, - "access": "read" - } - } - ], - "body": [ - { - "text": ".saturating_mul(" - }, - { - "placeholder": { - "arg": 2, - "access": "read" - } - }, - { - "text": ")" - } - ] - } - }, - { - "text": " as usize;\n let mut src = " + "text": "libcc2rs::fwrite_unsafe(" }, { "placeholder": { @@ -588,124 +559,36 @@ } }, { - "text": " as *mut u8;\n\n let mut f = " - }, - { - "method_call": { - "receiver": [ - { - "method_call": { - "receiver": [ - { - "text": "(*" - }, - { - "placeholder": { - "arg": 3, - "access": "read" - } - }, - { - "text": ")" - } - ], - "body": [ - { - "text": ".try_clone()" - } - ] - } - } - ], - "body": [ - { - "text": ".expect(\"try_clone failed\")" - } - ] - } - }, - { - "text": ";\n let mut writer = std::io::BufWriter::with_capacity(64 * 1024, f);\n\n let mut written_bytes: usize = 0;\n let mut buffer: [u8; 8192] = [0; 8192];\n\n while written_bytes < total {\n let remaining = total - written_bytes;\n let to_fill = std::cmp::min(" - }, - { - "method_call": { - "receiver": [ - { - "text": "buffer" - } - ], - "body": [ - { - "text": ".len()" - } - ] - } - }, - { - "text": ", remaining);\n\n for i in 0..to_fill {\n buffer[i] = *src;\n src = " - }, - { - "method_call": { - "receiver": [ - { - "text": "src" - } - ], - "body": [ - { - "text": ".offset(1)" - } - ] - } - }, - { - "text": ";\n }\n\n let mut off = 0;\n while off < to_fill {\n match std::io::Write::write(&mut writer, &buffer[off..to_fill]) {\n Ok(0) => break,\n Ok(n) => off += n,\n Err(ref e) if " + "text": " as *const ::std::ffi::c_void, " }, { - "method_call": { - "receiver": [ - { - "text": "e" - } - ], - "body": [ - { - "text": ".kind()" - } - ] + "placeholder": { + "arg": 1, + "access": "read" } }, { - "text": " == std::io::ErrorKind::Interrupted => continue,\n Err(e) => panic!(\"Unhandled error in fwrite: {e}\"),\n }\n }\n\n if off == 0 {\n break;\n }\n\n written_bytes += off;\n }\n\n " + "text": ", " }, { - "method_call": { - "receiver": [ - { - "text": "std::io::Write::flush(&mut writer)" - } - ], - "body": [ - { - "text": ".expect(\"flush failed\")" - } - ] + "placeholder": { + "arg": 2, + "access": "read" } }, { - "text": ";\n\n (written_bytes / " + "text": ", " }, { "placeholder": { - "arg": 1, + "arg": 3, "access": "read" } }, { - "text": " as usize) as u64" + "text": ")" } ], - "multi_statement": true, "params": { "a0": { "type": "*const ::libc::c_void", diff --git a/rules/stdio/tgt_refcount.rs b/rules/stdio/tgt_refcount.rs index 4c2e0a60..1814ac55 100644 --- a/rules/stdio/tgt_refcount.rs +++ b/rules/stdio/tgt_refcount.rs @@ -60,49 +60,7 @@ fn f5(a0: AnyPtr, a1: u64, a2: u64, a3: Ptr<::std::fs::File>) -> u64 { } fn f6(a0: AnyPtr, a1: u64, a2: u64, a3: Ptr<::std::fs::File>) -> u64 { - let total = a1.saturating_mul(a2) as usize; - let mut src = a0 - .cast::() - .expect("fwrite: only supporting u8 pointers") - .clone(); - - let mut f = (*a3.upgrade().deref()) - .try_clone() - .expect("try_clone failed"); - let mut writer = std::io::BufWriter::with_capacity(64 * 1024, f); - - let mut written_bytes: usize = 0; - let mut buffer: [u8; 8192] = [0; 8192]; - - while written_bytes < total { - let remaining = total - written_bytes; - let to_fill = std::cmp::min(buffer.len(), remaining); - - for i in 0..to_fill { - buffer[i] = src.read(); - src = src.offset(1); - } - - let mut off = 0; - while off < to_fill { - match std::io::Write::write(&mut writer, &buffer[off..to_fill]) { - Ok(0) => break, - Ok(n) => off += n, - Err(ref e) if e.kind() == std::io::ErrorKind::Interrupted => continue, - Err(e) => panic!("Unhandled error in fwrite: {e}"), - } - } - - if off == 0 { - break; - } - - written_bytes += off; - } - - std::io::Write::flush(&mut writer).expect("flush failed"); - - (written_bytes / a1 as usize) as u64 + libcc2rs::fwrite_refcount(a0, a1, a2, a3.clone()) } fn f7(a0: Ptr<::std::fs::File>) -> i32 { diff --git a/rules/stdio/tgt_unsafe.rs b/rules/stdio/tgt_unsafe.rs index 737728b9..98502092 100644 --- a/rules/stdio/tgt_unsafe.rs +++ b/rules/stdio/tgt_unsafe.rs @@ -66,48 +66,11 @@ unsafe fn f4(a0: *mut ::std::fs::File, a1: i64, a2: i32) -> i32 { } 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) } + libcc2rs::fread_unsafe(a0 as *mut ::std::ffi::c_void, a1, a2, a3) } 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; - - let mut f = (*a3).try_clone().expect("try_clone failed"); - let mut writer = std::io::BufWriter::with_capacity(64 * 1024, f); - - let mut written_bytes: usize = 0; - let mut buffer: [u8; 8192] = [0; 8192]; - - while written_bytes < total { - let remaining = total - written_bytes; - let to_fill = std::cmp::min(buffer.len(), remaining); - - for i in 0..to_fill { - buffer[i] = *src; - src = src.offset(1); - } - - let mut off = 0; - while off < to_fill { - match std::io::Write::write(&mut writer, &buffer[off..to_fill]) { - Ok(0) => break, - Ok(n) => off += n, - Err(ref e) if e.kind() == std::io::ErrorKind::Interrupted => continue, - Err(e) => panic!("Unhandled error in fwrite: {e}"), - } - } - - if off == 0 { - break; - } - - written_bytes += off; - } - - std::io::Write::flush(&mut writer).expect("flush failed"); - - (written_bytes / a1 as usize) as u64 + libcc2rs::fwrite_unsafe(a0 as *const ::std::ffi::c_void, a1, a2, a3) } unsafe fn f7(a0: *mut ::std::fs::File) -> i32 { diff --git a/tests/unit/fn_ptr_stdlib_compare.cpp b/tests/unit/fn_ptr_stdlib_compare.cpp index 38f2e134..0c58caef 100644 --- a/tests/unit/fn_ptr_stdlib_compare.cpp +++ b/tests/unit/fn_ptr_stdlib_compare.cpp @@ -9,6 +9,14 @@ 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; } +typedef size_t (*fwrite_t)(const void *, size_t, size_t, FILE *); + +typedef size_t (*fwrite_alternative_t)(const char *, size_t, size_t, void *); + +size_t my_alternative_fwrite(const char *p, size_t n, size_t m, void *f) { + return 33; +} + #define CHECK_FREAD(call) \ do { \ FILE *stream = fopen("/dev/zero", "rb"); \ @@ -26,6 +34,17 @@ size_t my_alternative_fread(char *p, size_t n, size_t m, void *f) { return 22; } fclose(stream); \ } while (0) +#define CHECK_FWRITE(call) \ + do { \ + FILE *stream = fopen("/dev/null", "wb"); \ + assert(stream != nullptr); \ + char buf[10]; \ + memset(buf, 'Y', sizeof(buf)); \ + size_t n = (call)(buf, 1, 10, stream); \ + assert(n == 10); \ + fclose(stream); \ + } while (0) + int main() { fread_t fn1 = fread; assert(fn1 == fread); @@ -40,5 +59,18 @@ int main() { CHECK_FREAD(fread); CHECK_FREAD((*fn1)); + fwrite_t gn1 = fwrite; + assert(gn1 == fwrite); + assert(gn1 != nullptr); + + fwrite_alternative_t gn2 = (fwrite_alternative_t)fwrite; + assert(gn1 == (fwrite_t)gn2); + + fwrite_t g3 = (fwrite_t)my_alternative_fwrite; + assert((*g3)(nullptr, 0, 0, nullptr) == 33); + + CHECK_FWRITE(fwrite); + CHECK_FWRITE((*gn1)); + return 0; } diff --git a/tests/unit/out/refcount/fn_ptr_stdlib_compare.rs b/tests/unit/out/refcount/fn_ptr_stdlib_compare.rs index e5bc3877..53c82c00 100644 --- a/tests/unit/out/refcount/fn_ptr_stdlib_compare.rs +++ b/tests/unit/out/refcount/fn_ptr_stdlib_compare.rs @@ -13,6 +13,13 @@ pub fn my_alternative_fread_0(p: Ptr, n: u64, m: u64, f: AnyPtr) -> u64 { let f: Value = Rc::new(RefCell::new(f)); return 22_u64; } +pub fn my_alternative_fwrite_1(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 33_u64; +} pub fn main() { std::process::exit(main_0()); } @@ -177,5 +184,150 @@ fn main_0() -> i32 { break; } } + let gn1: Value) -> u64>> = + Rc::new(RefCell::new(FnPtr::< + fn(AnyPtr, u64, u64, Ptr<::std::fs::File>) -> u64, + >::new(libcc2rs::fwrite_refcount))); + assert!({ + let _lhs = (*gn1.borrow()).clone(); + _lhs == FnPtr::) -> u64>::new( + libcc2rs::fwrite_refcount, + ) + }); + assert!(!((*gn1.borrow()).is_null())); + let gn2: Value, u64, u64, AnyPtr) -> u64>> = Rc::new(RefCell::new( + FnPtr::) -> u64>::new(libcc2rs::fwrite_refcount) + .cast::, u64, u64, AnyPtr) -> u64>(Some( + (|a0: Ptr, a1: u64, a2: u64, a3: AnyPtr| -> u64 { + libcc2rs::fwrite_refcount( + a0.to_any(), + a1, + a2, + a3.cast::<::std::fs::File>().unwrap(), + ) + }) as fn(Ptr, u64, u64, AnyPtr) -> u64, + )), + )); + assert!({ + let _lhs = (*gn1.borrow()).clone(); + _lhs == ((*gn2.borrow()).cast::) -> u64>(None)) + .clone() + }); + let g3: Value) -> u64>> = + Rc::new(RefCell::new( + FnPtr::, u64, u64, AnyPtr) -> u64>::new(my_alternative_fwrite_1).cast::, + ) + -> u64>( + Some( + (|a0: AnyPtr, a1: u64, a2: u64, a3: Ptr<::std::fs::File>| -> u64 { + my_alternative_fwrite_1(a0.cast::().unwrap(), a1, a2, a3.to_any()) + }) as fn(AnyPtr, u64, u64, Ptr<::std::fs::File>) -> u64, + ), + ), + )); + assert!( + (({ + let _arg0: AnyPtr = AnyPtr::default(); + let _arg1: u64 = 0_u64; + let _arg2: u64 = 0_u64; + let _arg3: Ptr<::std::fs::File> = Ptr::<::std::fs::File>::null(); + (*(*g3.borrow()))(_arg0, _arg1, _arg2, _arg3) + }) == 33_u64) + ); + 'loop_: loop { + let stream: Value> = Rc::new(RefCell::new( + match Ptr::from_string_literal("wb").to_rust_string() { + v if v == "rb" => std::fs::OpenOptions::new() + .read(true) + .open(Ptr::from_string_literal("/dev/null").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/null").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..10).map(|_| ::default()).collect::>(), + )); + { + ((buf.as_pointer() as Ptr) as Ptr).to_any().memset( + (('Y' as u8) as i32) as u8, + ::std::mem::size_of::<[u8; 10]>() as u64 as usize, + ); + ((buf.as_pointer() as Ptr) as Ptr).to_any().clone() + }; + let n: Value = Rc::new(RefCell::new(libcc2rs::fwrite_refcount( + ((buf.as_pointer() as Ptr) as Ptr).to_any(), + 1_u64, + 10_u64, + (*stream.borrow()).clone(), + ))); + assert!(((*n.borrow()) == 10_u64)); + { + (*stream.borrow()).delete(); + 0 + }; + if !(0 != 0) { + break; + } + } + 'loop_: loop { + let stream: Value> = Rc::new(RefCell::new( + match Ptr::from_string_literal("wb").to_rust_string() { + v if v == "rb" => std::fs::OpenOptions::new() + .read(true) + .open(Ptr::from_string_literal("/dev/null").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/null").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..10).map(|_| ::default()).collect::>(), + )); + { + ((buf.as_pointer() as Ptr) as Ptr).to_any().memset( + (('Y' as u8) as i32) as u8, + ::std::mem::size_of::<[u8; 10]>() 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(); + (*(*gn1.borrow()))(_arg0, _arg1, _arg2, _arg3) + }), + )); + assert!(((*n.borrow()) == 10_u64)); + { + (*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 index a3165261..aa223c99 100644 --- a/tests/unit/out/unsafe/fn_ptr_stdlib_compare.rs +++ b/tests/unit/out/unsafe/fn_ptr_stdlib_compare.rs @@ -14,6 +14,14 @@ pub unsafe fn my_alternative_fread_0( ) -> u64 { return 22_u64; } +pub unsafe fn my_alternative_fwrite_1( + mut p: *const u8, + mut n: u64, + mut m: u64, + mut f: *mut ::libc::c_void, +) -> u64 { + return 33_u64; +} pub fn main() { unsafe { std::process::exit(main_0() as i32); @@ -87,14 +95,12 @@ unsafe fn main_0() -> i32 { } (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, - ) - }; + let mut n: u64 = 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)) { @@ -177,5 +183,141 @@ unsafe fn main_0() -> i32 { break; } } + let mut gn1: Option u64> = + Some(libcc2rs::fwrite_unsafe); + assert!(((gn1) == (Some(libcc2rs::fwrite_unsafe)))); + assert!(!((gn1).is_none())); + let mut gn2: Option u64> = + std::mem::transmute::< + Option u64>, + Option u64>, + >(Some(libcc2rs::fwrite_unsafe)); + assert!( + ((gn1) + == (std::mem::transmute::< + Option u64>, + Option u64>, + >(gn2))) + ); + let mut g3: Option u64> = + std::mem::transmute::< + Option u64>, + Option u64>, + >(Some(my_alternative_fwrite_1)); + assert!( + ((unsafe { + let _arg0: *const ::libc::c_void = std::ptr::null(); + let _arg1: u64 = 0_u64; + let _arg2: u64 = 0_u64; + let _arg3: *mut ::std::fs::File = std::ptr::null_mut(); + (g3).unwrap()(_arg0, _arg1, _arg2, _arg3) + }) == (33_u64)) + ); + 'loop_: loop { + let mut stream: *mut ::std::fs::File = + match std::ffi::CStr::from_ptr(b"wb\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/null\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/null\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; 10] = [0_u8; 10]; + { + 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; 10]>() as u64 { + *byte_0.offset(offset as isize) = (('Y' as u8) as i32) as u8; + } + (buf.as_mut_ptr() as *mut u8 as *mut ::libc::c_void) + }; + let mut n: u64 = libcc2rs::fwrite_unsafe( + (buf.as_mut_ptr() as *const u8 as *const ::libc::c_void) as *const ::std::ffi::c_void, + 1_u64, + 10_u64, + stream, + ); + assert!(((n) == (10_u64))); + { + 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"wb\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/null\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/null\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; 10] = [0_u8; 10]; + { + 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; 10]>() as u64 { + *byte_0.offset(offset as isize) = (('Y' 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: *const ::libc::c_void = + (buf.as_mut_ptr() as *const u8 as *const ::libc::c_void); + let _arg1: u64 = 1_u64; + let _arg2: u64 = 10_u64; + let _arg3: *mut ::std::fs::File = stream; + (gn1).unwrap()(_arg0, _arg1, _arg2, _arg3) + }); + assert!(((n) == (10_u64))); + { + Box::from_raw(stream); + 0 + }; + if !(0 != 0) { + break; + } + } return 0; }