about summary refs log tree commit diff
path: root/src/libstd/sys
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2019-11-29 05:04:51 +0000
committerbors <bors@rust-lang.org>2019-11-29 05:04:51 +0000
commit3907d59bcf6824f32bf9c91205f0c2dbcc467658 (patch)
treee136b73a01468cbac8f3e9b6c1666f9dd9927cd1 /src/libstd/sys
parent861e96f2e9fabe04965899f30598115dd3a163e9 (diff)
parentc6bcea965d3efd57b87ef590ad3b593a89253d96 (diff)
downloadrust-3907d59bcf6824f32bf9c91205f0c2dbcc467658.tar.gz
rust-3907d59bcf6824f32bf9c91205f0c2dbcc467658.zip
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.
Diffstat (limited to 'src/libstd/sys')
-rw-r--r--src/libstd/sys/unix/args.rs30
1 files changed, 29 insertions, 1 deletions
diff --git a/src/libstd/sys/unix/args.rs b/src/libstd/sys/unix/args.rs
index 82ef35ea7b5..15dafb1bcf9 100644
--- a/src/libstd/sys/unix/args.rs
+++ b/src/libstd/sys/unix/args.rs
@@ -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;