Skip to content

Commit 3907d59

Browse files
committed
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.
2 parents 861e96f + c6bcea9 commit 3907d59

File tree

5 files changed

+62
-1
lines changed

5 files changed

+62
-1
lines changed

Diff for: src/libstd/env.rs

+10
Original file line numberDiff line numberDiff line change
@@ -702,6 +702,11 @@ pub struct ArgsOs { inner: sys::args::Args }
702702
/// (such as `*` and `?`). On Windows this is not done, and such arguments are
703703
/// passed as-is.
704704
///
705+
/// On glibc Linux, arguments are retrieved by placing a function in .init_array.
706+
/// glibc passes argc, argv, and envp to functions in .init_array, as a non-standard extension.
707+
/// This allows `std::env::args` to work even in a `cdylib` or `staticlib`, as it does on macOS
708+
/// and Windows.
709+
///
705710
/// # Panics
706711
///
707712
/// The returned iterator will panic during iteration if any argument to the
@@ -732,6 +737,11 @@ pub fn args() -> Args {
732737
/// set to arbitrary text, and it may not even exist, so this property should
733738
/// not be relied upon for security purposes.
734739
///
740+
/// On glibc Linux, arguments are retrieved by placing a function in .init_array.
741+
/// glibc passes argc, argv, and envp to functions in .init_array, as a non-standard extension.
742+
/// This allows `std::env::args` to work even in a `cdylib` or `staticlib`, as it does on macOS
743+
/// and Windows.
744+
///
735745
/// # Examples
736746
///
737747
/// ```

Diff for: src/libstd/sys/unix/args.rs

+29-1
Original file line numberDiff line numberDiff line change
@@ -72,12 +72,40 @@ mod imp {
7272
// acquire this mutex reentrantly!
7373
static LOCK: Mutex = Mutex::new();
7474

75-
pub unsafe fn init(argc: isize, argv: *const *const u8) {
75+
unsafe fn really_init(argc: isize, argv: *const *const u8) {
7676
let _guard = LOCK.lock();
7777
ARGC = argc;
7878
ARGV = argv;
7979
}
8080

81+
#[inline(always)]
82+
pub unsafe fn init(_argc: isize, _argv: *const *const u8) {
83+
#[cfg(not(all(target_os = "linux", target_env = "gnu")))]
84+
really_init(_argc, _argv);
85+
}
86+
87+
/// glibc passes argc, argv, and envp to functions in .init_array, as a non-standard extension.
88+
/// This allows `std::env::args` to work even in a `cdylib`, as it does on macOS and Windows.
89+
#[cfg(all(target_os = "linux", target_env = "gnu"))]
90+
#[used]
91+
#[link_section = ".init_array.00099"]
92+
static ARGV_INIT_ARRAY: extern "C" fn(
93+
crate::os::raw::c_int,
94+
*const *const u8,
95+
*const *const u8,
96+
) = {
97+
extern "C" fn init_wrapper(
98+
argc: crate::os::raw::c_int,
99+
argv: *const *const u8,
100+
_envp: *const *const u8,
101+
) {
102+
unsafe {
103+
really_init(argc as isize, argv);
104+
}
105+
}
106+
init_wrapper
107+
};
108+
81109
pub unsafe fn cleanup() {
82110
let _guard = LOCK.lock();
83111
ARGC = 0;
+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# only-gnu
2+
# only-linux
3+
4+
-include ../tools.mk
5+
6+
# This ensures that std::env::args works in a library called from C on glibc Linux.
7+
8+
all:
9+
$(RUSTC) --crate-type=staticlib library.rs
10+
$(CC) program.c $(call STATICLIB,library) $(call OUT_EXE,program) \
11+
$(EXTRACFLAGS) $(EXTRACXXFLAGS)
12+
$(call RUN,program)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
#[no_mangle]
2+
pub extern fn args_check() {
3+
assert_ne!(std::env::args_os().count(), 0);
4+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// ignore-license
2+
void args_check();
3+
4+
int main() {
5+
args_check();
6+
return 0;
7+
}

0 commit comments

Comments
 (0)