From 2b31e0472fcb97771175b95bb7f2b4fa100e5e66 Mon Sep 17 00:00:00 2001 From: David Anekstein Date: Thu, 10 Aug 2023 14:09:07 -0400 Subject: [PATCH 01/17] add algo_md5.rs --- c2rust-analyze/tests/filecheck.rs | 1 + c2rust-analyze/tests/filecheck/algo_md5.rs | 695 +++++++++++++++++++++ 2 files changed, 696 insertions(+) create mode 100644 c2rust-analyze/tests/filecheck/algo_md5.rs diff --git a/c2rust-analyze/tests/filecheck.rs b/c2rust-analyze/tests/filecheck.rs index 7b5037b743..43525bf850 100644 --- a/c2rust-analyze/tests/filecheck.rs +++ b/c2rust-analyze/tests/filecheck.rs @@ -33,6 +33,7 @@ macro_rules! define_tests { define_tests! { addr_of, aggregate1, + algo_md5, alias1, alias2, alias3, diff --git a/c2rust-analyze/tests/filecheck/algo_md5.rs b/c2rust-analyze/tests/filecheck/algo_md5.rs new file mode 100644 index 0000000000..d428c90343 --- /dev/null +++ b/c2rust-analyze/tests/filecheck/algo_md5.rs @@ -0,0 +1,695 @@ +#![feature(rustc_private)] + +extern crate libc; + +extern "C" { + fn memcpy(_: *mut libc::c_void, _: *const libc::c_void, _: libc::c_ulong) -> *mut libc::c_void; + fn memset(_: *mut libc::c_void, _: libc::c_int, _: libc::c_ulong) -> *mut libc::c_void; +} +pub type __uint32_t = libc::c_uint; +pub type uint32_t = __uint32_t; +#[derive(Copy, Clone)] +#[repr(C)] +pub struct MD5_CTX { + pub state: [uint32_t; 4], + pub count: [uint32_t; 2], + pub buffer: [libc::c_uchar; 64], +} +static mut PADDING: [libc::c_uchar; 64] = [ + 0x80 as libc::c_int as libc::c_uchar, + 0 as libc::c_int as libc::c_uchar, + 0 as libc::c_int as libc::c_uchar, + 0 as libc::c_int as libc::c_uchar, + 0 as libc::c_int as libc::c_uchar, + 0 as libc::c_int as libc::c_uchar, + 0 as libc::c_int as libc::c_uchar, + 0 as libc::c_int as libc::c_uchar, + 0 as libc::c_int as libc::c_uchar, + 0 as libc::c_int as libc::c_uchar, + 0 as libc::c_int as libc::c_uchar, + 0 as libc::c_int as libc::c_uchar, + 0 as libc::c_int as libc::c_uchar, + 0 as libc::c_int as libc::c_uchar, + 0 as libc::c_int as libc::c_uchar, + 0 as libc::c_int as libc::c_uchar, + 0 as libc::c_int as libc::c_uchar, + 0 as libc::c_int as libc::c_uchar, + 0 as libc::c_int as libc::c_uchar, + 0 as libc::c_int as libc::c_uchar, + 0 as libc::c_int as libc::c_uchar, + 0 as libc::c_int as libc::c_uchar, + 0 as libc::c_int as libc::c_uchar, + 0 as libc::c_int as libc::c_uchar, + 0 as libc::c_int as libc::c_uchar, + 0 as libc::c_int as libc::c_uchar, + 0 as libc::c_int as libc::c_uchar, + 0 as libc::c_int as libc::c_uchar, + 0 as libc::c_int as libc::c_uchar, + 0 as libc::c_int as libc::c_uchar, + 0 as libc::c_int as libc::c_uchar, + 0 as libc::c_int as libc::c_uchar, + 0 as libc::c_int as libc::c_uchar, + 0 as libc::c_int as libc::c_uchar, + 0 as libc::c_int as libc::c_uchar, + 0 as libc::c_int as libc::c_uchar, + 0 as libc::c_int as libc::c_uchar, + 0 as libc::c_int as libc::c_uchar, + 0 as libc::c_int as libc::c_uchar, + 0 as libc::c_int as libc::c_uchar, + 0 as libc::c_int as libc::c_uchar, + 0 as libc::c_int as libc::c_uchar, + 0 as libc::c_int as libc::c_uchar, + 0 as libc::c_int as libc::c_uchar, + 0 as libc::c_int as libc::c_uchar, + 0 as libc::c_int as libc::c_uchar, + 0 as libc::c_int as libc::c_uchar, + 0 as libc::c_int as libc::c_uchar, + 0 as libc::c_int as libc::c_uchar, + 0 as libc::c_int as libc::c_uchar, + 0 as libc::c_int as libc::c_uchar, + 0 as libc::c_int as libc::c_uchar, + 0 as libc::c_int as libc::c_uchar, + 0 as libc::c_int as libc::c_uchar, + 0 as libc::c_int as libc::c_uchar, + 0 as libc::c_int as libc::c_uchar, + 0 as libc::c_int as libc::c_uchar, + 0 as libc::c_int as libc::c_uchar, + 0 as libc::c_int as libc::c_uchar, + 0 as libc::c_int as libc::c_uchar, + 0 as libc::c_int as libc::c_uchar, + 0 as libc::c_int as libc::c_uchar, + 0 as libc::c_int as libc::c_uchar, + 0 as libc::c_int as libc::c_uchar, +]; +#[no_mangle] +pub unsafe extern "C" fn MD5_Init(mut context: *mut MD5_CTX) { + (*context).count[1 as libc::c_int as usize] = 0 as libc::c_int as uint32_t; + (*context).count[0 as libc::c_int as usize] = (*context).count[1 as libc::c_int as usize]; + (*context).state[0 as libc::c_int as usize] = 0x67452301 as libc::c_int as uint32_t; + (*context).state[1 as libc::c_int as usize] = 0xefcdab89 as libc::c_uint; + (*context).state[2 as libc::c_int as usize] = 0x98badcfe as libc::c_uint; + (*context).state[3 as libc::c_int as usize] = 0x10325476 as libc::c_int as uint32_t; +} +#[no_mangle] +pub unsafe extern "C" fn MD5_Update( + mut context: *mut MD5_CTX, + mut _input: *const libc::c_void, + mut inputLen: libc::c_uint, +) { + let mut i: libc::c_uint = 0; + let mut ndx: libc::c_uint = 0; + let mut partLen: libc::c_uint = 0; + let mut input: *const libc::c_uchar = _input as *const libc::c_uchar; + ndx = (*context).count[0 as libc::c_int as usize] >> 3 as libc::c_int + & 0x3f as libc::c_int as libc::c_uint; + (*context).count[0 as libc::c_int as usize] = + ((*context).count[0 as libc::c_int as usize] as libc::c_uint) + .wrapping_add(inputLen << 3 as libc::c_int) as uint32_t as uint32_t; + if (*context).count[0 as libc::c_int as usize] < inputLen << 3 as libc::c_int { + (*context).count[1 as libc::c_int as usize] = + ((*context).count[1 as libc::c_int as usize]).wrapping_add(1); + } + (*context).count[1 as libc::c_int as usize] = + ((*context).count[1 as libc::c_int as usize] as libc::c_uint) + .wrapping_add(inputLen >> 29 as libc::c_int) as uint32_t as uint32_t; + partLen = (64 as libc::c_int as libc::c_uint).wrapping_sub(ndx); + if inputLen >= partLen { + memcpy( + &mut *((*context).buffer).as_mut_ptr().offset(ndx as isize) as *mut libc::c_uchar + as *mut libc::c_void, + input as *mut libc::c_uchar as *const libc::c_void, + partLen as libc::c_ulong, + ); + li_MD5Transform( + ((*context).state).as_mut_ptr(), + ((*context).buffer).as_mut_ptr() as *const libc::c_uchar, + ); + i = partLen; + while i.wrapping_add(63 as libc::c_int as libc::c_uint) < inputLen { + li_MD5Transform(((*context).state).as_mut_ptr(), &*input.offset(i as isize)); + i = i.wrapping_add(64 as libc::c_int as libc::c_uint); + } + ndx = 0 as libc::c_int as libc::c_uint; + } else { + i = 0 as libc::c_int as libc::c_uint; + } + memcpy( + &mut *((*context).buffer).as_mut_ptr().offset(ndx as isize) as *mut libc::c_uchar + as *mut libc::c_void, + &*input.offset(i as isize) as *const libc::c_uchar as *mut libc::c_uchar + as *const libc::c_void, + inputLen.wrapping_sub(i) as libc::c_ulong, + ); +} +#[no_mangle] +pub unsafe extern "C" fn MD5_Final(mut digest: *mut libc::c_uchar, mut context: *mut MD5_CTX) { + let mut bits: [libc::c_uchar; 8] = [0; 8]; + let mut ndx: libc::c_uint = 0; + let mut padLen: libc::c_uint = 0; + Encode( + bits.as_mut_ptr(), + ((*context).count).as_mut_ptr(), + 8 as libc::c_int as libc::c_uint, + ); + ndx = (*context).count[0 as libc::c_int as usize] >> 3 as libc::c_int + & 0x3f as libc::c_int as libc::c_uint; + padLen = if ndx < 56 as libc::c_int as libc::c_uint { + (56 as libc::c_int as libc::c_uint).wrapping_sub(ndx) + } else { + (120 as libc::c_int as libc::c_uint).wrapping_sub(ndx) + }; + MD5_Update(context, PADDING.as_mut_ptr() as *const libc::c_void, padLen); + MD5_Update( + context, + bits.as_mut_ptr() as *const libc::c_void, + 8 as libc::c_int as libc::c_uint, + ); + Encode( + digest, + ((*context).state).as_mut_ptr(), + 16 as libc::c_int as libc::c_uint, + ); + memset( + context as *mut libc::c_uchar as *mut libc::c_void, + 0 as libc::c_int, + ::std::mem::size_of::() as libc::c_ulong, + ); +} +unsafe extern "C" fn li_MD5Transform(mut state: *mut uint32_t, mut block: *const libc::c_uchar) { + let mut a: uint32_t = *state.offset(0 as libc::c_int as isize); + let mut b: uint32_t = *state.offset(1 as libc::c_int as isize); + let mut c: uint32_t = *state.offset(2 as libc::c_int as isize); + let mut d: uint32_t = *state.offset(3 as libc::c_int as isize); + let mut x: [uint32_t; 16] = [0; 16]; + Decode(x.as_mut_ptr(), block, 64 as libc::c_int as libc::c_uint); + a = (a as libc::c_uint).wrapping_add( + (b & c | !b & d) + .wrapping_add(x[0 as libc::c_int as usize]) + .wrapping_add(0xd76aa478 as libc::c_uint), + ) as uint32_t as uint32_t; + a = a << 7 as libc::c_int | a >> 32 as libc::c_int - 7 as libc::c_int; + a = (a as libc::c_uint).wrapping_add(b) as uint32_t as uint32_t; + d = (d as libc::c_uint).wrapping_add( + (a & b | !a & c) + .wrapping_add(x[1 as libc::c_int as usize]) + .wrapping_add(0xe8c7b756 as libc::c_uint), + ) as uint32_t as uint32_t; + d = d << 12 as libc::c_int | d >> 32 as libc::c_int - 12 as libc::c_int; + d = (d as libc::c_uint).wrapping_add(a) as uint32_t as uint32_t; + c = (c as libc::c_uint).wrapping_add( + (d & a | !d & b) + .wrapping_add(x[2 as libc::c_int as usize]) + .wrapping_add(0x242070db as libc::c_int as uint32_t), + ) as uint32_t as uint32_t; + c = c << 17 as libc::c_int | c >> 32 as libc::c_int - 17 as libc::c_int; + c = (c as libc::c_uint).wrapping_add(d) as uint32_t as uint32_t; + b = (b as libc::c_uint).wrapping_add( + (c & d | !c & a) + .wrapping_add(x[3 as libc::c_int as usize]) + .wrapping_add(0xc1bdceee as libc::c_uint), + ) as uint32_t as uint32_t; + b = b << 22 as libc::c_int | b >> 32 as libc::c_int - 22 as libc::c_int; + b = (b as libc::c_uint).wrapping_add(c) as uint32_t as uint32_t; + a = (a as libc::c_uint).wrapping_add( + (b & c | !b & d) + .wrapping_add(x[4 as libc::c_int as usize]) + .wrapping_add(0xf57c0faf as libc::c_uint), + ) as uint32_t as uint32_t; + a = a << 7 as libc::c_int | a >> 32 as libc::c_int - 7 as libc::c_int; + a = (a as libc::c_uint).wrapping_add(b) as uint32_t as uint32_t; + d = (d as libc::c_uint).wrapping_add( + (a & b | !a & c) + .wrapping_add(x[5 as libc::c_int as usize]) + .wrapping_add(0x4787c62a as libc::c_int as uint32_t), + ) as uint32_t as uint32_t; + d = d << 12 as libc::c_int | d >> 32 as libc::c_int - 12 as libc::c_int; + d = (d as libc::c_uint).wrapping_add(a) as uint32_t as uint32_t; + c = (c as libc::c_uint).wrapping_add( + (d & a | !d & b) + .wrapping_add(x[6 as libc::c_int as usize]) + .wrapping_add(0xa8304613 as libc::c_uint), + ) as uint32_t as uint32_t; + c = c << 17 as libc::c_int | c >> 32 as libc::c_int - 17 as libc::c_int; + c = (c as libc::c_uint).wrapping_add(d) as uint32_t as uint32_t; + b = (b as libc::c_uint).wrapping_add( + (c & d | !c & a) + .wrapping_add(x[7 as libc::c_int as usize]) + .wrapping_add(0xfd469501 as libc::c_uint), + ) as uint32_t as uint32_t; + b = b << 22 as libc::c_int | b >> 32 as libc::c_int - 22 as libc::c_int; + b = (b as libc::c_uint).wrapping_add(c) as uint32_t as uint32_t; + a = (a as libc::c_uint).wrapping_add( + (b & c | !b & d) + .wrapping_add(x[8 as libc::c_int as usize]) + .wrapping_add(0x698098d8 as libc::c_int as uint32_t), + ) as uint32_t as uint32_t; + a = a << 7 as libc::c_int | a >> 32 as libc::c_int - 7 as libc::c_int; + a = (a as libc::c_uint).wrapping_add(b) as uint32_t as uint32_t; + d = (d as libc::c_uint).wrapping_add( + (a & b | !a & c) + .wrapping_add(x[9 as libc::c_int as usize]) + .wrapping_add(0x8b44f7af as libc::c_uint), + ) as uint32_t as uint32_t; + d = d << 12 as libc::c_int | d >> 32 as libc::c_int - 12 as libc::c_int; + d = (d as libc::c_uint).wrapping_add(a) as uint32_t as uint32_t; + c = (c as libc::c_uint).wrapping_add( + (d & a | !d & b) + .wrapping_add(x[10 as libc::c_int as usize]) + .wrapping_add(0xffff5bb1 as libc::c_uint), + ) as uint32_t as uint32_t; + c = c << 17 as libc::c_int | c >> 32 as libc::c_int - 17 as libc::c_int; + c = (c as libc::c_uint).wrapping_add(d) as uint32_t as uint32_t; + b = (b as libc::c_uint).wrapping_add( + (c & d | !c & a) + .wrapping_add(x[11 as libc::c_int as usize]) + .wrapping_add(0x895cd7be as libc::c_uint), + ) as uint32_t as uint32_t; + b = b << 22 as libc::c_int | b >> 32 as libc::c_int - 22 as libc::c_int; + b = (b as libc::c_uint).wrapping_add(c) as uint32_t as uint32_t; + a = (a as libc::c_uint).wrapping_add( + (b & c | !b & d) + .wrapping_add(x[12 as libc::c_int as usize]) + .wrapping_add(0x6b901122 as libc::c_int as uint32_t), + ) as uint32_t as uint32_t; + a = a << 7 as libc::c_int | a >> 32 as libc::c_int - 7 as libc::c_int; + a = (a as libc::c_uint).wrapping_add(b) as uint32_t as uint32_t; + d = (d as libc::c_uint).wrapping_add( + (a & b | !a & c) + .wrapping_add(x[13 as libc::c_int as usize]) + .wrapping_add(0xfd987193 as libc::c_uint), + ) as uint32_t as uint32_t; + d = d << 12 as libc::c_int | d >> 32 as libc::c_int - 12 as libc::c_int; + d = (d as libc::c_uint).wrapping_add(a) as uint32_t as uint32_t; + c = (c as libc::c_uint).wrapping_add( + (d & a | !d & b) + .wrapping_add(x[14 as libc::c_int as usize]) + .wrapping_add(0xa679438e as libc::c_uint), + ) as uint32_t as uint32_t; + c = c << 17 as libc::c_int | c >> 32 as libc::c_int - 17 as libc::c_int; + c = (c as libc::c_uint).wrapping_add(d) as uint32_t as uint32_t; + b = (b as libc::c_uint).wrapping_add( + (c & d | !c & a) + .wrapping_add(x[15 as libc::c_int as usize]) + .wrapping_add(0x49b40821 as libc::c_int as uint32_t), + ) as uint32_t as uint32_t; + b = b << 22 as libc::c_int | b >> 32 as libc::c_int - 22 as libc::c_int; + b = (b as libc::c_uint).wrapping_add(c) as uint32_t as uint32_t; + a = (a as libc::c_uint).wrapping_add( + (b & d | c & !d) + .wrapping_add(x[1 as libc::c_int as usize]) + .wrapping_add(0xf61e2562 as libc::c_uint), + ) as uint32_t as uint32_t; + a = a << 5 as libc::c_int | a >> 32 as libc::c_int - 5 as libc::c_int; + a = (a as libc::c_uint).wrapping_add(b) as uint32_t as uint32_t; + d = (d as libc::c_uint).wrapping_add( + (a & c | b & !c) + .wrapping_add(x[6 as libc::c_int as usize]) + .wrapping_add(0xc040b340 as libc::c_uint), + ) as uint32_t as uint32_t; + d = d << 9 as libc::c_int | d >> 32 as libc::c_int - 9 as libc::c_int; + d = (d as libc::c_uint).wrapping_add(a) as uint32_t as uint32_t; + c = (c as libc::c_uint).wrapping_add( + (d & b | a & !b) + .wrapping_add(x[11 as libc::c_int as usize]) + .wrapping_add(0x265e5a51 as libc::c_int as uint32_t), + ) as uint32_t as uint32_t; + c = c << 14 as libc::c_int | c >> 32 as libc::c_int - 14 as libc::c_int; + c = (c as libc::c_uint).wrapping_add(d) as uint32_t as uint32_t; + b = (b as libc::c_uint).wrapping_add( + (c & a | d & !a) + .wrapping_add(x[0 as libc::c_int as usize]) + .wrapping_add(0xe9b6c7aa as libc::c_uint), + ) as uint32_t as uint32_t; + b = b << 20 as libc::c_int | b >> 32 as libc::c_int - 20 as libc::c_int; + b = (b as libc::c_uint).wrapping_add(c) as uint32_t as uint32_t; + a = (a as libc::c_uint).wrapping_add( + (b & d | c & !d) + .wrapping_add(x[5 as libc::c_int as usize]) + .wrapping_add(0xd62f105d as libc::c_uint), + ) as uint32_t as uint32_t; + a = a << 5 as libc::c_int | a >> 32 as libc::c_int - 5 as libc::c_int; + a = (a as libc::c_uint).wrapping_add(b) as uint32_t as uint32_t; + d = (d as libc::c_uint).wrapping_add( + (a & c | b & !c) + .wrapping_add(x[10 as libc::c_int as usize]) + .wrapping_add(0x2441453 as libc::c_int as uint32_t), + ) as uint32_t as uint32_t; + d = d << 9 as libc::c_int | d >> 32 as libc::c_int - 9 as libc::c_int; + d = (d as libc::c_uint).wrapping_add(a) as uint32_t as uint32_t; + c = (c as libc::c_uint).wrapping_add( + (d & b | a & !b) + .wrapping_add(x[15 as libc::c_int as usize]) + .wrapping_add(0xd8a1e681 as libc::c_uint), + ) as uint32_t as uint32_t; + c = c << 14 as libc::c_int | c >> 32 as libc::c_int - 14 as libc::c_int; + c = (c as libc::c_uint).wrapping_add(d) as uint32_t as uint32_t; + b = (b as libc::c_uint).wrapping_add( + (c & a | d & !a) + .wrapping_add(x[4 as libc::c_int as usize]) + .wrapping_add(0xe7d3fbc8 as libc::c_uint), + ) as uint32_t as uint32_t; + b = b << 20 as libc::c_int | b >> 32 as libc::c_int - 20 as libc::c_int; + b = (b as libc::c_uint).wrapping_add(c) as uint32_t as uint32_t; + a = (a as libc::c_uint).wrapping_add( + (b & d | c & !d) + .wrapping_add(x[9 as libc::c_int as usize]) + .wrapping_add(0x21e1cde6 as libc::c_int as uint32_t), + ) as uint32_t as uint32_t; + a = a << 5 as libc::c_int | a >> 32 as libc::c_int - 5 as libc::c_int; + a = (a as libc::c_uint).wrapping_add(b) as uint32_t as uint32_t; + d = (d as libc::c_uint).wrapping_add( + (a & c | b & !c) + .wrapping_add(x[14 as libc::c_int as usize]) + .wrapping_add(0xc33707d6 as libc::c_uint), + ) as uint32_t as uint32_t; + d = d << 9 as libc::c_int | d >> 32 as libc::c_int - 9 as libc::c_int; + d = (d as libc::c_uint).wrapping_add(a) as uint32_t as uint32_t; + c = (c as libc::c_uint).wrapping_add( + (d & b | a & !b) + .wrapping_add(x[3 as libc::c_int as usize]) + .wrapping_add(0xf4d50d87 as libc::c_uint), + ) as uint32_t as uint32_t; + c = c << 14 as libc::c_int | c >> 32 as libc::c_int - 14 as libc::c_int; + c = (c as libc::c_uint).wrapping_add(d) as uint32_t as uint32_t; + b = (b as libc::c_uint).wrapping_add( + (c & a | d & !a) + .wrapping_add(x[8 as libc::c_int as usize]) + .wrapping_add(0x455a14ed as libc::c_int as uint32_t), + ) as uint32_t as uint32_t; + b = b << 20 as libc::c_int | b >> 32 as libc::c_int - 20 as libc::c_int; + b = (b as libc::c_uint).wrapping_add(c) as uint32_t as uint32_t; + a = (a as libc::c_uint).wrapping_add( + (b & d | c & !d) + .wrapping_add(x[13 as libc::c_int as usize]) + .wrapping_add(0xa9e3e905 as libc::c_uint), + ) as uint32_t as uint32_t; + a = a << 5 as libc::c_int | a >> 32 as libc::c_int - 5 as libc::c_int; + a = (a as libc::c_uint).wrapping_add(b) as uint32_t as uint32_t; + d = (d as libc::c_uint).wrapping_add( + (a & c | b & !c) + .wrapping_add(x[2 as libc::c_int as usize]) + .wrapping_add(0xfcefa3f8 as libc::c_uint), + ) as uint32_t as uint32_t; + d = d << 9 as libc::c_int | d >> 32 as libc::c_int - 9 as libc::c_int; + d = (d as libc::c_uint).wrapping_add(a) as uint32_t as uint32_t; + c = (c as libc::c_uint).wrapping_add( + (d & b | a & !b) + .wrapping_add(x[7 as libc::c_int as usize]) + .wrapping_add(0x676f02d9 as libc::c_int as uint32_t), + ) as uint32_t as uint32_t; + c = c << 14 as libc::c_int | c >> 32 as libc::c_int - 14 as libc::c_int; + c = (c as libc::c_uint).wrapping_add(d) as uint32_t as uint32_t; + b = (b as libc::c_uint).wrapping_add( + (c & a | d & !a) + .wrapping_add(x[12 as libc::c_int as usize]) + .wrapping_add(0x8d2a4c8a as libc::c_uint), + ) as uint32_t as uint32_t; + b = b << 20 as libc::c_int | b >> 32 as libc::c_int - 20 as libc::c_int; + b = (b as libc::c_uint).wrapping_add(c) as uint32_t as uint32_t; + a = (a as libc::c_uint).wrapping_add( + (b ^ c ^ d) + .wrapping_add(x[5 as libc::c_int as usize]) + .wrapping_add(0xfffa3942 as libc::c_uint), + ) as uint32_t as uint32_t; + a = a << 4 as libc::c_int | a >> 32 as libc::c_int - 4 as libc::c_int; + a = (a as libc::c_uint).wrapping_add(b) as uint32_t as uint32_t; + d = (d as libc::c_uint).wrapping_add( + (a ^ b ^ c) + .wrapping_add(x[8 as libc::c_int as usize]) + .wrapping_add(0x8771f681 as libc::c_uint), + ) as uint32_t as uint32_t; + d = d << 11 as libc::c_int | d >> 32 as libc::c_int - 11 as libc::c_int; + d = (d as libc::c_uint).wrapping_add(a) as uint32_t as uint32_t; + c = (c as libc::c_uint).wrapping_add( + (d ^ a ^ b) + .wrapping_add(x[11 as libc::c_int as usize]) + .wrapping_add(0x6d9d6122 as libc::c_int as uint32_t), + ) as uint32_t as uint32_t; + c = c << 16 as libc::c_int | c >> 32 as libc::c_int - 16 as libc::c_int; + c = (c as libc::c_uint).wrapping_add(d) as uint32_t as uint32_t; + b = (b as libc::c_uint).wrapping_add( + (c ^ d ^ a) + .wrapping_add(x[14 as libc::c_int as usize]) + .wrapping_add(0xfde5380c as libc::c_uint), + ) as uint32_t as uint32_t; + b = b << 23 as libc::c_int | b >> 32 as libc::c_int - 23 as libc::c_int; + b = (b as libc::c_uint).wrapping_add(c) as uint32_t as uint32_t; + a = (a as libc::c_uint).wrapping_add( + (b ^ c ^ d) + .wrapping_add(x[1 as libc::c_int as usize]) + .wrapping_add(0xa4beea44 as libc::c_uint), + ) as uint32_t as uint32_t; + a = a << 4 as libc::c_int | a >> 32 as libc::c_int - 4 as libc::c_int; + a = (a as libc::c_uint).wrapping_add(b) as uint32_t as uint32_t; + d = (d as libc::c_uint).wrapping_add( + (a ^ b ^ c) + .wrapping_add(x[4 as libc::c_int as usize]) + .wrapping_add(0x4bdecfa9 as libc::c_int as uint32_t), + ) as uint32_t as uint32_t; + d = d << 11 as libc::c_int | d >> 32 as libc::c_int - 11 as libc::c_int; + d = (d as libc::c_uint).wrapping_add(a) as uint32_t as uint32_t; + c = (c as libc::c_uint).wrapping_add( + (d ^ a ^ b) + .wrapping_add(x[7 as libc::c_int as usize]) + .wrapping_add(0xf6bb4b60 as libc::c_uint), + ) as uint32_t as uint32_t; + c = c << 16 as libc::c_int | c >> 32 as libc::c_int - 16 as libc::c_int; + c = (c as libc::c_uint).wrapping_add(d) as uint32_t as uint32_t; + b = (b as libc::c_uint).wrapping_add( + (c ^ d ^ a) + .wrapping_add(x[10 as libc::c_int as usize]) + .wrapping_add(0xbebfbc70 as libc::c_uint), + ) as uint32_t as uint32_t; + b = b << 23 as libc::c_int | b >> 32 as libc::c_int - 23 as libc::c_int; + b = (b as libc::c_uint).wrapping_add(c) as uint32_t as uint32_t; + a = (a as libc::c_uint).wrapping_add( + (b ^ c ^ d) + .wrapping_add(x[13 as libc::c_int as usize]) + .wrapping_add(0x289b7ec6 as libc::c_int as uint32_t), + ) as uint32_t as uint32_t; + a = a << 4 as libc::c_int | a >> 32 as libc::c_int - 4 as libc::c_int; + a = (a as libc::c_uint).wrapping_add(b) as uint32_t as uint32_t; + d = (d as libc::c_uint).wrapping_add( + (a ^ b ^ c) + .wrapping_add(x[0 as libc::c_int as usize]) + .wrapping_add(0xeaa127fa as libc::c_uint), + ) as uint32_t as uint32_t; + d = d << 11 as libc::c_int | d >> 32 as libc::c_int - 11 as libc::c_int; + d = (d as libc::c_uint).wrapping_add(a) as uint32_t as uint32_t; + c = (c as libc::c_uint).wrapping_add( + (d ^ a ^ b) + .wrapping_add(x[3 as libc::c_int as usize]) + .wrapping_add(0xd4ef3085 as libc::c_uint), + ) as uint32_t as uint32_t; + c = c << 16 as libc::c_int | c >> 32 as libc::c_int - 16 as libc::c_int; + c = (c as libc::c_uint).wrapping_add(d) as uint32_t as uint32_t; + b = (b as libc::c_uint).wrapping_add( + (c ^ d ^ a) + .wrapping_add(x[6 as libc::c_int as usize]) + .wrapping_add(0x4881d05 as libc::c_int as uint32_t), + ) as uint32_t as uint32_t; + b = b << 23 as libc::c_int | b >> 32 as libc::c_int - 23 as libc::c_int; + b = (b as libc::c_uint).wrapping_add(c) as uint32_t as uint32_t; + a = (a as libc::c_uint).wrapping_add( + (b ^ c ^ d) + .wrapping_add(x[9 as libc::c_int as usize]) + .wrapping_add(0xd9d4d039 as libc::c_uint), + ) as uint32_t as uint32_t; + a = a << 4 as libc::c_int | a >> 32 as libc::c_int - 4 as libc::c_int; + a = (a as libc::c_uint).wrapping_add(b) as uint32_t as uint32_t; + d = (d as libc::c_uint).wrapping_add( + (a ^ b ^ c) + .wrapping_add(x[12 as libc::c_int as usize]) + .wrapping_add(0xe6db99e5 as libc::c_uint), + ) as uint32_t as uint32_t; + d = d << 11 as libc::c_int | d >> 32 as libc::c_int - 11 as libc::c_int; + d = (d as libc::c_uint).wrapping_add(a) as uint32_t as uint32_t; + c = (c as libc::c_uint).wrapping_add( + (d ^ a ^ b) + .wrapping_add(x[15 as libc::c_int as usize]) + .wrapping_add(0x1fa27cf8 as libc::c_int as uint32_t), + ) as uint32_t as uint32_t; + c = c << 16 as libc::c_int | c >> 32 as libc::c_int - 16 as libc::c_int; + c = (c as libc::c_uint).wrapping_add(d) as uint32_t as uint32_t; + b = (b as libc::c_uint).wrapping_add( + (c ^ d ^ a) + .wrapping_add(x[2 as libc::c_int as usize]) + .wrapping_add(0xc4ac5665 as libc::c_uint), + ) as uint32_t as uint32_t; + b = b << 23 as libc::c_int | b >> 32 as libc::c_int - 23 as libc::c_int; + b = (b as libc::c_uint).wrapping_add(c) as uint32_t as uint32_t; + a = (a as libc::c_uint).wrapping_add( + (c ^ (b | !d)) + .wrapping_add(x[0 as libc::c_int as usize]) + .wrapping_add(0xf4292244 as libc::c_uint), + ) as uint32_t as uint32_t; + a = a << 6 as libc::c_int | a >> 32 as libc::c_int - 6 as libc::c_int; + a = (a as libc::c_uint).wrapping_add(b) as uint32_t as uint32_t; + d = (d as libc::c_uint).wrapping_add( + (b ^ (a | !c)) + .wrapping_add(x[7 as libc::c_int as usize]) + .wrapping_add(0x432aff97 as libc::c_int as uint32_t), + ) as uint32_t as uint32_t; + d = d << 10 as libc::c_int | d >> 32 as libc::c_int - 10 as libc::c_int; + d = (d as libc::c_uint).wrapping_add(a) as uint32_t as uint32_t; + c = (c as libc::c_uint).wrapping_add( + (a ^ (d | !b)) + .wrapping_add(x[14 as libc::c_int as usize]) + .wrapping_add(0xab9423a7 as libc::c_uint), + ) as uint32_t as uint32_t; + c = c << 15 as libc::c_int | c >> 32 as libc::c_int - 15 as libc::c_int; + c = (c as libc::c_uint).wrapping_add(d) as uint32_t as uint32_t; + b = (b as libc::c_uint).wrapping_add( + (d ^ (c | !a)) + .wrapping_add(x[5 as libc::c_int as usize]) + .wrapping_add(0xfc93a039 as libc::c_uint), + ) as uint32_t as uint32_t; + b = b << 21 as libc::c_int | b >> 32 as libc::c_int - 21 as libc::c_int; + b = (b as libc::c_uint).wrapping_add(c) as uint32_t as uint32_t; + a = (a as libc::c_uint).wrapping_add( + (c ^ (b | !d)) + .wrapping_add(x[12 as libc::c_int as usize]) + .wrapping_add(0x655b59c3 as libc::c_int as uint32_t), + ) as uint32_t as uint32_t; + a = a << 6 as libc::c_int | a >> 32 as libc::c_int - 6 as libc::c_int; + a = (a as libc::c_uint).wrapping_add(b) as uint32_t as uint32_t; + d = (d as libc::c_uint).wrapping_add( + (b ^ (a | !c)) + .wrapping_add(x[3 as libc::c_int as usize]) + .wrapping_add(0x8f0ccc92 as libc::c_uint), + ) as uint32_t as uint32_t; + d = d << 10 as libc::c_int | d >> 32 as libc::c_int - 10 as libc::c_int; + d = (d as libc::c_uint).wrapping_add(a) as uint32_t as uint32_t; + c = (c as libc::c_uint).wrapping_add( + (a ^ (d | !b)) + .wrapping_add(x[10 as libc::c_int as usize]) + .wrapping_add(0xffeff47d as libc::c_uint), + ) as uint32_t as uint32_t; + c = c << 15 as libc::c_int | c >> 32 as libc::c_int - 15 as libc::c_int; + c = (c as libc::c_uint).wrapping_add(d) as uint32_t as uint32_t; + b = (b as libc::c_uint).wrapping_add( + (d ^ (c | !a)) + .wrapping_add(x[1 as libc::c_int as usize]) + .wrapping_add(0x85845dd1 as libc::c_uint), + ) as uint32_t as uint32_t; + b = b << 21 as libc::c_int | b >> 32 as libc::c_int - 21 as libc::c_int; + b = (b as libc::c_uint).wrapping_add(c) as uint32_t as uint32_t; + a = (a as libc::c_uint).wrapping_add( + (c ^ (b | !d)) + .wrapping_add(x[8 as libc::c_int as usize]) + .wrapping_add(0x6fa87e4f as libc::c_int as uint32_t), + ) as uint32_t as uint32_t; + a = a << 6 as libc::c_int | a >> 32 as libc::c_int - 6 as libc::c_int; + a = (a as libc::c_uint).wrapping_add(b) as uint32_t as uint32_t; + d = (d as libc::c_uint).wrapping_add( + (b ^ (a | !c)) + .wrapping_add(x[15 as libc::c_int as usize]) + .wrapping_add(0xfe2ce6e0 as libc::c_uint), + ) as uint32_t as uint32_t; + d = d << 10 as libc::c_int | d >> 32 as libc::c_int - 10 as libc::c_int; + d = (d as libc::c_uint).wrapping_add(a) as uint32_t as uint32_t; + c = (c as libc::c_uint).wrapping_add( + (a ^ (d | !b)) + .wrapping_add(x[6 as libc::c_int as usize]) + .wrapping_add(0xa3014314 as libc::c_uint), + ) as uint32_t as uint32_t; + c = c << 15 as libc::c_int | c >> 32 as libc::c_int - 15 as libc::c_int; + c = (c as libc::c_uint).wrapping_add(d) as uint32_t as uint32_t; + b = (b as libc::c_uint).wrapping_add( + (d ^ (c | !a)) + .wrapping_add(x[13 as libc::c_int as usize]) + .wrapping_add(0x4e0811a1 as libc::c_int as uint32_t), + ) as uint32_t as uint32_t; + b = b << 21 as libc::c_int | b >> 32 as libc::c_int - 21 as libc::c_int; + b = (b as libc::c_uint).wrapping_add(c) as uint32_t as uint32_t; + a = (a as libc::c_uint).wrapping_add( + (c ^ (b | !d)) + .wrapping_add(x[4 as libc::c_int as usize]) + .wrapping_add(0xf7537e82 as libc::c_uint), + ) as uint32_t as uint32_t; + a = a << 6 as libc::c_int | a >> 32 as libc::c_int - 6 as libc::c_int; + a = (a as libc::c_uint).wrapping_add(b) as uint32_t as uint32_t; + d = (d as libc::c_uint).wrapping_add( + (b ^ (a | !c)) + .wrapping_add(x[11 as libc::c_int as usize]) + .wrapping_add(0xbd3af235 as libc::c_uint), + ) as uint32_t as uint32_t; + d = d << 10 as libc::c_int | d >> 32 as libc::c_int - 10 as libc::c_int; + d = (d as libc::c_uint).wrapping_add(a) as uint32_t as uint32_t; + c = (c as libc::c_uint).wrapping_add( + (a ^ (d | !b)) + .wrapping_add(x[2 as libc::c_int as usize]) + .wrapping_add(0x2ad7d2bb as libc::c_int as uint32_t), + ) as uint32_t as uint32_t; + c = c << 15 as libc::c_int | c >> 32 as libc::c_int - 15 as libc::c_int; + c = (c as libc::c_uint).wrapping_add(d) as uint32_t as uint32_t; + b = (b as libc::c_uint).wrapping_add( + (d ^ (c | !a)) + .wrapping_add(x[9 as libc::c_int as usize]) + .wrapping_add(0xeb86d391 as libc::c_uint), + ) as uint32_t as uint32_t; + b = b << 21 as libc::c_int | b >> 32 as libc::c_int - 21 as libc::c_int; + b = (b as libc::c_uint).wrapping_add(c) as uint32_t as uint32_t; + let ref mut fresh0 = *state.offset(0 as libc::c_int as isize); + *fresh0 = (*fresh0 as libc::c_uint).wrapping_add(a) as uint32_t as uint32_t; + let ref mut fresh1 = *state.offset(1 as libc::c_int as isize); + *fresh1 = (*fresh1 as libc::c_uint).wrapping_add(b) as uint32_t as uint32_t; + let ref mut fresh2 = *state.offset(2 as libc::c_int as isize); + *fresh2 = (*fresh2 as libc::c_uint).wrapping_add(c) as uint32_t as uint32_t; + let ref mut fresh3 = *state.offset(3 as libc::c_int as isize); + *fresh3 = (*fresh3 as libc::c_uint).wrapping_add(d) as uint32_t as uint32_t; + memset( + x.as_mut_ptr() as *mut libc::c_uchar as *mut libc::c_void, + 0 as libc::c_int, + ::std::mem::size_of::<[uint32_t; 16]>() as libc::c_ulong, + ); +} +unsafe extern "C" fn Encode( + mut output: *mut libc::c_uchar, + mut input: *mut uint32_t, + mut len: libc::c_uint, +) { + let mut i: libc::c_uint = 0; + let mut j: libc::c_uint = 0; + i = 0 as libc::c_int as libc::c_uint; + j = 0 as libc::c_int as libc::c_uint; + while j < len { + *output.offset(j as isize) = + (*input.offset(i as isize) & 0xff as libc::c_int as libc::c_uint) as libc::c_uchar; + *output.offset(j.wrapping_add(1 as libc::c_int as libc::c_uint) as isize) = + (*input.offset(i as isize) >> 8 as libc::c_int & 0xff as libc::c_int as libc::c_uint) + as libc::c_uchar; + *output.offset(j.wrapping_add(2 as libc::c_int as libc::c_uint) as isize) = + (*input.offset(i as isize) >> 16 as libc::c_int & 0xff as libc::c_int as libc::c_uint) + as libc::c_uchar; + *output.offset(j.wrapping_add(3 as libc::c_int as libc::c_uint) as isize) = + (*input.offset(i as isize) >> 24 as libc::c_int & 0xff as libc::c_int as libc::c_uint) + as libc::c_uchar; + i = i.wrapping_add(1); + j = j.wrapping_add(4 as libc::c_int as libc::c_uint); + } +} +unsafe extern "C" fn Decode( + mut output: *mut uint32_t, + mut input: *const libc::c_uchar, + mut len: libc::c_uint, +) { + let mut i: libc::c_uint = 0; + let mut j: libc::c_uint = 0; + i = 0 as libc::c_int as libc::c_uint; + j = 0 as libc::c_int as libc::c_uint; + while j < len { + *output.offset(i as isize) = *input.offset(j as isize) as uint32_t + | (*input.offset(j.wrapping_add(1 as libc::c_int as libc::c_uint) as isize) + as uint32_t) + << 8 as libc::c_int + | (*input.offset(j.wrapping_add(2 as libc::c_int as libc::c_uint) as isize) + as uint32_t) + << 16 as libc::c_int + | (*input.offset(j.wrapping_add(3 as libc::c_int as libc::c_uint) as isize) + as uint32_t) + << 24 as libc::c_int; + i = i.wrapping_add(1); + j = j.wrapping_add(4 as libc::c_int as libc::c_uint); + } +} From ac353ce8c49842ba4db4f1215b0f18bd7ef190ad Mon Sep 17 00:00:00 2001 From: David Anekstein Date: Fri, 11 Aug 2023 16:10:39 -0400 Subject: [PATCH 02/17] unlower: look for last terminator statement across multiple blocks. Sometimes we want to `get_last_call` where the input `locs` span multiple blocks. This means that sometimes the `last()` statement is not a call as it would normally be in a list of locations constrained to just one block, so instead we traverse the statements in reverse and return the first found terminator. --- c2rust-analyze/src/rewrite/expr/unlower.rs | 23 ++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/c2rust-analyze/src/rewrite/expr/unlower.rs b/c2rust-analyze/src/rewrite/expr/unlower.rs index 45f608c00a..00cee0aa26 100644 --- a/c2rust-analyze/src/rewrite/expr/unlower.rs +++ b/c2rust-analyze/src/rewrite/expr/unlower.rs @@ -155,17 +155,20 @@ impl<'a, 'tcx> UnlowerVisitor<'a, 'tcx> { &'a mir::Operand<'tcx>, &'a [mir::Operand<'tcx>], )> { - let loc = *locs.last()?; - let term = self.mir.stmt_at(loc).right()?; - match term.kind { - mir::TerminatorKind::Call { - ref func, - ref args, - destination, - .. - } => Some((loc, destination, func, args)), - _ => None, + for &loc in locs.iter().rev() { + if let Some(term) = self.mir.stmt_at(loc).right() { + match term.kind { + mir::TerminatorKind::Call { + ref func, + ref args, + destination, + .. + } => return Some((loc, destination, func, args)), + _ => {} + } + } } + None } fn should_ignore_statement(&self, loc: Location) -> bool { From 64f4cf86ee8c224359d9935a5b63adf54ba65009 Mon Sep 17 00:00:00 2001 From: David Anekstein Date: Tue, 15 Aug 2023 20:19:04 -0400 Subject: [PATCH 03/17] handle memset and memcpy + casts to libc::c_void for supplying their arguments --- c2rust-analyze/src/borrowck/type_check.rs | 13 ++ c2rust-analyze/src/c_void_casts.rs | 187 ++++++++++++------ c2rust-analyze/src/dataflow/type_check.rs | 73 +++++++ c2rust-analyze/src/rewrite/expr/distribute.rs | 2 +- c2rust-analyze/src/util.rs | 20 ++ 5 files changed, 232 insertions(+), 63 deletions(-) diff --git a/c2rust-analyze/src/borrowck/type_check.rs b/c2rust-analyze/src/borrowck/type_check.rs index 3121664275..859cc1b801 100644 --- a/c2rust-analyze/src/borrowck/type_check.rs +++ b/c2rust-analyze/src/borrowck/type_check.rs @@ -583,6 +583,19 @@ impl<'tcx> TypeChecker<'tcx, '_> { self.visit_operand(p) }); } + Callee::Memcpy => { + let _pl_lty = self.visit_place(destination); + let _rv_lty = assert_matches!(&args[..], [dest, src, _] => { + self.visit_operand(dest); + self.visit_operand(src); + }); + } + Callee::Memset => { + let _pl_lty = self.visit_place(destination); + let _rv_lty = assert_matches!(&args[..], [dest, ..] => { + self.visit_operand(dest) + }); + } Callee::IsNull => { let _rv_lty = assert_matches!(&args[..], [p] => { self.visit_operand(p) diff --git a/c2rust-analyze/src/c_void_casts.rs b/c2rust-analyze/src/c_void_casts.rs index 7a1e4a003b..606db13054 100644 --- a/c2rust-analyze/src/c_void_casts.rs +++ b/c2rust-analyze/src/c_void_casts.rs @@ -1,10 +1,10 @@ use std::borrow::Borrow; -use std::collections::{HashMap, HashSet}; +use std::collections::{HashMap, HashSet, VecDeque}; use rustc_middle::{ mir::{ - Body, LocalDecls, Location, Place, Rvalue, Statement, StatementKind, Terminator, - TerminatorKind, + BasicBlock, BasicBlockData, Body, LocalDecls, Location, Place, Rvalue, Statement, + StatementKind, Terminator, TerminatorKind, }, ty::{TyCtxt, TyKind}, }; @@ -48,6 +48,7 @@ impl CVoidCastDirection { Malloc | Calloc => &[From][..], Realloc => &[To, From][..], Free => &[To][..], + Memcpy | Memset => &[To][..], _ => &[], } } @@ -83,6 +84,24 @@ impl<'tcx> CVoidPtr<'tcx> { Self { place } } + pub fn checked_optional( + place: Place<'tcx>, + local_decls: &LocalDecls<'tcx>, + tcx: TyCtxt<'tcx>, + ) -> Option { + let deref_ty = place.ty(local_decls, tcx).ty.builtin_deref(true)?; + + if let TyKind::Adt(adt, _) = deref_ty.ty.kind() { + if tcx.def_path(adt.did()).data[0].to_string() == "ffi" + && tcx.item_name(adt.did()).as_str() == "c_void" + { + return Some(Self { place }); + } + } + + None + } + /// Check another [`Place`] for being a [`*c_void`](core::ffi::c_void) /// by comparing it to ourself, which is already checked. /// @@ -137,7 +156,7 @@ impl<'tcx> Borrow> for CVoidPtr<'tcx> { } } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Eq, PartialEq, Hash)] /// A cast to/from a [`*c_void`](core::ffi::c_void) to/from a properly typed pointer. pub struct CVoidCast<'tcx> { /// The [`*c_void`](core::ffi::c_void) side of the cast. @@ -162,14 +181,14 @@ pub struct CVoidCast<'tcx> { pub struct CVoidCastsUniDirectional<'tcx> { /// Mapping from location of a call that either /// produces or consumes a [`CVoidPtr`] to its - /// succeeding or preceding [`CVoidCast`] - calls: HashMap>, + /// succeeding or preceding [`CVoidCast`]s + calls: HashMap>>, /// Set of locations where [`CVoidCast`]s occur. casts: HashSet, } impl<'tcx> CVoidCastsUniDirectional<'tcx> { - /// Get the adjusted [`Place`] from a cast at a particulat [`Location`]. + /// Get the adjusted [`Place`] from a cast at a particular [`Location`]. /// /// Otherwise, the same `place` is returned, as no adjustments are necessary. pub fn get_adjusted_place_or_default_to( @@ -177,20 +196,22 @@ impl<'tcx> CVoidCastsUniDirectional<'tcx> { loc: Location, place: Place<'tcx>, ) -> Place<'tcx> { - *self - .calls - .get(&loc) - .map(|cast| { - assert_eq!(cast.c_void_ptr.place, place); - &cast.other_ptr - }) - .unwrap_or(&place) + // If there are multiple CVoidCasts for a Location, this logic may need to be adjusted + // depending on the intended behavior. + if let Some(casts) = self.calls.get(&loc) { + for cast in casts { + if cast.c_void_ptr.place == place { + return cast.other_ptr; + } + } + } + place } /// Tracks the [Location] of the use of a casted pointer in a [TerminatorKind::Call] pub fn insert_call(&mut self, loc: Location, cast: CVoidCast<'tcx>) { - assert!(!self.calls.contains_key(&loc)); - self.calls.insert(loc, cast); + let entry = self.calls.entry(loc).or_insert_with(HashSet::new); + entry.insert(cast); } /// Tracks the [Location] of void pointer [Rvalue::Cast] @@ -377,7 +398,9 @@ impl<'tcx> CVoidCasts<'tcx> { for (sidx, stmt) in statements.iter().enumerate().rev() { let cast = c_void_ptr.get_cast_from_stmt(CVoidCastDirection::To, stmt); if let Some(cast) = cast { - return Some((sidx, cast)); + if cast.c_void_ptr == c_void_ptr { + return Some((sidx, cast)); + } } else if Self::is_place_modified_by_statement(&c_void_ptr.place, stmt) { return None; } @@ -403,59 +426,99 @@ impl<'tcx> CVoidCasts<'tcx> { /// [`*c_void`]: core::ffi::c_void fn insert_all_from_body(&mut self, body: &Body<'tcx>, tcx: TyCtxt<'tcx>) { for (block, bb_data) in body.basic_blocks().iter_enumerated() { - let term: &Terminator = match &bb_data.terminator { - Some(term) => term, - None => continue, - }; - let (func, args, destination, target) = match term.kind { - TerminatorKind::Call { - ref func, - ref args, + if let Some(term) = &bb_data.terminator { + if let TerminatorKind::Call { + func, + args, destination, target, .. - } => (func, args, destination, target), - _ => continue, - }; - let func_ty = func.ty(&body.local_decls, tcx); - - for direction in CVoidCastDirection::from_callee(ty_callee(tcx, func_ty)) - .iter() - .copied() - { - use CVoidCastDirection::*; - let c_void_ptr = match direction { - From => destination, - To => args[0] - .place() - .expect("Casts to/from null pointer are not yet supported"), - }; - let c_void_ptr = CVoidPtr::checked(c_void_ptr, &body.local_decls, tcx); - let cast = match direction { - // For [`CVoidCastDirection::From`], we only count - // a cast from `*c_void` to an arbitrary type in the subsequent block, - // searching forward. - From => Self::find_first_cast( - &body.basic_blocks()[target.unwrap()].statements, - c_void_ptr, - ), - // For [`CVoidCastDirection::To`], we only count - // a cast to `*c_void` from an arbitrary type in the same block, - // searching backwards. - To => Self::find_last_cast(&bb_data.statements, c_void_ptr), - }; - if let Some((statement_index, cast)) = cast { + } = &term.kind + { + let func_ty = func.ty(&body.local_decls, tcx); + let directions = CVoidCastDirection::from_callee(ty_callee(tcx, func_ty)); + + for direction in directions.iter().copied() { + use CVoidCastDirection::*; + + match direction { + From => { + let c_void_ptr = + CVoidPtr::checked(*destination, &body.local_decls, tcx); + if let Some((statement_index, cast)) = Self::find_first_cast( + &body.basic_blocks()[target.unwrap()].statements, + c_void_ptr, + ) { + self.insert_cast( + direction, + Location { + statement_index, + block: target.unwrap(), + }, + ); + self.insert_call( + direction, + terminator_location(block, bb_data), + cast, + ); + } + } + To => { + for arg in args { + if let Some(place) = arg.place() { + if let Some(c_void_ptr) = CVoidPtr::checked_optional( + place, + &body.local_decls, + tcx, + ) { + self.find_and_insert_pred_cast( + body, c_void_ptr, direction, block, bb_data, + ); + } + } + } + } + } + } + } + } + } + } + + /// Performs BFS in the CFG to find where the c_void_ptr + /// was cast to that type + fn find_and_insert_pred_cast( + &mut self, + body: &Body<'tcx>, + c_void_ptr: CVoidPtr<'tcx>, + direction: CVoidCastDirection, + block: BasicBlock, + bb_data: &BasicBlockData<'tcx>, + ) { + let predecessors = body.basic_blocks.predecessors(); + + let mut seen = HashSet::new(); + let mut queue = VecDeque::new(); + queue.push_back(block); + + while let Some(current_block) = queue.pop_front() { + if seen.insert(current_block) { + let current_block_data = &body.basic_blocks()[current_block]; + if let Some((statement_index, cast)) = + Self::find_last_cast(¤t_block_data.statements, c_void_ptr) + { self.insert_cast( direction, Location { statement_index, - block: match direction { - To => block, - From => target.unwrap(), - }, + block: current_block, }, ); - self.insert_call(direction, terminator_location(block, bb_data), cast); + self.insert_call(direction, terminator_location(current_block, bb_data), cast); + } + + for &pred in &predecessors[current_block] { + queue.push_back(pred); } } } diff --git a/c2rust-analyze/src/dataflow/type_check.rs b/c2rust-analyze/src/dataflow/type_check.rs index 7f888df42b..fbf2f8bbc6 100644 --- a/c2rust-analyze/src/dataflow/type_check.rs +++ b/c2rust-analyze/src/dataflow/type_check.rs @@ -494,7 +494,80 @@ impl<'tcx> TypeChecker<'tcx, '_> { let perms = PermissionSet::FREE; self.constraints.add_all_perms(rv_lty.label, perms); } + Callee::Memcpy => { + let out_ptr = self.acx.c_void_casts.get_adjusted_place_or_default_to( + loc, + CVoidCastDirection::From, + destination, + ); + + let dest_ptr = args[0] + .place() + .expect("Casts to/from null pointer are not yet supported"); + let dest_ptr = self.acx.c_void_casts.get_adjusted_place_or_default_to( + loc, + CVoidCastDirection::To, + dest_ptr, + ); + self.visit_place(out_ptr, Mutability::Mut); + assert!(args.len() == 3); + self.visit_place(dest_ptr, Mutability::Mut); + let rv_lty = self.acx.type_of(dest_ptr); + + // input needs WRITE permission + let perms = PermissionSet::WRITE; + self.constraints.add_all_perms(rv_lty.label, perms); + + // TODO: the return values of `memcpy` are rarely used + // and may not always be casted to a non-void-pointer, + // so avoid unifying for now + // self.do_equivalence_nested(pl_lty, rv_lty); + + let src_ptr = args[1] + .place() + .expect("Casts to/from null pointer are not yet supported"); + let src_ptr = self.acx.c_void_casts.get_adjusted_place_or_default_to( + loc, + CVoidCastDirection::To, + src_ptr, + ); + self.visit_place(out_ptr, Mutability::Mut); + let pl_lty = self.acx.type_of(out_ptr); + assert!(args.len() == 3); + self.visit_place(src_ptr, Mutability::Not); + let rv_lty = self.acx.type_of(src_ptr); + + // input needs READ permission + let perms = PermissionSet::READ; + self.constraints.add_all_perms(rv_lty.label, perms); + + // TODO: the return values of `memcpy` are rarely used + // and may not always be casted to a non-void-pointer, + // so avoid unifying for now + // self.do_equivalence_nested(pl_lty, rv_lty); + } + Callee::Memset => { + let dest_ptr = args[0] + .place() + .expect("Casts to/from null pointer are not yet supported"); + let dest_ptr = self.acx.c_void_casts.get_adjusted_place_or_default_to( + loc, + CVoidCastDirection::To, + dest_ptr, + ); + self.visit_place(destination, Mutability::Mut); + assert!(args.len() == 3); + + let rv_lty = self.acx.type_of(dest_ptr); + let perms = PermissionSet::WRITE; + self.constraints.add_all_perms(rv_lty.label, perms); + // TODO: the return values of `memcpy` are rarely used + // and may not always be casted to a non-void-pointer, + // so avoid unifying for now + // let pl_lty = self.acx.type_of(out_ptr); + // self.do_equivalence_nested(pl_lty, rv_lty); + } Callee::IsNull => { assert!(args.len() == 1); self.visit_operand(&args[0]); diff --git a/c2rust-analyze/src/rewrite/expr/distribute.rs b/c2rust-analyze/src/rewrite/expr/distribute.rs index 9fcdbb79cc..75928b54b4 100644 --- a/c2rust-analyze/src/rewrite/expr/distribute.rs +++ b/c2rust-analyze/src/rewrite/expr/distribute.rs @@ -65,7 +65,7 @@ pub fn distribute( let origin = match unlower_map.get(&key) { Some(x) => x, None => { - error!("unlower_map has no origin for {:?}", key); + error!("unlower_map has no origin for {:?} {:?}", key, unlower_map); continue; } }; diff --git a/c2rust-analyze/src/util.rs b/c2rust-analyze/src/util.rs index 4a9c15bf38..01c1b7efa3 100644 --- a/c2rust-analyze/src/util.rs +++ b/c2rust-analyze/src/util.rs @@ -177,6 +177,12 @@ pub enum Callee<'tcx> { /// libc::calloc Calloc, + /// libc::memset + Memset, + + /// libc::memcpy + Memcpy, + /// libc::free Free, @@ -303,6 +309,20 @@ fn builtin_callee<'tcx>(tcx: TyCtxt<'tcx>, did: DefId, substs: SubstsRef<'tcx>) None } + "memset" => { + if matches!(tcx.def_kind(tcx.parent(did)), DefKind::ForeignMod) { + return Some(Callee::Memset); + } + None + } + + "memcpy" => { + if matches!(tcx.def_kind(tcx.parent(did)), DefKind::ForeignMod) { + return Some(Callee::Memcpy); + } + None + } + "is_null" => { // The `offset` inherent method of `*const T` and `*mut T`. let parent_did = tcx.parent(did); From 9bf521167aa8ac455077c0c6c664f21a9c59cea9 Mon Sep 17 00:00:00 2001 From: David Anekstein Date: Mon, 21 Aug 2023 19:37:45 -0400 Subject: [PATCH 04/17] enable memcpy and memset in tests --- c2rust-analyze/tests/filecheck/algo_md5.rs | 55 +++++++++++----------- 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/c2rust-analyze/tests/filecheck/algo_md5.rs b/c2rust-analyze/tests/filecheck/algo_md5.rs index d428c90343..50f2704c81 100644 --- a/c2rust-analyze/tests/filecheck/algo_md5.rs +++ b/c2rust-analyze/tests/filecheck/algo_md5.rs @@ -93,13 +93,13 @@ pub unsafe extern "C" fn MD5_Init(mut context: *mut MD5_CTX) { #[no_mangle] pub unsafe extern "C" fn MD5_Update( mut context: *mut MD5_CTX, - mut _input: *const libc::c_void, + mut input: *const libc::c_void, mut inputLen: libc::c_uint, ) { let mut i: libc::c_uint = 0; let mut ndx: libc::c_uint = 0; let mut partLen: libc::c_uint = 0; - let mut input: *const libc::c_uchar = _input as *const libc::c_uchar; + // let mut input: *const libc::c_uchar = _input as *const libc::c_uchar; ndx = (*context).count[0 as libc::c_int as usize] >> 3 as libc::c_int & 0x3f as libc::c_int as libc::c_uint; (*context).count[0 as libc::c_int as usize] = @@ -126,31 +126,31 @@ pub unsafe extern "C" fn MD5_Update( ); i = partLen; while i.wrapping_add(63 as libc::c_int as libc::c_uint) < inputLen { - li_MD5Transform(((*context).state).as_mut_ptr(), &*input.offset(i as isize)); + // li_MD5Transform(((*context).state).as_mut_ptr(), &*input.offset(i as isize)); i = i.wrapping_add(64 as libc::c_int as libc::c_uint); } ndx = 0 as libc::c_int as libc::c_uint; } else { i = 0 as libc::c_int as libc::c_uint; } - memcpy( - &mut *((*context).buffer).as_mut_ptr().offset(ndx as isize) as *mut libc::c_uchar - as *mut libc::c_void, - &*input.offset(i as isize) as *const libc::c_uchar as *mut libc::c_uchar - as *const libc::c_void, - inputLen.wrapping_sub(i) as libc::c_ulong, - ); + // memcpy( + // &mut *((*context).buffer).as_mut_ptr().offset(ndx as isize) as *mut libc::c_uchar + // as *mut libc::c_void, + // &*input.offset(i as isize) as *const libc::c_uchar as *mut libc::c_uchar + // as *const libc::c_void, + // inputLen.wrapping_sub(i) as libc::c_ulong, + // ); } #[no_mangle] pub unsafe extern "C" fn MD5_Final(mut digest: *mut libc::c_uchar, mut context: *mut MD5_CTX) { let mut bits: [libc::c_uchar; 8] = [0; 8]; let mut ndx: libc::c_uint = 0; let mut padLen: libc::c_uint = 0; - Encode( - bits.as_mut_ptr(), - ((*context).count).as_mut_ptr(), - 8 as libc::c_int as libc::c_uint, - ); + // Encode( + // bits.as_mut_ptr(), + // ((*context).count).as_mut_ptr(), + // 8 as libc::c_int as libc::c_uint, + // ); ndx = (*context).count[0 as libc::c_int as usize] >> 3 as libc::c_int & 0x3f as libc::c_int as libc::c_uint; padLen = if ndx < 56 as libc::c_int as libc::c_uint { @@ -158,17 +158,18 @@ pub unsafe extern "C" fn MD5_Final(mut digest: *mut libc::c_uchar, mut context: } else { (120 as libc::c_int as libc::c_uint).wrapping_sub(ndx) }; - MD5_Update(context, PADDING.as_mut_ptr() as *const libc::c_void, padLen); - MD5_Update( - context, - bits.as_mut_ptr() as *const libc::c_void, - 8 as libc::c_int as libc::c_uint, - ); - Encode( - digest, - ((*context).state).as_mut_ptr(), - 16 as libc::c_int as libc::c_uint, - ); + // MD5_Update(context, PADDING.as_mut_ptr(),// as *const libc::c_void, + // padLen); + // MD5_Update( + // context, + // bits.as_mut_ptr(), // as *const libc::c_void, + // 8 as libc::c_int as libc::c_uint, + // ); + // Encode( + // digest, + // ((*context).state).as_mut_ptr(), + // 16 as libc::c_int as libc::c_uint, + // ); memset( context as *mut libc::c_uchar as *mut libc::c_void, 0 as libc::c_int, @@ -181,7 +182,7 @@ unsafe extern "C" fn li_MD5Transform(mut state: *mut uint32_t, mut block: *const let mut c: uint32_t = *state.offset(2 as libc::c_int as isize); let mut d: uint32_t = *state.offset(3 as libc::c_int as isize); let mut x: [uint32_t; 16] = [0; 16]; - Decode(x.as_mut_ptr(), block, 64 as libc::c_int as libc::c_uint); + // Decode(x.as_mut_ptr(), block, 64 as libc::c_int as libc::c_uint); a = (a as libc::c_uint).wrapping_add( (b & c | !b & d) .wrapping_add(x[0 as libc::c_int as usize]) From 339b202645c7febe9f4c28b7caec7010e2493faf Mon Sep 17 00:00:00 2001 From: David Anekstein Date: Tue, 22 Aug 2023 19:27:34 -0400 Subject: [PATCH 05/17] fix warnings --- c2rust-analyze/src/c_void_casts.rs | 2 +- c2rust-analyze/src/dataflow/type_check.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/c2rust-analyze/src/c_void_casts.rs b/c2rust-analyze/src/c_void_casts.rs index 606db13054..f795f4ac96 100644 --- a/c2rust-analyze/src/c_void_casts.rs +++ b/c2rust-analyze/src/c_void_casts.rs @@ -4,7 +4,7 @@ use std::collections::{HashMap, HashSet, VecDeque}; use rustc_middle::{ mir::{ BasicBlock, BasicBlockData, Body, LocalDecls, Location, Place, Rvalue, Statement, - StatementKind, Terminator, TerminatorKind, + StatementKind, TerminatorKind, }, ty::{TyCtxt, TyKind}, }; diff --git a/c2rust-analyze/src/dataflow/type_check.rs b/c2rust-analyze/src/dataflow/type_check.rs index fbf2f8bbc6..6c41416d9e 100644 --- a/c2rust-analyze/src/dataflow/type_check.rs +++ b/c2rust-analyze/src/dataflow/type_check.rs @@ -532,7 +532,7 @@ impl<'tcx> TypeChecker<'tcx, '_> { src_ptr, ); self.visit_place(out_ptr, Mutability::Mut); - let pl_lty = self.acx.type_of(out_ptr); + let _pl_lty = self.acx.type_of(out_ptr); assert!(args.len() == 3); self.visit_place(src_ptr, Mutability::Not); let rv_lty = self.acx.type_of(src_ptr); From 80acb75628b6f8bef5e1bbc0dee5dac50ebf1754 Mon Sep 17 00:00:00 2001 From: David Anekstein Date: Sun, 27 Aug 2023 16:26:06 -0400 Subject: [PATCH 06/17] revert debug print change for `unlower_map` Co-authored-by: spernsteiner --- c2rust-analyze/src/rewrite/expr/distribute.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/c2rust-analyze/src/rewrite/expr/distribute.rs b/c2rust-analyze/src/rewrite/expr/distribute.rs index 75928b54b4..9fcdbb79cc 100644 --- a/c2rust-analyze/src/rewrite/expr/distribute.rs +++ b/c2rust-analyze/src/rewrite/expr/distribute.rs @@ -65,7 +65,7 @@ pub fn distribute( let origin = match unlower_map.get(&key) { Some(x) => x, None => { - error!("unlower_map has no origin for {:?} {:?}", key, unlower_map); + error!("unlower_map has no origin for {:?}", key); continue; } }; From e5a13601295f71fb4b9b3539ae4112d7ad1a54d5 Mon Sep 17 00:00:00 2001 From: David Anekstein Date: Mon, 28 Aug 2023 12:12:17 -0400 Subject: [PATCH 07/17] put CVoidPtr::checked in terms of CVoidPtr::checked_optional --- c2rust-analyze/src/c_void_casts.rs | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/c2rust-analyze/src/c_void_casts.rs b/c2rust-analyze/src/c_void_casts.rs index f795f4ac96..9e3f1aca51 100644 --- a/c2rust-analyze/src/c_void_casts.rs +++ b/c2rust-analyze/src/c_void_casts.rs @@ -70,18 +70,7 @@ impl<'tcx> CVoidPtr<'tcx> { /// /// This panics on failure. pub fn checked(place: Place<'tcx>, local_decls: &LocalDecls<'tcx>, tcx: TyCtxt<'tcx>) -> Self { - let deref_ty = place - .ty(local_decls, tcx) - .ty - .builtin_deref(true) - .unwrap() - .ty - .kind(); - assert_matches!(deref_ty, TyKind::Adt(adt, _) => { - assert_eq!(tcx.def_path(adt.did()).data[0].to_string(), "ffi"); - assert_eq!(tcx.item_name(adt.did()).as_str(), "c_void"); - }); - Self { place } + Self::checked_optional(place, local_decls, tcx).unwrap() } pub fn checked_optional( From 32c266218740c25f5251821fa863820f9190c6e6 Mon Sep 17 00:00:00 2001 From: David Anekstein Date: Mon, 28 Aug 2023 12:35:20 -0400 Subject: [PATCH 08/17] use linear search to find last cast, and panic if the place has already been assigned to/from --- c2rust-analyze/src/c_void_casts.rs | 52 ++++++++++++------------------ 1 file changed, 20 insertions(+), 32 deletions(-) diff --git a/c2rust-analyze/src/c_void_casts.rs b/c2rust-analyze/src/c_void_casts.rs index 9e3f1aca51..2560e2ad7a 100644 --- a/c2rust-analyze/src/c_void_casts.rs +++ b/c2rust-analyze/src/c_void_casts.rs @@ -1,16 +1,14 @@ use std::borrow::Borrow; -use std::collections::{HashMap, HashSet, VecDeque}; +use std::collections::{HashMap, HashSet}; use rustc_middle::{ mir::{ - BasicBlock, BasicBlockData, Body, LocalDecls, Location, Place, Rvalue, Statement, - StatementKind, TerminatorKind, + BasicBlockData, Body, LocalDecls, Location, Place, Rvalue, Statement, StatementKind, + TerminatorKind, }, ty::{TyCtxt, TyKind}, }; -use assert_matches::assert_matches; - use crate::util::{get_assign_sides, get_cast_place, terminator_location, ty_callee, Callee}; /// The direction of a [`*c_void`](core::ffi::c_void) cast. @@ -461,7 +459,7 @@ impl<'tcx> CVoidCasts<'tcx> { tcx, ) { self.find_and_insert_pred_cast( - body, c_void_ptr, direction, block, bb_data, + body, c_void_ptr, direction, bb_data, ); } } @@ -481,34 +479,24 @@ impl<'tcx> CVoidCasts<'tcx> { body: &Body<'tcx>, c_void_ptr: CVoidPtr<'tcx>, direction: CVoidCastDirection, - block: BasicBlock, bb_data: &BasicBlockData<'tcx>, ) { - let predecessors = body.basic_blocks.predecessors(); - - let mut seen = HashSet::new(); - let mut queue = VecDeque::new(); - queue.push_back(block); - - while let Some(current_block) = queue.pop_front() { - if seen.insert(current_block) { - let current_block_data = &body.basic_blocks()[current_block]; - if let Some((statement_index, cast)) = - Self::find_last_cast(¤t_block_data.statements, c_void_ptr) - { - self.insert_cast( - direction, - Location { - statement_index, - block: current_block, - }, - ); - self.insert_call(direction, terminator_location(current_block, bb_data), cast); - } - - for &pred in &predecessors[current_block] { - queue.push_back(pred); - } + let mut inserted_places = HashSet::new(); + for (current_block, current_block_data) in body.basic_blocks().iter_enumerated() { + if let Some((statement_index, cast)) = + Self::find_last_cast(¤t_block_data.statements, c_void_ptr) + { + assert!( + inserted_places.insert(c_void_ptr.place), + "Duplicate c_void_ptr.place found: {:?}", + c_void_ptr.place + ); + let location = Location { + statement_index, + block: current_block, + }; + self.insert_cast(direction, location); + self.insert_call(direction, terminator_location(current_block, bb_data), cast); } } } From bec007e89d0e9c532a6b966cd2eb33a675caa9aa Mon Sep 17 00:00:00 2001 From: David Anekstein Date: Mon, 28 Aug 2023 12:35:37 -0400 Subject: [PATCH 09/17] in algo_md5 tests, comment out unsupported intermediate casts --- c2rust-analyze/tests/filecheck/algo_md5.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/c2rust-analyze/tests/filecheck/algo_md5.rs b/c2rust-analyze/tests/filecheck/algo_md5.rs index 50f2704c81..d04a2fd53c 100644 --- a/c2rust-analyze/tests/filecheck/algo_md5.rs +++ b/c2rust-analyze/tests/filecheck/algo_md5.rs @@ -81,6 +81,8 @@ static mut PADDING: [libc::c_uchar; 64] = [ 0 as libc::c_int as libc::c_uchar, 0 as libc::c_int as libc::c_uchar, ]; + +// CHECK-LABEL: MD5_Init #[no_mangle] pub unsafe extern "C" fn MD5_Init(mut context: *mut MD5_CTX) { (*context).count[1 as libc::c_int as usize] = 0 as libc::c_int as uint32_t; @@ -117,7 +119,7 @@ pub unsafe extern "C" fn MD5_Update( memcpy( &mut *((*context).buffer).as_mut_ptr().offset(ndx as isize) as *mut libc::c_uchar as *mut libc::c_void, - input as *mut libc::c_uchar as *const libc::c_void, + input /* as *mut libc::c_uchar */ as *const libc::c_void, partLen as libc::c_ulong, ); li_MD5Transform( @@ -171,7 +173,7 @@ pub unsafe extern "C" fn MD5_Final(mut digest: *mut libc::c_uchar, mut context: // 16 as libc::c_int as libc::c_uint, // ); memset( - context as *mut libc::c_uchar as *mut libc::c_void, + context /* as *mut libc::c_uchar */ as *mut libc::c_void, 0 as libc::c_int, ::std::mem::size_of::() as libc::c_ulong, ); @@ -640,7 +642,7 @@ unsafe extern "C" fn li_MD5Transform(mut state: *mut uint32_t, mut block: *const let ref mut fresh3 = *state.offset(3 as libc::c_int as isize); *fresh3 = (*fresh3 as libc::c_uint).wrapping_add(d) as uint32_t as uint32_t; memset( - x.as_mut_ptr() as *mut libc::c_uchar as *mut libc::c_void, + x.as_mut_ptr() /* as *mut libc::c_uchar */ as *mut libc::c_void, 0 as libc::c_int, ::std::mem::size_of::<[uint32_t; 16]>() as libc::c_ulong, ); From 4b72bbc1ddb5d9945c908e148c9ecef77997af86 Mon Sep 17 00:00:00 2001 From: David Anekstein Date: Mon, 28 Aug 2023 12:38:08 -0400 Subject: [PATCH 10/17] remove spurious comment --- c2rust-analyze/src/dataflow/type_check.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/c2rust-analyze/src/dataflow/type_check.rs b/c2rust-analyze/src/dataflow/type_check.rs index 6c41416d9e..b0a96415ff 100644 --- a/c2rust-analyze/src/dataflow/type_check.rs +++ b/c2rust-analyze/src/dataflow/type_check.rs @@ -518,11 +518,6 @@ impl<'tcx> TypeChecker<'tcx, '_> { let perms = PermissionSet::WRITE; self.constraints.add_all_perms(rv_lty.label, perms); - // TODO: the return values of `memcpy` are rarely used - // and may not always be casted to a non-void-pointer, - // so avoid unifying for now - // self.do_equivalence_nested(pl_lty, rv_lty); - let src_ptr = args[1] .place() .expect("Casts to/from null pointer are not yet supported"); From 29c42af121d0c467a41d09717fa6b734dcc39d1f Mon Sep 17 00:00:00 2001 From: David Anekstein Date: Mon, 28 Aug 2023 13:39:57 -0400 Subject: [PATCH 11/17] add Terminator import for rustdoc --- c2rust-analyze/src/c_void_casts.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/c2rust-analyze/src/c_void_casts.rs b/c2rust-analyze/src/c_void_casts.rs index 2560e2ad7a..174e03a632 100644 --- a/c2rust-analyze/src/c_void_casts.rs +++ b/c2rust-analyze/src/c_void_casts.rs @@ -4,7 +4,7 @@ use std::collections::{HashMap, HashSet}; use rustc_middle::{ mir::{ BasicBlockData, Body, LocalDecls, Location, Place, Rvalue, Statement, StatementKind, - TerminatorKind, + Terminator, TerminatorKind, }, ty::{TyCtxt, TyKind}, }; From ffaadbb78088ed5b30ca1999437fd0c5e3716b89 Mon Sep 17 00:00:00 2001 From: David Anekstein Date: Mon, 28 Aug 2023 14:04:34 -0400 Subject: [PATCH 12/17] make rustdoc and rustlint happy --- c2rust-analyze/src/c_void_casts.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/c2rust-analyze/src/c_void_casts.rs b/c2rust-analyze/src/c_void_casts.rs index 174e03a632..31b8e9f2e4 100644 --- a/c2rust-analyze/src/c_void_casts.rs +++ b/c2rust-analyze/src/c_void_casts.rs @@ -4,7 +4,7 @@ use std::collections::{HashMap, HashSet}; use rustc_middle::{ mir::{ BasicBlockData, Body, LocalDecls, Location, Place, Rvalue, Statement, StatementKind, - Terminator, TerminatorKind, + TerminatorKind, }, ty::{TyCtxt, TyKind}, }; @@ -354,8 +354,10 @@ impl<'tcx> CVoidCasts<'tcx> { /// in a sequence of [Statement]s. We expect that the /// cast is the first non-[StatementKind::StorageDead] /// statement in the block, a special case for - /// [Terminator]s whose destination is casted from a + /// [`Terminator`]s whose destination is casted from a /// void pointer to some other pointer type. + /// + /// [`Terminator`]: rustc_middle::mir::Terminator fn find_first_cast( statements: &[Statement<'tcx>], c_void_ptr: CVoidPtr<'tcx>, From 63661f78b154e1110bed56370eab5fc5c3687ca9 Mon Sep 17 00:00:00 2001 From: David Anekstein Date: Mon, 28 Aug 2023 17:49:43 -0400 Subject: [PATCH 13/17] assert c_void_ptr casts are MIR temp locals --- c2rust-analyze/src/c_void_casts.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/c2rust-analyze/src/c_void_casts.rs b/c2rust-analyze/src/c_void_casts.rs index 31b8e9f2e4..b15bf97620 100644 --- a/c2rust-analyze/src/c_void_casts.rs +++ b/c2rust-analyze/src/c_void_casts.rs @@ -1,6 +1,7 @@ use std::borrow::Borrow; use std::collections::{HashMap, HashSet}; +use rustc_middle::mir::LocalKind; use rustc_middle::{ mir::{ BasicBlockData, Body, LocalDecls, Location, Place, Rvalue, Statement, StatementKind, @@ -493,6 +494,7 @@ impl<'tcx> CVoidCasts<'tcx> { "Duplicate c_void_ptr.place found: {:?}", c_void_ptr.place ); + assert_eq!(body.local_kind(c_void_ptr.place.local), LocalKind::Temp); let location = Location { statement_index, block: current_block, From b398bb5128e4faa90286831f3f1905866e386708 Mon Sep 17 00:00:00 2001 From: David Anekstein Date: Mon, 28 Aug 2023 17:59:37 -0400 Subject: [PATCH 14/17] memset: perform a pseudo-assignment for *dest = *src --- c2rust-analyze/src/dataflow/type_check.rs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/c2rust-analyze/src/dataflow/type_check.rs b/c2rust-analyze/src/dataflow/type_check.rs index b0a96415ff..3b7ae89b03 100644 --- a/c2rust-analyze/src/dataflow/type_check.rs +++ b/c2rust-analyze/src/dataflow/type_check.rs @@ -527,19 +527,17 @@ impl<'tcx> TypeChecker<'tcx, '_> { src_ptr, ); self.visit_place(out_ptr, Mutability::Mut); - let _pl_lty = self.acx.type_of(out_ptr); + let dest_ptr_lty = self.acx.type_of(out_ptr); assert!(args.len() == 3); self.visit_place(src_ptr, Mutability::Not); - let rv_lty = self.acx.type_of(src_ptr); + let src_ptr_lty = self.acx.type_of(src_ptr); // input needs READ permission let perms = PermissionSet::READ; - self.constraints.add_all_perms(rv_lty.label, perms); + self.constraints.add_all_perms(src_ptr_lty.label, perms); - // TODO: the return values of `memcpy` are rarely used - // and may not always be casted to a non-void-pointer, - // so avoid unifying for now - // self.do_equivalence_nested(pl_lty, rv_lty); + // Perform a pseudo-assignment for *dest = *src + self.do_equivalence_nested(dest_ptr_lty.args[0], src_ptr_lty.args[0]); } Callee::Memset => { let dest_ptr = args[0] From d10a36903472b5717580e81586b047a5e9f781bf Mon Sep 17 00:00:00 2001 From: David Anekstein Date: Mon, 28 Aug 2023 18:02:28 -0400 Subject: [PATCH 15/17] update comment --- c2rust-analyze/src/c_void_casts.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/c2rust-analyze/src/c_void_casts.rs b/c2rust-analyze/src/c_void_casts.rs index b15bf97620..18fe1bea73 100644 --- a/c2rust-analyze/src/c_void_casts.rs +++ b/c2rust-analyze/src/c_void_casts.rs @@ -475,7 +475,7 @@ impl<'tcx> CVoidCasts<'tcx> { } } - /// Performs BFS in the CFG to find where the c_void_ptr + /// Performs a search in the CFG to find where the c_void_ptr /// was cast to that type fn find_and_insert_pred_cast( &mut self, From 37047e6e7b75bdac1e56c43a45798665a95a73d9 Mon Sep 17 00:00:00 2001 From: David Anekstein Date: Mon, 28 Aug 2023 21:03:44 -0400 Subject: [PATCH 16/17] elaborate on unsupport cast case --- c2rust-analyze/src/c_void_casts.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/c2rust-analyze/src/c_void_casts.rs b/c2rust-analyze/src/c_void_casts.rs index 18fe1bea73..78b7438d4c 100644 --- a/c2rust-analyze/src/c_void_casts.rs +++ b/c2rust-analyze/src/c_void_casts.rs @@ -494,7 +494,10 @@ impl<'tcx> CVoidCasts<'tcx> { "Duplicate c_void_ptr.place found: {:?}", c_void_ptr.place ); - assert_eq!(body.local_kind(c_void_ptr.place.local), LocalKind::Temp); + assert!( + body.local_kind(c_void_ptr.place.local) == LocalKind::Temp, + "Unsupported cast into non-temporary local" + ); let location = Location { statement_index, block: current_block, From df757906184d23bb0e481559f4ef27db6a1da940 Mon Sep 17 00:00:00 2001 From: David Anekstein Date: Mon, 28 Aug 2023 21:18:53 -0400 Subject: [PATCH 17/17] check for multiple assignments to local and panic if present --- c2rust-analyze/src/c_void_casts.rs | 44 ++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/c2rust-analyze/src/c_void_casts.rs b/c2rust-analyze/src/c_void_casts.rs index 78b7438d4c..7b9795c576 100644 --- a/c2rust-analyze/src/c_void_casts.rs +++ b/c2rust-analyze/src/c_void_casts.rs @@ -1,7 +1,7 @@ use std::borrow::Borrow; use std::collections::{HashMap, HashSet}; -use rustc_middle::mir::LocalKind; +use rustc_middle::mir::{BasicBlock, LocalKind}; use rustc_middle::{ mir::{ BasicBlockData, Body, LocalDecls, Location, Place, Rvalue, Statement, StatementKind, @@ -475,8 +475,32 @@ impl<'tcx> CVoidCasts<'tcx> { } } - /// Performs a search in the CFG to find where the c_void_ptr - /// was cast to that type + fn find_modifying_assignments( + current_block: BasicBlock, + current_block_data: &BasicBlockData<'tcx>, + c_void_ptr: &CVoidPtr<'tcx>, + ) -> Vec<(BasicBlock, usize)> { + let mut modifying_statements = current_block_data + .statements + .iter() + .enumerate() + .filter(|(_, stmt)| { + matches!(stmt.kind, StatementKind::Assign(..)) + && Self::is_place_modified_by_statement(&c_void_ptr.place, stmt) + }) + .map(|(index, _stmt)| (current_block, index)) + .collect::>(); + + if let Some(terminator) = ¤t_block_data.terminator { + if matches!(terminator.kind, TerminatorKind::Call { destination, .. } if destination == c_void_ptr.place) + { + modifying_statements.push((current_block, usize::MAX)); + } + } + + modifying_statements + } + fn find_and_insert_pred_cast( &mut self, body: &Body<'tcx>, @@ -485,7 +509,15 @@ impl<'tcx> CVoidCasts<'tcx> { bb_data: &BasicBlockData<'tcx>, ) { let mut inserted_places = HashSet::new(); + let mut modifying_statements = Vec::new(); + for (current_block, current_block_data) in body.basic_blocks().iter_enumerated() { + modifying_statements.extend(Self::find_modifying_assignments( + current_block, + current_block_data, + &c_void_ptr, + )); + if let Some((statement_index, cast)) = Self::find_last_cast(¤t_block_data.statements, c_void_ptr) { @@ -506,6 +538,12 @@ impl<'tcx> CVoidCasts<'tcx> { self.insert_call(direction, terminator_location(current_block, bb_data), cast); } } + + assert!( + modifying_statements.len() == 1, + "c_void_ptr.place modified multiple times: {:?}", + modifying_statements + ); } pub fn new(body: &Body<'tcx>, tcx: TyCtxt<'tcx>) -> Self {