mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-04 02:54:00 +00:00
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
This commit is contained in:
parent
aa67e13498
commit
ae2a5ecbf6
@ -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); })
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 = ~[];
|
||||
|
@ -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) {
|
||||
|
@ -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) {
|
||||
|
@ -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) -> !;
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user