]> git.lizzy.rs Git - rust.git/blobdiff - src/libstd/unstable/dynamic_lib.rs
Find the cratemap at runtime on windows.
[rust.git] / src / libstd / unstable / dynamic_lib.rs
index 64dd5bba6bcf828de6f19e2443ce64e7c9fa3412..41ff79bc8845815db4eda5382c676bb04473eb62 100644 (file)
@@ -15,6 +15,7 @@
 A simple wrapper over the platforms dynamic library facilities
 
 */
+use c_str::ToCStr;
 use cast;
 use path;
 use libc;
 pub struct DynamicLibrary { priv handle: *libc::c_void }
 
 impl Drop for DynamicLibrary {
-    fn finalize(&self) {
+    fn drop(&mut self) {
         match do dl::check_for_errors_in {
             unsafe {
                 dl::close(self.handle)
             }
         } {
-            Ok(()) => { },
+            Ok(()) => {},
             Err(str) => fail!(str)
         }
     }
@@ -41,14 +42,20 @@ impl DynamicLibrary {
     /// Lazily open a dynamic library. When passed None it gives a
     /// handle to the calling process
     pub fn open(filename: Option<&path::Path>) -> Result<DynamicLibrary, ~str> {
-        do dl::check_for_errors_in {
-            unsafe {
-                DynamicLibrary { handle:
-                    match filename {
-                        Some(name) => dl::open_external(name),
-                        None => dl::open_internal()
-                    }
+        unsafe {
+            let maybe_library = do dl::check_for_errors_in {
+                match filename {
+                    Some(name) => dl::open_external(name),
+                    None => dl::open_internal()
                 }
+            };
+
+            // The dynamic library must not be constructed if there is
+            // an error opening the library so the destructor does not
+            // run.
+            match maybe_library {
+                Err(err) => Err(err),
+                Ok(handle) => Ok(DynamicLibrary { handle: handle })
             }
         }
     }
@@ -58,41 +65,72 @@ pub unsafe fn symbol<T>(&self, symbol: &str) -> Result<T, ~str> {
         // This function should have a lifetime constraint of 'self on
         // T but that feature is still unimplemented
 
-        do dl::check_for_errors_in {
-            let symbol_value = do symbol.as_c_str |raw_string| {
+        let maybe_symbol_value = do dl::check_for_errors_in {
+            do symbol.with_c_str |raw_string| {
                 dl::symbol(self.handle, raw_string)
-            };
+            }
+        };
 
-            cast::transmute(symbol_value)
+        // The value must not be constructed if there is an error so
+        // the destructor does not run.
+        match maybe_symbol_value {
+            Err(err) => Err(err),
+            Ok(symbol_value) => Ok(cast::transmute(symbol_value))
         }
     }
 }
 
-#[test]
-#[ignore(cfg(windows))]
-priv fn test_loading_cosine () {
-    // The math library does not need to be loaded since it is already
-    // statically linked in
-    let libm = match DynamicLibrary::open(None) {
-        Err (error) => fail!("Could not load self as module: %s", error),
-        Ok (libm) => libm
-    };
-
-    // Unfortunately due to issue #6194 it is not possible to call
-    // this as a C function
-    let cosine: extern fn(libc::c_double) -> libc::c_double = unsafe {
-        match libm.symbol("cos") {
-            Err (error) => fail!("Could not load function cos: %s", error),
-            Ok (cosine) => cosine
+
+#[cfg(test)]
+mod test {
+    use super::*;
+    use option::*;
+    use result::*;
+    use path::*;
+    use libc;
+
+    #[test]
+    // #[ignore(cfg(windows))] // FIXME #8818
+    #[ignore] // FIXME #9137 this library isn't thread-safe
+    fn test_loading_cosine() {
+        // The math library does not need to be loaded since it is already
+        // statically linked in
+        let libm = match DynamicLibrary::open(None) {
+            Err(error) => fail!("Could not load self as module: %s", error),
+            Ok(libm) => libm
+        };
+
+        // Unfortunately due to issue #6194 it is not possible to call
+        // this as a C function
+        let cosine: extern fn(libc::c_double) -> libc::c_double = unsafe {
+            match libm.symbol("cos") {
+                Err(error) => fail!("Could not load function cos: %s", error),
+                Ok(cosine) => cosine
+            }
+        };
+
+        let argument = 0.0;
+        let expected_result = 1.0;
+        let result = cosine(argument);
+        if result != expected_result {
+            fail!("cos(%?) != %? but equaled %? instead", argument,
+                  expected_result, result)
         }
-    };
+    }
 
-    let argument = 0.0;
-    let expected_result = 1.0;
-    let result = cosine(argument);
-    if result != expected_result {
-        fail!("cos(%?) != %? but equaled %? instead", argument,
-              expected_result, result)
+    #[test]
+    #[cfg(target_os = "linux")]
+    #[cfg(target_os = "macos")]
+    #[cfg(target_os = "freebsd")]
+    #[ignore] // FIXME #9137 this library isn't thread-safe
+    fn test_errors_do_not_crash() {
+        // Open /dev/null as a library to get an error, and make sure
+        // that only causes an error, and not a crash.
+        let path = GenericPath::from_str("/dev/null");
+        match DynamicLibrary::open(Some(&path)) {
+            Err(_) => {}
+            Ok(_) => fail!("Successfully opened the empty library.")
+        }
     }
 }
 
@@ -100,27 +138,33 @@ pub unsafe fn symbol<T>(&self, symbol: &str) -> Result<T, ~str> {
 #[cfg(target_os = "android")]
 #[cfg(target_os = "macos")]
 #[cfg(target_os = "freebsd")]
-mod dl {
+pub mod dl {
+    use c_str::ToCStr;
     use libc;
     use path;
     use ptr;
     use str;
-    use task;
+    use unstable::sync::atomically;
     use result::*;
 
     pub unsafe fn open_external(filename: &path::Path) -> *libc::c_void {
-        do filename.to_str().as_c_str |raw_name| {
+        #[fixed_stack_segment]; #[inline(never)];
+        do filename.with_c_str |raw_name| {
             dlopen(raw_name, Lazy as libc::c_int)
         }
     }
 
     pub unsafe fn open_internal() -> *libc::c_void {
+        #[fixed_stack_segment]; #[inline(never)];
+
         dlopen(ptr::null(), Lazy as libc::c_int)
     }
 
     pub fn check_for_errors_in<T>(f: &fn()->T) -> Result<T, ~str> {
+        #[fixed_stack_segment]; #[inline(never)];
+
         unsafe {
-            do task::atomically {
+            do atomically {
                 let _old_error = dlerror();
 
                 let result = f();
@@ -136,9 +180,13 @@ pub fn check_for_errors_in<T>(f: &fn()->T) -> Result<T, ~str> {
     }
 
     pub unsafe fn symbol(handle: *libc::c_void, symbol: *libc::c_char) -> *libc::c_void {
+        #[fixed_stack_segment]; #[inline(never)];
+
         dlsym(handle, symbol)
     }
     pub unsafe fn close(handle: *libc::c_void) {
+        #[fixed_stack_segment]; #[inline(never)];
+
         dlclose(handle); ()
     }
 
@@ -159,30 +207,32 @@ pub enum RTLD {
 }
 
 #[cfg(target_os = "win32")]
-mod dl {
+pub mod dl {
     use os;
     use libc;
     use path;
     use ptr;
-    use str;
-    use task;
+    use unstable::sync::atomically;
     use result::*;
 
     pub unsafe fn open_external(filename: &path::Path) -> *libc::c_void {
+        #[fixed_stack_segment]; #[inline(never)];
         do os::win32::as_utf16_p(filename.to_str()) |raw_name| {
             LoadLibraryW(raw_name)
         }
     }
 
     pub unsafe fn open_internal() -> *libc::c_void {
-        let mut handle = ptr::null();
+        #[fixed_stack_segment]; #[inline(never)];
+        let handle = ptr::null();
         GetModuleHandleExW(0 as libc::DWORD, ptr::null(), &handle as **libc::c_void);
         handle
     }
 
     pub fn check_for_errors_in<T>(f: &fn()->T) -> Result<T, ~str> {
+        #[fixed_stack_segment]; #[inline(never)];
         unsafe {
-            do task::atomically {
+            do atomically {
                 SetLastError(0);
 
                 let result = f();
@@ -197,12 +247,15 @@ pub fn check_for_errors_in<T>(f: &fn()->T) -> Result<T, ~str> {
         }
     }
     pub unsafe fn symbol(handle: *libc::c_void, symbol: *libc::c_char) -> *libc::c_void {
+        #[fixed_stack_segment]; #[inline(never)];
         GetProcAddress(handle, symbol)
     }
     pub unsafe fn close(handle: *libc::c_void) {
+        #[fixed_stack_segment]; #[inline(never)];
         FreeLibrary(handle); ()
     }
 
+    #[cfg(target_arch = "x86")]
     #[link_name = "kernel32"]
     extern "stdcall" {
         fn SetLastError(error: u32);
@@ -212,4 +265,15 @@ fn GetModuleHandleExW(dwFlags: libc::DWORD, name: *u16,
         fn GetProcAddress(handle: *libc::c_void, name: *libc::c_char) -> *libc::c_void;
         fn FreeLibrary(handle: *libc::c_void);
     }
+
+    #[cfg(target_arch = "x86_64")]
+    #[link_name = "kernel32"]
+    extern {
+        fn SetLastError(error: u32);
+        fn LoadLibraryW(name: *u16) -> *libc::c_void;
+        fn GetModuleHandleExW(dwFlags: libc::DWORD, name: *u16,
+                              handle: **libc::c_void) -> *libc::c_void;
+        fn GetProcAddress(handle: *libc::c_void, name: *libc::c_char) -> *libc::c_void;
+        fn FreeLibrary(handle: *libc::c_void);
+    }
 }