about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2013-12-12 17:34:29 -0800
committerAlex Crichton <alex@alexcrichton.com>2013-12-24 14:42:00 -0800
commit76270816d527bfceef64bf6cbdc64f985ca73eba (patch)
tree1b620e0a90a0119e309ff560e2214152e9d608f1 /src
parentdd19785f963fd1045e53447add17ab36ca41fc79 (diff)
downloadrust-76270816d527bfceef64bf6cbdc64f985ca73eba.tar.gz
rust-76270816d527bfceef64bf6cbdc64f985ca73eba.zip
std: Make logging safely implemented
This commit fixes the logging function to be safely implemented, as well as
forcibly requiring a task to be present to use logging macros. This is safely
implemented by transferring ownership of the logger from the task to the local
stack frame in order to perform the print. This means that if a logger does more
logging while logging a new one will be initialized and then will get
overwritten once the initial logging function returns.

Without a scheme such as this, it is possible to unsafely alias two loggers by
logging twice (unsafely borrows from the task twice).
Diffstat (limited to 'src')
-rw-r--r--src/libstd/logging.rs32
1 files changed, 11 insertions, 21 deletions
diff --git a/src/libstd/logging.rs b/src/libstd/logging.rs
index dbe8b3247c0..fb83cfdd6ea 100644
--- a/src/libstd/logging.rs
+++ b/src/libstd/logging.rs
@@ -118,26 +118,16 @@ pub static ERROR: u32 = 1;
 /// It is not recommended to call this function directly, rather it should be
 /// invoked through the logging family of macros.
 pub fn log(_level: u32, args: &fmt::Arguments) {
-    unsafe {
-        let optional_task: Option<*mut Task> = Local::try_unsafe_borrow();
-        match optional_task {
-            Some(local) => {
-                // Lazily initialize the local task's logger
-                match (*local).logger {
-                    // Use the available logger if we have one
-                    Some(ref mut logger) => { logger.log(args); }
-                    None => {
-                        let mut logger = StdErrLogger::new();
-                        logger.log(args);
-                        (*local).logger = Some(logger);
-                    }
-                }
-            }
-            // If there's no local task, then always log to stderr
-            None => {
-                let mut logger = StdErrLogger::new();
-                logger.log(args);
-            }
-        }
+    let mut logger = {
+        let mut task = Local::borrow(None::<Task>);
+        task.get().logger.take()
+    };
+
+    if logger.is_none() {
+        logger = Some(StdErrLogger::new());
     }
+    logger.get_mut_ref().log(args);
+
+    let mut task = Local::borrow(None::<Task>);
+    task.get().logger = logger;
 }