Skip to content

Commit 52f1d90

Browse files
committed
auto merge of #11635 : thestinger/rust/zero-size-alloc, r=alexcrichton
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
2 parents 53733c8 + ae2a5ec commit 52f1d90

File tree

7 files changed

+42
-37
lines changed

7 files changed

+42
-37
lines changed

src/libextra/c_vec.rs

+3-5
Original file line numberDiff line numberDiff line change
@@ -160,21 +160,19 @@ impl <T> Container for CVec<T> {
160160

161161
#[cfg(test)]
162162
mod tests {
163-
164163
use super::*;
165164

166165
use std::libc::*;
167166
use std::libc;
168167
use std::ptr;
168+
use std::rt::global_heap::malloc_raw;
169169

170170
fn malloc(n: uint) -> CVec<u8> {
171171
unsafe {
172-
let mem = libc::malloc(n as size_t);
173-
174-
assert!(mem as int != 0);
172+
let mem = malloc_raw(n);
175173

176174
CVec::new_with_dtor(mem as *mut u8, n,
177-
proc() { libc::free(mem); })
175+
proc() { libc::free(mem as *c_void); })
178176
}
179177
}
180178

src/libnative/io/file.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
use std::c_str::CString;
1414
use std::io::IoError;
1515
use std::io;
16-
use std::libc::c_int;
16+
use std::libc::{c_int, c_void};
1717
use std::libc;
1818
use std::os;
1919
use std::rt::rtio;
@@ -548,7 +548,7 @@ pub fn readdir(p: &CString) -> IoResult<~[Path]> {
548548
let p = Path::new(p);
549549
let star = p.join("*");
550550
as_utf16_p(star.as_str().unwrap(), |path_ptr| {
551-
let wfd_ptr = malloc_raw(rust_list_dir_wfd_size() as uint);
551+
let wfd_ptr = malloc_raw(rust_list_dir_wfd_size() as uint) as *c_void;
552552
let find_handle = FindFirstFileW(path_ptr, wfd_ptr as HANDLE);
553553
if find_handle as libc::c_int != INVALID_HANDLE_VALUE {
554554
let mut paths = ~[];

src/librustuv/net.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use std::rt::task::BlockedTask;
1919
use std::str;
2020
use std::unstable::finally::Finally;
2121
use std::vec;
22+
use std::rt::global_heap::malloc_raw;
2223

2324
use homing::{HomingIO, HomeHandle};
2425
use stream::StreamWatcher;
@@ -122,8 +123,7 @@ fn socket_name(sk: SocketNameKind, handle: *c_void) -> Result<SocketAddr, IoErro
122123
// Allocate a sockaddr_storage
123124
// since we don't know if it's ipv4 or ipv6
124125
let size = uvll::rust_sockaddr_size();
125-
let name = libc::malloc(size as size_t);
126-
assert!(!name.is_null());
126+
let name = malloc_raw(size as uint) as *c_void;
127127
let mut namelen = size;
128128

129129
let ret = match getsockname(handle, name, &mut namelen) {

src/librustuv/uvll.rs

+4-7
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,9 @@
3131

3232
use std::libc::{size_t, c_int, c_uint, c_void, c_char, c_double};
3333
use std::libc::ssize_t;
34-
use std::libc::{malloc, free};
34+
use std::libc::free;
3535
use std::libc;
36+
use std::rt::global_heap::malloc_raw;
3637

3738
#[cfg(test)]
3839
use std::libc::uintptr_t;
@@ -374,9 +375,7 @@ pub enum uv_membership {
374375
pub unsafe fn malloc_handle(handle: uv_handle_type) -> *c_void {
375376
assert!(handle != UV_UNKNOWN_HANDLE && handle != UV_HANDLE_TYPE_MAX);
376377
let size = uv_handle_size(handle);
377-
let p = malloc(size);
378-
assert!(p.is_not_null());
379-
return p;
378+
malloc_raw(size as uint) as *c_void
380379
}
381380

382381
pub unsafe fn free_handle(v: *c_void) {
@@ -386,9 +385,7 @@ pub unsafe fn free_handle(v: *c_void) {
386385
pub unsafe fn malloc_req(req: uv_req_type) -> *c_void {
387386
assert!(req != UV_UNKNOWN_REQ && req != UV_REQ_TYPE_MAX);
388387
let size = uv_req_size(req);
389-
let p = malloc(size);
390-
assert!(p.is_not_null());
391-
return p;
388+
malloc_raw(size as uint) as *c_void
392389
}
393390

394391
pub unsafe fn free_req(v: *c_void) {

src/libstd/libc.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -3223,7 +3223,7 @@ pub mod funcs {
32233223
pub fn strtoul(s: *c_char, endp: **c_char, base: c_int)
32243224
-> c_ulong;
32253225
pub fn calloc(nobj: size_t, size: size_t) -> *c_void;
3226-
pub fn malloc(size: size_t) -> *c_void;
3226+
pub fn malloc(size: size_t) -> *mut c_void;
32273227
pub fn realloc(p: *mut c_void, size: size_t) -> *mut c_void;
32283228
pub fn free(p: *c_void);
32293229
pub fn exit(status: c_int) -> !;

src/libstd/rt/global_heap.rs

+25-12
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
// except according to those terms.
1010

1111
use libc::{c_void, c_char, size_t, uintptr_t, free, malloc, realloc};
12-
use ptr::RawPtr;
12+
use ptr::{RawPtr, mut_null};
1313
use unstable::intrinsics::{TyDesc, abort};
1414
use unstable::raw;
1515
use mem::size_of;
@@ -31,24 +31,37 @@ fn align_to(size: uint, align: uint) -> uint {
3131

3232
/// A wrapper around libc::malloc, aborting on out-of-memory
3333
#[inline]
34-
pub unsafe fn malloc_raw(size: uint) -> *c_void {
35-
let p = malloc(size as size_t);
36-
if p.is_null() {
37-
// we need a non-allocating way to print an error here
38-
abort();
34+
pub unsafe fn malloc_raw(size: uint) -> *mut c_void {
35+
// `malloc(0)` may allocate, but it may also return a null pointer
36+
// http://pubs.opengroup.org/onlinepubs/9699919799/functions/malloc.html
37+
if size == 0 {
38+
mut_null()
39+
} else {
40+
let p = malloc(size as size_t);
41+
if p.is_null() {
42+
// we need a non-allocating way to print an error here
43+
abort();
44+
}
45+
p
3946
}
40-
p
4147
}
4248

4349
/// A wrapper around libc::realloc, aborting on out-of-memory
4450
#[inline]
4551
pub unsafe fn realloc_raw(ptr: *mut c_void, size: uint) -> *mut c_void {
46-
let p = realloc(ptr, size as size_t);
47-
if p.is_null() {
48-
// we need a non-allocating way to print an error here
49-
abort();
52+
// `realloc(ptr, 0)` may allocate, but it may also return a null pointer
53+
// http://pubs.opengroup.org/onlinepubs/9699919799/functions/realloc.html
54+
if size == 0 {
55+
free(ptr as *c_void);
56+
mut_null()
57+
} else {
58+
let p = realloc(ptr, size as size_t);
59+
if p.is_null() {
60+
// we need a non-allocating way to print an error here
61+
abort();
62+
}
63+
p
5064
}
51-
p
5265
}
5366

5467
/// The allocator for unique pointers without contained managed pointers.

src/libstd/unstable/mutex.rs

+5-8
Original file line numberDiff line numberDiff line change
@@ -167,24 +167,22 @@ mod imp {
167167
use libc::c_void;
168168
use libc;
169169
use ptr;
170-
use ptr::RawPtr;
170+
use rt::global_heap::malloc_raw;
171171

172172
type pthread_mutex_t = libc::c_void;
173173
type pthread_mutexattr_t = libc::c_void;
174174
type pthread_cond_t = libc::c_void;
175175
type pthread_condattr_t = libc::c_void;
176176

177177
pub unsafe fn init_lock() -> uint {
178-
let block = libc::malloc(rust_pthread_mutex_t_size() as libc::size_t);
179-
assert!(!block.is_null());
178+
let block = malloc_raw(rust_pthread_mutex_t_size() as uint) as *c_void;
180179
let n = pthread_mutex_init(block, ptr::null());
181180
assert_eq!(n, 0);
182181
return block as uint;
183182
}
184183

185184
pub unsafe fn init_cond() -> uint {
186-
let block = libc::malloc(rust_pthread_cond_t_size() as libc::size_t);
187-
assert!(!block.is_null());
185+
let block = malloc_raw(rust_pthread_cond_t_size() as uint) as *c_void;
188186
let n = pthread_cond_init(block, ptr::null());
189187
assert_eq!(n, 0);
190188
return block as uint;
@@ -249,14 +247,13 @@ mod imp {
249247
use libc;
250248
use libc::{HANDLE, BOOL, LPSECURITY_ATTRIBUTES, c_void, DWORD, LPCSTR};
251249
use ptr;
252-
use ptr::RawPtr;
250+
use rt::global_heap::malloc_raw;
253251

254252
type LPCRITICAL_SECTION = *c_void;
255253
static SPIN_COUNT: DWORD = 4000;
256254

257255
pub unsafe fn init_lock() -> uint {
258-
let block = libc::malloc(rust_crit_section_size() as libc::size_t);
259-
assert!(!block.is_null());
256+
let block = malloc_raw(rust_crit_section_size() as uint) as *c_void;
260257
InitializeCriticalSectionAndSpinCount(block, SPIN_COUNT);
261258
return block as uint;
262259
}

0 commit comments

Comments
 (0)