about summary refs log tree commit diff
path: root/src/libstd
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2013-08-03 10:04:58 -0700
committerbors <bors@rust-lang.org>2013-08-03 10:04:58 -0700
commit800dbffa698007abb5b4318538c8c2ffbd08010b (patch)
tree81e846a1aa116a9c5e04472bca340d6e74c01aa7 /src/libstd
parent34101d2320583a0a95ab3afc4c2b6b75dadb5cd7 (diff)
parent2047026fefa38773ecdb046998a65ca1e1dc9cef (diff)
downloadrust-800dbffa698007abb5b4318538c8c2ffbd08010b.tar.gz
rust-800dbffa698007abb5b4318538c8c2ffbd08010b.zip
auto merge of #8219 : sstewartgallus/rust/fix_dynamic_lib, r=graydon
A test case was also created for this situation to prevent the problem
occuring again.

A similar problem was also fixed for the symbol method.

There was some minor code cleanup.

I am unsatisfied with using /dev/null as an invalid dynamic library. It is not cross platform.
Diffstat (limited to 'src/libstd')
-rw-r--r--src/libstd/unstable/dynamic_lib.rs106
1 files changed, 70 insertions, 36 deletions
diff --git a/src/libstd/unstable/dynamic_lib.rs b/src/libstd/unstable/dynamic_lib.rs
index ab44520454d..8d5654255f1 100644
--- a/src/libstd/unstable/dynamic_lib.rs
+++ b/src/libstd/unstable/dynamic_lib.rs
@@ -31,7 +31,7 @@ impl Drop for DynamicLibrary {
                 dl::close(self.handle)
             }
         } {
-            Ok(()) => { },
+            Ok(()) => {},
             Err(str) => fail!(str)
         }
     }
@@ -41,14 +41,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 +64,69 @@ impl DynamicLibrary {
         // 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.as_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]
+    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)
+        }
+    }
+
+    #[test]
+    #[cfg(target_os = "linux")]
+    #[cfg(target_os = "macos")]
+    #[cfg(target_os = "freebsd")]
+    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.")
         }
-    };
-
-    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)
     }
 }