Auto merge of #66547 - leo60228:procfs-fallback, r=dtolnay

Fallback to .init_array when no arguments are available on glibc Linux

Linux is one of the only platforms where `std::env::args` doesn't work in a cdylib.
This commit is contained in:
bors 2019-11-29 05:04:51 +00:00
commit 3907d59bcf
5 changed files with 62 additions and 1 deletions

View File

@ -702,6 +702,11 @@ pub struct ArgsOs { inner: sys::args::Args }
/// (such as `*` and `?`). On Windows this is not done, and such arguments are
/// passed as-is.
///
/// On glibc Linux, arguments are retrieved by placing a function in .init_array.
/// glibc passes argc, argv, and envp to functions in .init_array, as a non-standard extension.
/// This allows `std::env::args` to work even in a `cdylib` or `staticlib`, as it does on macOS
/// and Windows.
///
/// # Panics
///
/// The returned iterator will panic during iteration if any argument to the
@ -732,6 +737,11 @@ pub fn args() -> Args {
/// set to arbitrary text, and it may not even exist, so this property should
/// not be relied upon for security purposes.
///
/// On glibc Linux, arguments are retrieved by placing a function in .init_array.
/// glibc passes argc, argv, and envp to functions in .init_array, as a non-standard extension.
/// This allows `std::env::args` to work even in a `cdylib` or `staticlib`, as it does on macOS
/// and Windows.
///
/// # Examples
///
/// ```

View File

@ -72,12 +72,40 @@ mod imp {
// acquire this mutex reentrantly!
static LOCK: Mutex = Mutex::new();
pub unsafe fn init(argc: isize, argv: *const *const u8) {
unsafe fn really_init(argc: isize, argv: *const *const u8) {
let _guard = LOCK.lock();
ARGC = argc;
ARGV = argv;
}
#[inline(always)]
pub unsafe fn init(_argc: isize, _argv: *const *const u8) {
#[cfg(not(all(target_os = "linux", target_env = "gnu")))]
really_init(_argc, _argv);
}
/// glibc passes argc, argv, and envp to functions in .init_array, as a non-standard extension.
/// This allows `std::env::args` to work even in a `cdylib`, as it does on macOS and Windows.
#[cfg(all(target_os = "linux", target_env = "gnu"))]
#[used]
#[link_section = ".init_array.00099"]
static ARGV_INIT_ARRAY: extern "C" fn(
crate::os::raw::c_int,
*const *const u8,
*const *const u8,
) = {
extern "C" fn init_wrapper(
argc: crate::os::raw::c_int,
argv: *const *const u8,
_envp: *const *const u8,
) {
unsafe {
really_init(argc as isize, argv);
}
}
init_wrapper
};
pub unsafe fn cleanup() {
let _guard = LOCK.lock();
ARGC = 0;

View File

@ -0,0 +1,12 @@
# only-gnu
# only-linux
-include ../tools.mk
# This ensures that std::env::args works in a library called from C on glibc Linux.
all:
$(RUSTC) --crate-type=staticlib library.rs
$(CC) program.c $(call STATICLIB,library) $(call OUT_EXE,program) \
$(EXTRACFLAGS) $(EXTRACXXFLAGS)
$(call RUN,program)

View File

@ -0,0 +1,4 @@
#[no_mangle]
pub extern fn args_check() {
assert_ne!(std::env::args_os().count(), 0);
}

View File

@ -0,0 +1,7 @@
// ignore-license
void args_check();
int main() {
args_check();
return 0;
}