Skip to content

Commit

Permalink
[unix] Don't clone command-line args on startup
Browse files Browse the repository at this point in the history
  • Loading branch information
mbrubeck committed Jan 4, 2018
1 parent d96cc6e commit 91c3eee
Showing 1 changed file with 16 additions and 23 deletions.
39 changes: 16 additions & 23 deletions src/libstd/sys/unix/args.rs
Expand Up @@ -69,57 +69,50 @@ impl DoubleEndedIterator for Args {
target_os = "fuchsia"))]
mod imp {
use os::unix::prelude::*;
use mem;
use ptr;
use ffi::{CStr, OsString};
use marker::PhantomData;
use libc;
use super::Args;

use sys_common::mutex::Mutex;

static mut GLOBAL_ARGS_PTR: usize = 0;
static mut ARGC: isize = 0;
static mut ARGV: *const *const u8 = ptr::null();
static LOCK: Mutex = Mutex::new();

pub unsafe fn init(argc: isize, argv: *const *const u8) {
let args = (0..argc).map(|i| {
CStr::from_ptr(*argv.offset(i) as *const libc::c_char).to_bytes().to_vec()
}).collect();

LOCK.lock();
let ptr = get_global_ptr();
assert!((*ptr).is_none());
(*ptr) = Some(box args);
ARGC = argc;
ARGV = argv;
LOCK.unlock();
}

pub unsafe fn cleanup() {
LOCK.lock();
*get_global_ptr() = None;
ARGC = 0;
ARGV = ptr::null();
LOCK.unlock();
}

pub fn args() -> Args {
let bytes = clone().unwrap_or(Vec::new());
let v: Vec<OsString> = bytes.into_iter().map(|v| {
OsStringExt::from_vec(v)
}).collect();
Args { iter: v.into_iter(), _dont_send_or_sync_me: PhantomData }
Args {
iter: clone().into_iter(),
_dont_send_or_sync_me: PhantomData
}
}

fn clone() -> Option<Vec<Vec<u8>>> {
fn clone() -> Vec<OsString> {
unsafe {
LOCK.lock();
let ptr = get_global_ptr();
let ret = (*ptr).as_ref().map(|s| (**s).clone());
let ret = (0..ARGC).map(|i| {
let cstr = CStr::from_ptr(*ARGV.offset(i) as *const libc::c_char);
OsStringExt::from_vec(cstr.to_bytes().to_vec())
}).collect();

This comment has been minimized.

Copy link
@cheako

cheako Jun 12, 2019

I'm confused by the collect() here, why not just return the Map? Looks like there is a useless conversion to Vec then back into_iter().

This comment has been minimized.

Copy link
@mbrubeck

mbrubeck Jun 12, 2019

Author Contributor

I'm confused by the collect() here, why not just return the Map?

The Map is not safe to use after LOCK has been unlocked. This function needs to obtain the lock, eagerly clone and store all the args, release the lock, and then return the cloned data.

Looks like there is a useless conversion to Vec then back into_iter().

It's not possible to create a vec::IntoIter without first creating a Vec. The "conversion" is a trivial operation, since vec::IntoIter<T> is essentially the same as a Vec<T> but with one extra field.

LOCK.unlock();
return ret
}
}

fn get_global_ptr() -> *mut Option<Box<Vec<Vec<u8>>>> {
unsafe { mem::transmute(&GLOBAL_ARGS_PTR) }
}

}

#[cfg(any(target_os = "macos",
Expand Down

0 comments on commit 91c3eee

Please sign in to comment.