diff --git a/src/fn_call.rs b/src/fn_call.rs index d8794fed469..ae6aff10ac2 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -147,6 +147,45 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' )?; } } + "realloc" => { + let old_ptr = this.read_scalar(args[0])?.not_undef()?; + let new_size = this.read_scalar(args[1])?.to_usize(this)?; + let align = this.tcx.data_layout.pointer_align.abi; + if old_ptr.is_null_ptr(this) { + if new_size == 0 { + this.write_null(dest)?; + } else { + let new_ptr = this.memory_mut().allocate( + Size::from_bytes(new_size), + align, + MiriMemoryKind::C.into() + ); + this.write_scalar(Scalar::Ptr(new_ptr), dest)?; + } + } else { + let old_ptr = old_ptr.to_ptr()?; + let memory = this.memory_mut(); + let old_size = Size::from_bytes(memory.get(old_ptr.alloc_id)?.bytes.len() as u64); + if new_size == 0 { + memory.deallocate( + old_ptr, + Some((old_size, align)), + MiriMemoryKind::C.into(), + )?; + this.write_null(dest)?; + } else { + let new_ptr = memory.reallocate( + old_ptr, + old_size, + align, + Size::from_bytes(new_size), + align, + MiriMemoryKind::C.into(), + )?; + this.write_scalar(Scalar::Ptr(new_ptr), dest)?; + } + } + } "__rust_alloc" => { let size = this.read_scalar(args[0])?.to_usize(this)?; diff --git a/tests/run-pass/realloc.rs b/tests/run-pass/realloc.rs new file mode 100644 index 00000000000..c23b3e645c7 --- /dev/null +++ b/tests/run-pass/realloc.rs @@ -0,0 +1,45 @@ +//ignore-windows: Uses POSIX APIs + +#![feature(rustc_private)] + +use core::{slice, ptr}; + +extern crate libc; + +fn main() { + unsafe { + // Use calloc for initialized memory + let p1 = libc::calloc(20, 1); + + // old size < new size + let p2 = libc::realloc(p1, 40); + let slice = slice::from_raw_parts(p2 as *const u8, 20); + assert_eq!(&slice, &[0_u8; 20]); + + // old size == new size + let p3 = libc::realloc(p2, 40); + let slice = slice::from_raw_parts(p3 as *const u8, 20); + assert_eq!(&slice, &[0_u8; 20]); + + // old size > new size + let p4 = libc::realloc(p3, 10); + let slice = slice::from_raw_parts(p4 as *const u8, 10); + assert_eq!(&slice, &[0_u8; 10]); + + libc::free(p4); + } + + unsafe { + let p1 = libc::malloc(20); + + let p2 = libc::realloc(p1, 0); + assert!(p2.is_null()); + } + + unsafe { + let p1 = libc::realloc(ptr::null_mut(), 20); + assert!(!p1.is_null()); + + libc::free(p1); + } +}