diff --git a/libcc2rs/Cargo.toml b/libcc2rs/Cargo.toml index 6370ac02..a1761abf 100644 --- a/libcc2rs/Cargo.toml +++ b/libcc2rs/Cargo.toml @@ -8,3 +8,4 @@ libcc2rs-macros = { path = "../libcc2rs-macros", version = "0.1.0" } libc = "0.2" nix = { version = "0.30", features = ["socket", "net", "fs", "poll", "time", "user", "dir", "term", "event", "hostname"] } jiff = "0.2" +sprintf = "0.4" diff --git a/libcc2rs/src/format.rs b/libcc2rs/src/format.rs new file mode 100644 index 00000000..d33eb062 --- /dev/null +++ b/libcc2rs/src/format.rs @@ -0,0 +1,64 @@ +// Copyright (c) 2022-present INESC-ID. +// Distributed under the MIT license that can be found in the LICENSE file. + +use sprintf::parser::{ConversionType, FormatElement, parse_format_string}; +use sprintf::{Printf, vsprintfp}; + +use crate::va_args::{VaArg, VaArgGet}; + +pub fn format_c(fmt: &str, va: &[VaArg]) -> String { + let elements = match parse_format_string(fmt) { + Ok(elements) => elements, + Err(e) => panic!("format_c: cannot parse {fmt:?}: {e:?}"), + }; + let mut args: Vec> = Vec::new(); + let mut pos = 0; + for element in &elements { + if let FormatElement::Format(spec) = element { + if spec.conversion_type == ConversionType::PercentSign { + continue; + } + let arg = &va[pos]; + args.push(match spec.conversion_type { + ConversionType::DecInt => match arg { + VaArg::Int(v) => Box::new(*v), + VaArg::UInt(v) => Box::new(*v), + VaArg::Long(v) => Box::new(*v), + VaArg::ULong(v) => Box::new(*v), + _ => panic!("format_c: integer conversion expects an integer argument"), + }, + ConversionType::OctInt + | ConversionType::HexIntLower + | ConversionType::HexIntUpper => match arg { + VaArg::Int(v) => Box::new(*v as u32), + VaArg::UInt(v) => Box::new(*v), + VaArg::Long(v) => Box::new(*v as u64), + VaArg::ULong(v) => Box::new(*v), + VaArg::Ptr(p) => Box::new(p.to_int()), + VaArg::RawPtr(v) => Box::new(*v as usize), + VaArg::Double(_) => { + panic!("format_c: integer conversion expects an integer argument") + } + }, + ConversionType::Char => Box::new(i32::get(arg) as u8 as char), + ConversionType::String => match arg { + VaArg::Ptr(v) => Box::new(v.reinterpret_cast::().to_rust_string()), + _ => panic!("format_c: %s expects a string argument"), + }, + ConversionType::DecFloatLower + | ConversionType::DecFloatUpper + | ConversionType::SciFloatLower + | ConversionType::SciFloatUpper + | ConversionType::CompactFloatLower + | ConversionType::CompactFloatUpper => Box::new(f64::get(arg)), + ConversionType::PercentSign => panic!("format_c: %% consumes no argument"), + }); + pos += 1; + } + } + let refs: Vec<&dyn Printf> = args.iter().map(|arg| arg.as_ref()).collect(); + match vsprintfp(&elements, &refs) { + Ok(s) => s, + Err(e) => panic!("format_c: cannot format {fmt:?}: {e:?}"), + } +} diff --git a/libcc2rs/src/lib.rs b/libcc2rs/src/lib.rs index e9046a7f..f2e5b6fd 100644 --- a/libcc2rs/src/lib.rs +++ b/libcc2rs/src/lib.rs @@ -37,4 +37,7 @@ pub use compat::*; mod va_args; pub use va_args::*; +mod format; +pub use format::*; + pub use libcc2rs_macros::{goto, goto_block, switch}; diff --git a/rules/stdio/tgt_refcount.rs b/rules/stdio/tgt_refcount.rs index 0dba24cb..94a1a879 100644 --- a/rules/stdio/tgt_refcount.rs +++ b/rules/stdio/tgt_refcount.rs @@ -214,13 +214,16 @@ fn f19(a0: Ptr<::std::fs::File>, a1: i64, a2: i32) -> i32 { } fn f21(a0: Ptr, a1: usize, a2: Ptr, va: &[VaArg]) -> i32 { - panic!( - "snprintf is not supported in the refcount model (buf_is_null={}, size={}, fmt={:?}, varargs={})", - a0.is_null(), - a1, - a2.to_rust_string(), - va.len() - ) + let __s = libcc2rs::format_c(&a2.to_rust_string(), va); + let __b = __s.as_bytes(); + if a1 > 0 { + let __n = ::std::cmp::min(__b.len(), a1 - 1); + a0.with_slice_mut(__n + 1, |__dst| { + __dst[..__n].copy_from_slice(&__b[..__n]); + __dst[__n] = 0; + }); + } + __b.len() as i32 } fn f22(a0: Ptr, a1: Ptr) -> i32 { diff --git a/tests/unit/out/refcount/snprintf.rs b/tests/unit/out/refcount/snprintf.rs new file mode 100644 index 00000000..70b92fce --- /dev/null +++ b/tests/unit/out/refcount/snprintf.rs @@ -0,0 +1,431 @@ +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 main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let buf: Value> = Rc::new(RefCell::new( + (0..32).map(|_| ::default()).collect::>(), + )); + assert!( + ((({ + let __s = libcc2rs::format_c( + &Ptr::from_string_literal(b"x=%d y=%u").to_rust_string(), + &[(-3_i32).into(), (7_u32).into()], + ); + let __b = __s.as_bytes(); + if ::std::mem::size_of::<[u8; 32]>() > 0 { + let __n = ::std::cmp::min(__b.len(), ::std::mem::size_of::<[u8; 32]>() - 1); + (buf.as_pointer() as Ptr).with_slice_mut(__n + 1, |__dst| { + __dst[..__n].copy_from_slice(&__b[..__n]); + __dst[__n] = 0; + }); + } + __b.len() as i32 + } == 8) as i32) + != 0) + ); + assert!( + ((({ + let mut __it1 = (buf.as_pointer() as Ptr).to_c_string_iterator(); + let mut __it2 = Ptr::from_string_literal(b"x=-3 y=7").to_c_string_iterator(); + loop { + let __c1 = __it1.next(); + let __c2 = __it2.next(); + if __c1 != __c2 { + break (__c1.unwrap_or(0) as i32) - (__c2.unwrap_or(0) as i32); + } + if __c1.is_none() { + break 0; + } + } + } == 0) as i32) + != 0) + ); + assert!( + ((({ + let __s = libcc2rs::format_c( + &Ptr::from_string_literal(b"%s").to_rust_string(), + &[(Ptr::from_string_literal(b"hello")).into()], + ); + let __b = __s.as_bytes(); + if 4_usize > 0 { + let __n = ::std::cmp::min(__b.len(), 4_usize - 1); + (buf.as_pointer() as Ptr).with_slice_mut(__n + 1, |__dst| { + __dst[..__n].copy_from_slice(&__b[..__n]); + __dst[__n] = 0; + }); + } + __b.len() as i32 + } == 5) as i32) + != 0) + ); + assert!( + ((({ + let mut __it1 = (buf.as_pointer() as Ptr).to_c_string_iterator(); + let mut __it2 = Ptr::from_string_literal(b"hel").to_c_string_iterator(); + loop { + let __c1 = __it1.next(); + let __c2 = __it2.next(); + if __c1 != __c2 { + break (__c1.unwrap_or(0) as i32) - (__c2.unwrap_or(0) as i32); + } + if __c1.is_none() { + break 0; + } + } + } == 0) as i32) + != 0) + ); + assert!( + ((({ + let __s = libcc2rs::format_c( + &Ptr::from_string_literal(b"%05d|%x|%X").to_rust_string(), + &[(42).into(), (255).into(), (255).into()], + ); + let __b = __s.as_bytes(); + if ::std::mem::size_of::<[u8; 32]>() > 0 { + let __n = ::std::cmp::min(__b.len(), ::std::mem::size_of::<[u8; 32]>() - 1); + (buf.as_pointer() as Ptr).with_slice_mut(__n + 1, |__dst| { + __dst[..__n].copy_from_slice(&__b[..__n]); + __dst[__n] = 0; + }); + } + __b.len() as i32 + } == 11) as i32) + != 0) + ); + assert!( + ((({ + let mut __it1 = (buf.as_pointer() as Ptr).to_c_string_iterator(); + let mut __it2 = Ptr::from_string_literal(b"00042|ff|FF").to_c_string_iterator(); + loop { + let __c1 = __it1.next(); + let __c2 = __it2.next(); + if __c1 != __c2 { + break (__c1.unwrap_or(0) as i32) - (__c2.unwrap_or(0) as i32); + } + if __c1.is_none() { + break 0; + } + } + } == 0) as i32) + != 0) + ); + assert!( + ((({ + let __s = libcc2rs::format_c( + &Ptr::from_string_literal(b"%.2f").to_rust_string(), + &[(3.14159E+0).into()], + ); + let __b = __s.as_bytes(); + if ::std::mem::size_of::<[u8; 32]>() > 0 { + let __n = ::std::cmp::min(__b.len(), ::std::mem::size_of::<[u8; 32]>() - 1); + (buf.as_pointer() as Ptr).with_slice_mut(__n + 1, |__dst| { + __dst[..__n].copy_from_slice(&__b[..__n]); + __dst[__n] = 0; + }); + } + __b.len() as i32 + } == 4) as i32) + != 0) + ); + assert!( + ((({ + let mut __it1 = (buf.as_pointer() as Ptr).to_c_string_iterator(); + let mut __it2 = Ptr::from_string_literal(b"3.14").to_c_string_iterator(); + loop { + let __c1 = __it1.next(); + let __c2 = __it2.next(); + if __c1 != __c2 { + break (__c1.unwrap_or(0) as i32) - (__c2.unwrap_or(0) as i32); + } + if __c1.is_none() { + break 0; + } + } + } == 0) as i32) + != 0) + ); + assert!( + ((({ + let __s = libcc2rs::format_c( + &Ptr::from_string_literal(b"%-6s|").to_rust_string(), + &[(Ptr::from_string_literal(b"ab")).into()], + ); + let __b = __s.as_bytes(); + if ::std::mem::size_of::<[u8; 32]>() > 0 { + let __n = ::std::cmp::min(__b.len(), ::std::mem::size_of::<[u8; 32]>() - 1); + (buf.as_pointer() as Ptr).with_slice_mut(__n + 1, |__dst| { + __dst[..__n].copy_from_slice(&__b[..__n]); + __dst[__n] = 0; + }); + } + __b.len() as i32 + } == 7) as i32) + != 0) + ); + assert!( + ((({ + let mut __it1 = (buf.as_pointer() as Ptr).to_c_string_iterator(); + let mut __it2 = Ptr::from_string_literal(b"ab |").to_c_string_iterator(); + loop { + let __c1 = __it1.next(); + let __c2 = __it2.next(); + if __c1 != __c2 { + break (__c1.unwrap_or(0) as i32) - (__c2.unwrap_or(0) as i32); + } + if __c1.is_none() { + break 0; + } + } + } == 0) as i32) + != 0) + ); + assert!( + ((({ + let __s = libcc2rs::format_c( + &Ptr::from_string_literal(b"%c%%").to_rust_string(), + &[(65).into()], + ); + let __b = __s.as_bytes(); + if ::std::mem::size_of::<[u8; 32]>() > 0 { + let __n = ::std::cmp::min(__b.len(), ::std::mem::size_of::<[u8; 32]>() - 1); + (buf.as_pointer() as Ptr).with_slice_mut(__n + 1, |__dst| { + __dst[..__n].copy_from_slice(&__b[..__n]); + __dst[__n] = 0; + }); + } + __b.len() as i32 + } == 2) as i32) + != 0) + ); + assert!( + ((({ + let mut __it1 = (buf.as_pointer() as Ptr).to_c_string_iterator(); + let mut __it2 = Ptr::from_string_literal(b"A%").to_c_string_iterator(); + loop { + let __c1 = __it1.next(); + let __c2 = __it2.next(); + if __c1 != __c2 { + break (__c1.unwrap_or(0) as i32) - (__c2.unwrap_or(0) as i32); + } + if __c1.is_none() { + break 0; + } + } + } == 0) as i32) + != 0) + ); + assert!( + ((({ + let __s = libcc2rs::format_c( + &Ptr::from_string_literal(b"%+d % d").to_rust_string(), + &[(5).into(), (5).into()], + ); + let __b = __s.as_bytes(); + if ::std::mem::size_of::<[u8; 32]>() > 0 { + let __n = ::std::cmp::min(__b.len(), ::std::mem::size_of::<[u8; 32]>() - 1); + (buf.as_pointer() as Ptr).with_slice_mut(__n + 1, |__dst| { + __dst[..__n].copy_from_slice(&__b[..__n]); + __dst[__n] = 0; + }); + } + __b.len() as i32 + } == 5) as i32) + != 0) + ); + assert!( + ((({ + let mut __it1 = (buf.as_pointer() as Ptr).to_c_string_iterator(); + let mut __it2 = Ptr::from_string_literal(b"+5 5").to_c_string_iterator(); + loop { + let __c1 = __it1.next(); + let __c2 = __it2.next(); + if __c1 != __c2 { + break (__c1.unwrap_or(0) as i32) - (__c2.unwrap_or(0) as i32); + } + if __c1.is_none() { + break 0; + } + } + } == 0) as i32) + != 0) + ); + assert!( + ((({ + let __s = libcc2rs::format_c( + &Ptr::from_string_literal(b"%ld %lu %zu").to_rust_string(), + &[(-1_i64).into(), (1_u64).into(), (9 as usize).into()], + ); + let __b = __s.as_bytes(); + if ::std::mem::size_of::<[u8; 32]>() > 0 { + let __n = ::std::cmp::min(__b.len(), ::std::mem::size_of::<[u8; 32]>() - 1); + (buf.as_pointer() as Ptr).with_slice_mut(__n + 1, |__dst| { + __dst[..__n].copy_from_slice(&__b[..__n]); + __dst[__n] = 0; + }); + } + __b.len() as i32 + } == 6) as i32) + != 0) + ); + assert!( + ((({ + let mut __it1 = (buf.as_pointer() as Ptr).to_c_string_iterator(); + let mut __it2 = Ptr::from_string_literal(b"-1 1 9").to_c_string_iterator(); + loop { + let __c1 = __it1.next(); + let __c2 = __it2.next(); + if __c1 != __c2 { + break (__c1.unwrap_or(0) as i32) - (__c2.unwrap_or(0) as i32); + } + if __c1.is_none() { + break 0; + } + } + } == 0) as i32) + != 0) + ); + assert!( + ((({ + let __s = libcc2rs::format_c( + &Ptr::from_string_literal(b"%e").to_rust_string(), + &[(1.2345678E+3).into()], + ); + let __b = __s.as_bytes(); + if ::std::mem::size_of::<[u8; 32]>() > 0 { + let __n = ::std::cmp::min(__b.len(), ::std::mem::size_of::<[u8; 32]>() - 1); + (buf.as_pointer() as Ptr).with_slice_mut(__n + 1, |__dst| { + __dst[..__n].copy_from_slice(&__b[..__n]); + __dst[__n] = 0; + }); + } + __b.len() as i32 + } == 12) as i32) + != 0) + ); + assert!( + ((({ + let mut __it1 = (buf.as_pointer() as Ptr).to_c_string_iterator(); + let mut __it2 = Ptr::from_string_literal(b"1.234568e+03").to_c_string_iterator(); + loop { + let __c1 = __it1.next(); + let __c2 = __it2.next(); + if __c1 != __c2 { + break (__c1.unwrap_or(0) as i32) - (__c2.unwrap_or(0) as i32); + } + if __c1.is_none() { + break 0; + } + } + } == 0) as i32) + != 0) + ); + assert!( + ((({ + let __s = libcc2rs::format_c( + &Ptr::from_string_literal(b"%g").to_rust_string(), + &[(1.234567E+6).into()], + ); + let __b = __s.as_bytes(); + if ::std::mem::size_of::<[u8; 32]>() > 0 { + let __n = ::std::cmp::min(__b.len(), ::std::mem::size_of::<[u8; 32]>() - 1); + (buf.as_pointer() as Ptr).with_slice_mut(__n + 1, |__dst| { + __dst[..__n].copy_from_slice(&__b[..__n]); + __dst[__n] = 0; + }); + } + __b.len() as i32 + } == 11) as i32) + != 0) + ); + assert!( + ((({ + let mut __it1 = (buf.as_pointer() as Ptr).to_c_string_iterator(); + let mut __it2 = Ptr::from_string_literal(b"1.23457e+06").to_c_string_iterator(); + loop { + let __c1 = __it1.next(); + let __c2 = __it2.next(); + if __c1 != __c2 { + break (__c1.unwrap_or(0) as i32) - (__c2.unwrap_or(0) as i32); + } + if __c1.is_none() { + break 0; + } + } + } == 0) as i32) + != 0) + ); + (*buf.borrow_mut())[(0) as usize] = (('Z' as i32) as u8); + assert!( + ((({ + let __s = libcc2rs::format_c( + &Ptr::from_string_literal(b"%d").to_rust_string(), + &[(123).into()], + ); + let __b = __s.as_bytes(); + if 0_usize > 0 { + let __n = ::std::cmp::min(__b.len(), 0_usize - 1); + (buf.as_pointer() as Ptr).with_slice_mut(__n + 1, |__dst| { + __dst[..__n].copy_from_slice(&__b[..__n]); + __dst[__n] = 0; + }); + } + __b.len() as i32 + } == 3) as i32) + != 0) + ); + assert!((((((*buf.borrow())[(0) as usize] as i32) == ('Z' as i32)) as i32) != 0)); + let fmt: Value> = Rc::new(RefCell::new( + (0..8).map(|_| ::default()).collect::>(), + )); + (*fmt.borrow_mut())[(0) as usize] = (('%' as i32) as u8); + (*fmt.borrow_mut())[(1) as usize] = (('5' as i32) as u8); + (*fmt.borrow_mut())[(2) as usize] = (('.' as i32) as u8); + (*fmt.borrow_mut())[(3) as usize] = (('1' as i32) as u8); + (*fmt.borrow_mut())[(4) as usize] = (('f' as i32) as u8); + (*fmt.borrow_mut())[(5) as usize] = 0_u8; + assert!( + ((({ + let __s = libcc2rs::format_c( + &(fmt.as_pointer() as Ptr).to_rust_string(), + &[(3.26E+0).into()], + ); + let __b = __s.as_bytes(); + if ::std::mem::size_of::<[u8; 32]>() > 0 { + let __n = ::std::cmp::min(__b.len(), ::std::mem::size_of::<[u8; 32]>() - 1); + (buf.as_pointer() as Ptr).with_slice_mut(__n + 1, |__dst| { + __dst[..__n].copy_from_slice(&__b[..__n]); + __dst[__n] = 0; + }); + } + __b.len() as i32 + } == 5) as i32) + != 0) + ); + assert!( + ((({ + let mut __it1 = (buf.as_pointer() as Ptr).to_c_string_iterator(); + let mut __it2 = Ptr::from_string_literal(b" 3.3").to_c_string_iterator(); + loop { + let __c1 = __it1.next(); + let __c2 = __it2.next(); + if __c1 != __c2 { + break (__c1.unwrap_or(0) as i32) - (__c2.unwrap_or(0) as i32); + } + if __c1.is_none() { + break 0; + } + } + } == 0) as i32) + != 0) + ); + return 0; +} diff --git a/tests/unit/out/unsafe/snprintf.rs b/tests/unit/out/unsafe/snprintf.rs new file mode 100644 index 00000000..c8bfbe46 --- /dev/null +++ b/tests/unit/out/unsafe/snprintf.rs @@ -0,0 +1,241 @@ +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 buf: [libc::c_char; 32] = [(0 as libc::c_char); 32]; + assert!( + ((((unsafe { + libc::snprintf( + buf.as_mut_ptr() as *mut libc::c_char, + ::std::mem::size_of::<[libc::c_char; 32]>() as usize, + (c"x=%d y=%u".as_ptr().cast_mut()).cast_const() as *const libc::c_char, + (-3_i32), + (7_u32), + ) + }) == (8)) as i32) + != 0) + ); + assert!( + ((((libc::strcmp( + (buf.as_mut_ptr()).cast_const(), + (c"x=-3 y=7".as_ptr().cast_mut()).cast_const() + )) == (0)) as i32) + != 0) + ); + assert!( + ((((unsafe { + libc::snprintf( + buf.as_mut_ptr() as *mut libc::c_char, + 4_usize as usize, + (c"%s".as_ptr().cast_mut()).cast_const() as *const libc::c_char, + (c"hello".as_ptr().cast_mut()), + ) + }) == (5)) as i32) + != 0) + ); + assert!( + ((((libc::strcmp( + (buf.as_mut_ptr()).cast_const(), + (c"hel".as_ptr().cast_mut()).cast_const() + )) == (0)) as i32) + != 0) + ); + assert!( + ((((unsafe { + libc::snprintf( + buf.as_mut_ptr() as *mut libc::c_char, + ::std::mem::size_of::<[libc::c_char; 32]>() as usize, + (c"%05d|%x|%X".as_ptr().cast_mut()).cast_const() as *const libc::c_char, + (42), + (255), + (255), + ) + }) == (11)) as i32) + != 0) + ); + assert!( + ((((libc::strcmp( + (buf.as_mut_ptr()).cast_const(), + (c"00042|ff|FF".as_ptr().cast_mut()).cast_const() + )) == (0)) as i32) + != 0) + ); + assert!( + ((((unsafe { + libc::snprintf( + buf.as_mut_ptr() as *mut libc::c_char, + ::std::mem::size_of::<[libc::c_char; 32]>() as usize, + (c"%.2f".as_ptr().cast_mut()).cast_const() as *const libc::c_char, + (3.14159E+0), + ) + }) == (4)) as i32) + != 0) + ); + assert!( + ((((libc::strcmp( + (buf.as_mut_ptr()).cast_const(), + (c"3.14".as_ptr().cast_mut()).cast_const() + )) == (0)) as i32) + != 0) + ); + assert!( + ((((unsafe { + libc::snprintf( + buf.as_mut_ptr() as *mut libc::c_char, + ::std::mem::size_of::<[libc::c_char; 32]>() as usize, + (c"%-6s|".as_ptr().cast_mut()).cast_const() as *const libc::c_char, + (c"ab".as_ptr().cast_mut()), + ) + }) == (7)) as i32) + != 0) + ); + assert!( + ((((libc::strcmp( + (buf.as_mut_ptr()).cast_const(), + (c"ab |".as_ptr().cast_mut()).cast_const() + )) == (0)) as i32) + != 0) + ); + assert!( + ((((unsafe { + libc::snprintf( + buf.as_mut_ptr() as *mut libc::c_char, + ::std::mem::size_of::<[libc::c_char; 32]>() as usize, + (c"%c%%".as_ptr().cast_mut()).cast_const() as *const libc::c_char, + (65), + ) + }) == (2)) as i32) + != 0) + ); + assert!( + ((((libc::strcmp( + (buf.as_mut_ptr()).cast_const(), + (c"A%".as_ptr().cast_mut()).cast_const() + )) == (0)) as i32) + != 0) + ); + assert!( + ((((unsafe { + libc::snprintf( + buf.as_mut_ptr() as *mut libc::c_char, + ::std::mem::size_of::<[libc::c_char; 32]>() as usize, + (c"%+d % d".as_ptr().cast_mut()).cast_const() as *const libc::c_char, + (5), + (5), + ) + }) == (5)) as i32) + != 0) + ); + assert!( + ((((libc::strcmp( + (buf.as_mut_ptr()).cast_const(), + (c"+5 5".as_ptr().cast_mut()).cast_const() + )) == (0)) as i32) + != 0) + ); + assert!( + ((((unsafe { + libc::snprintf( + buf.as_mut_ptr() as *mut libc::c_char, + ::std::mem::size_of::<[libc::c_char; 32]>() as usize, + (c"%ld %lu %zu".as_ptr().cast_mut()).cast_const() as *const libc::c_char, + (-1_i64), + (1_u64), + (9 as usize), + ) + }) == (6)) as i32) + != 0) + ); + assert!( + ((((libc::strcmp( + (buf.as_mut_ptr()).cast_const(), + (c"-1 1 9".as_ptr().cast_mut()).cast_const() + )) == (0)) as i32) + != 0) + ); + assert!( + ((((unsafe { + libc::snprintf( + buf.as_mut_ptr() as *mut libc::c_char, + ::std::mem::size_of::<[libc::c_char; 32]>() as usize, + (c"%e".as_ptr().cast_mut()).cast_const() as *const libc::c_char, + (1.2345678E+3), + ) + }) == (12)) as i32) + != 0) + ); + assert!( + ((((libc::strcmp( + (buf.as_mut_ptr()).cast_const(), + (c"1.234568e+03".as_ptr().cast_mut()).cast_const() + )) == (0)) as i32) + != 0) + ); + assert!( + ((((unsafe { + libc::snprintf( + buf.as_mut_ptr() as *mut libc::c_char, + ::std::mem::size_of::<[libc::c_char; 32]>() as usize, + (c"%g".as_ptr().cast_mut()).cast_const() as *const libc::c_char, + (1.234567E+6), + ) + }) == (11)) as i32) + != 0) + ); + assert!( + ((((libc::strcmp( + (buf.as_mut_ptr()).cast_const(), + (c"1.23457e+06".as_ptr().cast_mut()).cast_const() + )) == (0)) as i32) + != 0) + ); + buf[(0) as usize] = (('Z' as i32) as libc::c_char); + assert!( + ((((unsafe { + libc::snprintf( + buf.as_mut_ptr() as *mut libc::c_char, + 0_usize as usize, + (c"%d".as_ptr().cast_mut()).cast_const() as *const libc::c_char, + (123), + ) + }) == (3)) as i32) + != 0) + ); + assert!(((((buf[(0) as usize] as i32) == ('Z' as i32)) as i32) != 0)); + let mut fmt: [libc::c_char; 8] = [(0 as libc::c_char); 8]; + fmt[(0) as usize] = (('%' as i32) as libc::c_char); + fmt[(1) as usize] = (('5' as i32) as libc::c_char); + fmt[(2) as usize] = (('.' as i32) as libc::c_char); + fmt[(3) as usize] = (('1' as i32) as libc::c_char); + fmt[(4) as usize] = (('f' as i32) as libc::c_char); + fmt[(5) as usize] = (0 as libc::c_char); + assert!( + ((((unsafe { + libc::snprintf( + buf.as_mut_ptr() as *mut libc::c_char, + ::std::mem::size_of::<[libc::c_char; 32]>() as usize, + (fmt.as_mut_ptr()).cast_const() as *const libc::c_char, + (3.26E+0), + ) + }) == (5)) as i32) + != 0) + ); + assert!( + ((((libc::strcmp( + (buf.as_mut_ptr()).cast_const(), + (c" 3.3".as_ptr().cast_mut()).cast_const() + )) == (0)) as i32) + != 0) + ); + return 0; +} diff --git a/tests/unit/snprintf.c b/tests/unit/snprintf.c new file mode 100644 index 00000000..f3782662 --- /dev/null +++ b/tests/unit/snprintf.c @@ -0,0 +1,40 @@ +#include +#include +#include + +int main() { + char buf[32]; + assert(snprintf(buf, sizeof(buf), "x=%d y=%u", -3, 7u) == 8); + assert(strcmp(buf, "x=-3 y=7") == 0); + assert(snprintf(buf, 4, "%s", "hello") == 5); + assert(strcmp(buf, "hel") == 0); + assert(snprintf(buf, sizeof(buf), "%05d|%x|%X", 42, 255, 255) == 11); + assert(strcmp(buf, "00042|ff|FF") == 0); + assert(snprintf(buf, sizeof(buf), "%.2f", 3.14159) == 4); + assert(strcmp(buf, "3.14") == 0); + assert(snprintf(buf, sizeof(buf), "%-6s|", "ab") == 7); + assert(strcmp(buf, "ab |") == 0); + assert(snprintf(buf, sizeof(buf), "%c%%", 65) == 2); + assert(strcmp(buf, "A%") == 0); + assert(snprintf(buf, sizeof(buf), "%+d % d", 5, 5) == 5); + assert(strcmp(buf, "+5 5") == 0); + assert(snprintf(buf, sizeof(buf), "%ld %lu %zu", -1L, 1UL, (size_t)9) == 6); + assert(strcmp(buf, "-1 1 9") == 0); + assert(snprintf(buf, sizeof(buf), "%e", 1234.5678) == 12); + assert(strcmp(buf, "1.234568e+03") == 0); + assert(snprintf(buf, sizeof(buf), "%g", 1234567.0) == 11); + assert(strcmp(buf, "1.23457e+06") == 0); + buf[0] = 'Z'; + assert(snprintf(buf, 0, "%d", 123) == 3); + assert(buf[0] == 'Z'); + char fmt[8]; + fmt[0] = '%'; + fmt[1] = '5'; + fmt[2] = '.'; + fmt[3] = '1'; + fmt[4] = 'f'; + fmt[5] = 0; + assert(snprintf(buf, sizeof(buf), fmt, 3.26) == 5); + assert(strcmp(buf, " 3.3") == 0); + return 0; +}