diff options
| author | Daniel Micay <danielmicay@gmail.com> | 2014-01-17 20:45:48 -0500 |
|---|---|---|
| committer | Daniel Micay <danielmicay@gmail.com> | 2014-01-17 23:41:31 -0500 |
| commit | ae2a5ecbf600495a80ae4d99853a2ed2c8f6b5e9 (patch) | |
| tree | 699380bedd508918752bc0cfa7c8ebc91aff3ca0 | |
| parent | aa67e13498936c42581f70daaf3b6d028426dde6 (diff) | |
| download | rust-ae2a5ecbf600495a80ae4d99853a2ed2c8f6b5e9.tar.gz rust-ae2a5ecbf600495a80ae4d99853a2ed2c8f6b5e9.zip | |
handle zero-size allocations correctly
The `malloc` family of functions may return a null pointer for a zero-size allocation, which should not be interpreted as an out-of-memory error. If the implementation does not return a null pointer, then handling this will result in memory savings for zero-size types. This also switches some code to `malloc_raw` in order to maintain a centralized point for handling out-of-memory in `rt::global_heap`. Closes #11634
| -rw-r--r-- | src/libextra/c_vec.rs | 8 | ||||
| -rw-r--r-- | src/libnative/io/file.rs | 4 | ||||
| -rw-r--r-- | src/librustuv/net.rs | 4 | ||||
| -rw-r--r-- | src/librustuv/uvll.rs | 11 | ||||
| -rw-r--r-- | src/libstd/libc.rs | 2 | ||||
| -rw-r--r-- | src/libstd/rt/global_heap.rs | 37 | ||||
| -rw-r--r-- | src/libstd/unstable/mutex.rs | 13 |
7 files changed, 42 insertions, 37 deletions
diff --git a/src/libextra/c_vec.rs b/src/libextra/c_vec.rs index 68499cf7032..fc2caa13584 100644 --- a/src/libextra/c_vec.rs +++ b/src/libextra/c_vec.rs @@ -160,21 +160,19 @@ impl <T> Container for CVec<T> { #[cfg(test)] mod tests { - use super::*; use std::libc::*; use std::libc; use std::ptr; + use std::rt::global_heap::malloc_raw; fn malloc(n: uint) -> CVec<u8> { unsafe { - let mem = libc::malloc(n as size_t); - - assert!(mem as int != 0); + let mem = malloc_raw(n); CVec::new_with_dtor(mem as *mut u8, n, - proc() { libc::free(mem); }) + proc() { libc::free(mem as *c_void); }) } } diff --git a/src/libnative/io/file.rs b/src/libnative/io/file.rs index 49290434785..9e1bc977082 100644 --- a/src/libnative/io/file.rs +++ b/src/libnative/io/file.rs @@ -13,7 +13,7 @@ use std::c_str::CString; use std::io::IoError; use std::io; -use std::libc::c_int; +use std::libc::{c_int, c_void}; use std::libc; use std::os; use std::rt::rtio; @@ -548,7 +548,7 @@ pub fn readdir(p: &CString) -> IoResult<~[Path]> { let p = Path::new(p); let star = p.join("*"); as_utf16_p(star.as_str().unwrap(), |path_ptr| { - let wfd_ptr = malloc_raw(rust_list_dir_wfd_size() as uint); + let wfd_ptr = malloc_raw(rust_list_dir_wfd_size() as uint) as *c_void; let find_handle = FindFirstFileW(path_ptr, wfd_ptr as HANDLE); if find_handle as libc::c_int != INVALID_HANDLE_VALUE { let mut paths = ~[]; diff --git a/src/librustuv/net.rs b/src/librustuv/net.rs index ee78585fcfd..a39f6ac286f 100644 --- a/src/librustuv/net.rs +++ b/src/librustuv/net.rs @@ -19,6 +19,7 @@ use std::rt::task::BlockedTask; use std::str; use std::unstable::finally::Finally; use std::vec; +use std::rt::global_heap::malloc_raw; use homing::{HomingIO, HomeHandle}; use stream::StreamWatcher; @@ -122,8 +123,7 @@ fn socket_name(sk: SocketNameKind, handle: *c_void) -> Result<SocketAddr, IoErro // Allocate a sockaddr_storage // since we don't know if it's ipv4 or ipv6 let size = uvll::rust_sockaddr_size(); - let name = libc::malloc(size as size_t); - assert!(!name.is_null()); + let name = malloc_raw(size as uint) as *c_void; let mut namelen = size; let ret = match getsockname(handle, name, &mut namelen) { diff --git a/src/librustuv/uvll.rs b/src/librustuv/uvll.rs index eefccf05a54..0dcc4c5ef52 100644 --- a/src/librustuv/uvll.rs +++ b/src/librustuv/uvll.rs @@ -31,8 +31,9 @@ use std::libc::{size_t, c_int, c_uint, c_void, c_char, c_double}; use std::libc::ssize_t; -use std::libc::{malloc, free}; +use std::libc::free; use std::libc; +use std::rt::global_heap::malloc_raw; #[cfg(test)] use std::libc::uintptr_t; @@ -374,9 +375,7 @@ pub enum uv_membership { pub unsafe fn malloc_handle(handle: uv_handle_type) -> *c_void { assert!(handle != UV_UNKNOWN_HANDLE && handle != UV_HANDLE_TYPE_MAX); let size = uv_handle_size(handle); - let p = malloc(size); - assert!(p.is_not_null()); - return p; + malloc_raw(size as uint) as *c_void } pub unsafe fn free_handle(v: *c_void) { @@ -386,9 +385,7 @@ pub unsafe fn free_handle(v: *c_void) { pub unsafe fn malloc_req(req: uv_req_type) -> *c_void { assert!(req != UV_UNKNOWN_REQ && req != UV_REQ_TYPE_MAX); let size = uv_req_size(req); - let p = malloc(size); - assert!(p.is_not_null()); - return p; + malloc_raw(size as uint) as *c_void } pub unsafe fn free_req(v: *c_void) { diff --git a/src/libstd/libc.rs b/src/libstd/libc.rs index 9cf94e5a1b8..77ac226a7f1 100644 --- a/src/libstd/libc.rs +++ b/src/libstd/libc.rs @@ -3223,7 +3223,7 @@ pub mod funcs { pub fn strtoul(s: *c_char, endp: **c_char, base: c_int) -> c_ulong; pub fn calloc(nobj: size_t, size: size_t) -> *c_void; - pub fn malloc(size: size_t) -> *c_void; + pub fn malloc(size: size_t) -> *mut c_void; pub fn realloc(p: *mut c_void, size: size_t) -> *mut c_void; pub fn free(p: *c_void); pub fn exit(status: c_int) -> !; diff --git a/src/libstd/rt/global_heap.rs b/src/libstd/rt/global_heap.rs index ce4072fb1ab..00195f726cb 100644 --- a/src/libstd/rt/global_heap.rs +++ b/src/libstd/rt/global_heap.rs @@ -9,7 +9,7 @@ // except according to those terms. use libc::{c_void, c_char, size_t, uintptr_t, free, malloc, realloc}; -use ptr::RawPtr; +use ptr::{RawPtr, mut_null}; use unstable::intrinsics::{TyDesc, abort}; use unstable::raw; use mem::size_of; @@ -31,24 +31,37 @@ fn align_to(size: uint, align: uint) -> uint { /// A wrapper around libc::malloc, aborting on out-of-memory #[inline] -pub unsafe fn malloc_raw(size: uint) -> *c_void { - let p = malloc(size as size_t); - if p.is_null() { - // we need a non-allocating way to print an error here - abort(); +pub unsafe fn malloc_raw(size: uint) -> *mut c_void { + // `malloc(0)` may allocate, but it may also return a null pointer + // http://pubs.opengroup.org/onlinepubs/9699919799/functions/malloc.html + if size == 0 { + mut_null() + } else { + let p = malloc(size as size_t); + if p.is_null() { + // we need a non-allocating way to print an error here + abort(); + } + p } - p } /// A wrapper around libc::realloc, aborting on out-of-memory #[inline] pub unsafe fn realloc_raw(ptr: *mut c_void, size: uint) -> *mut c_void { - let p = realloc(ptr, size as size_t); - if p.is_null() { - // we need a non-allocating way to print an error here - abort(); + // `realloc(ptr, 0)` may allocate, but it may also return a null pointer + // http://pubs.opengroup.org/onlinepubs/9699919799/functions/realloc.html + if size == 0 { + free(ptr as *c_void); + mut_null() + } else { + let p = realloc(ptr, size as size_t); + if p.is_null() { + // we need a non-allocating way to print an error here + abort(); + } + p } - p } /// The allocator for unique pointers without contained managed pointers. diff --git a/src/libstd/unstable/mutex.rs b/src/libstd/unstable/mutex.rs index 4d12435e01a..81317b7de79 100644 --- a/src/libstd/unstable/mutex.rs +++ b/src/libstd/unstable/mutex.rs @@ -167,7 +167,7 @@ mod imp { use libc::c_void; use libc; use ptr; - use ptr::RawPtr; + use rt::global_heap::malloc_raw; type pthread_mutex_t = libc::c_void; type pthread_mutexattr_t = libc::c_void; @@ -175,16 +175,14 @@ mod imp { type pthread_condattr_t = libc::c_void; pub unsafe fn init_lock() -> uint { - let block = libc::malloc(rust_pthread_mutex_t_size() as libc::size_t); - assert!(!block.is_null()); + let block = malloc_raw(rust_pthread_mutex_t_size() as uint) as *c_void; let n = pthread_mutex_init(block, ptr::null()); assert_eq!(n, 0); return block as uint; } pub unsafe fn init_cond() -> uint { - let block = libc::malloc(rust_pthread_cond_t_size() as libc::size_t); - assert!(!block.is_null()); + let block = malloc_raw(rust_pthread_cond_t_size() as uint) as *c_void; let n = pthread_cond_init(block, ptr::null()); assert_eq!(n, 0); return block as uint; @@ -249,14 +247,13 @@ mod imp { use libc; use libc::{HANDLE, BOOL, LPSECURITY_ATTRIBUTES, c_void, DWORD, LPCSTR}; use ptr; - use ptr::RawPtr; + use rt::global_heap::malloc_raw; type LPCRITICAL_SECTION = *c_void; static SPIN_COUNT: DWORD = 4000; pub unsafe fn init_lock() -> uint { - let block = libc::malloc(rust_crit_section_size() as libc::size_t); - assert!(!block.is_null()); + let block = malloc_raw(rust_crit_section_size() as uint) as *c_void; InitializeCriticalSectionAndSpinCount(block, SPIN_COUNT); return block as uint; } |
