From b26213731c7a459f54ed80eabd0cfe584ca7d01e Mon Sep 17 00:00:00 2001
From: jD91mZM2 <me@krake.one>
Date: Wed, 8 Aug 2018 13:25:26 +0200
Subject: [PATCH] Don't forget to lock stdout when printfing

---
 src/platform/src/lib.rs | 34 +++++++++++++++--------------
 src/stdio/src/lib.rs    | 48 ++++++++++++++++++++++++++---------------
 src/stdio/src/scanf.rs  | 12 +++++++----
 3 files changed, 57 insertions(+), 37 deletions(-)

diff --git a/src/platform/src/lib.rs b/src/platform/src/lib.rs
index 1921a024..37964737 100644
--- a/src/platform/src/lib.rs
+++ b/src/platform/src/lib.rs
@@ -129,12 +129,12 @@ impl<'a, W: Write> Write for &'a mut W {
 }
 
 pub trait Read {
-    fn read_u8(&mut self, byte: &mut u8) -> bool;
+    fn read_u8(&mut self) -> Result<Option<u8>, ()>;
 }
 
 impl<'a, R: Read> Read for &'a mut R {
-    fn read_u8(&mut self, byte: &mut u8) -> bool {
-        (**self).read_u8(byte)
+    fn read_u8(&mut self) -> Result<Option<u8>, ()> {
+        (**self).read_u8()
     }
 }
 
@@ -169,11 +169,13 @@ impl FileReader {
 }
 
 impl Read for FileReader {
-    fn read_u8(&mut self, byte: &mut u8) -> bool {
-        let mut buf = [*byte];
-        let n = self.read(&mut buf);
-        *byte = buf[0];
-        n > 0
+    fn read_u8(&mut self) -> Result<Option<u8>, ()> {
+        let mut buf = [0];
+        match self.read(&mut buf) {
+            0 => Ok(None),
+            n if n < 0 => Err(()),
+            _ => Ok(Some(buf[0]))
+        }
     }
 }
 
@@ -241,13 +243,13 @@ impl Write for UnsafeStringWriter {
 pub struct StringReader<'a>(pub &'a [u8]);
 
 impl<'a> Read for StringReader<'a> {
-    fn read_u8(&mut self, byte: &mut u8) -> bool {
+    fn read_u8(&mut self) -> Result<Option<u8>, ()> {
         if self.0.is_empty() {
-            false
+            Ok(None)
         } else {
-            *byte = self.0[0];
+            let byte = self.0[0];
             self.0 = &self.0[1..];
-            true
+            Ok(Some(byte))
         }
     }
 }
@@ -255,14 +257,14 @@ impl<'a> Read for StringReader<'a> {
 pub struct UnsafeStringReader(pub *const u8);
 
 impl Read for UnsafeStringReader {
-    fn read_u8(&mut self, byte: &mut u8) -> bool {
+    fn read_u8(&mut self) -> Result<Option<u8>, ()> {
         unsafe {
             if *self.0 == 0 {
-                false
+                Ok(None)
             } else {
-                *byte = *self.0;
+                let byte = *self.0;
                 self.0 = self.0.offset(1);
-                true
+                Ok(Some(byte))
             }
         }
     }
diff --git a/src/stdio/src/lib.rs b/src/stdio/src/lib.rs
index e9b25a8f..993a88ff 100644
--- a/src/stdio/src/lib.rs
+++ b/src/stdio/src/lib.rs
@@ -16,7 +16,7 @@ extern crate string;
 extern crate va_list as vl;
 
 use core::fmt::Write as WriteFmt;
-use core::fmt::{self, Error, Result};
+use core::fmt::{self, Error};
 use core::sync::atomic::{AtomicBool, Ordering};
 use core::{ptr, str};
 
@@ -171,38 +171,52 @@ impl FILE {
     pub fn seek(&self, off: off_t, whence: c_int) -> off_t {
         platform::lseek(self.fd, off, whence)
     }
+
+    pub fn lock(&mut self) -> LockGuard {
+        flockfile(self);
+        LockGuard(self)
+    }
+}
+
+pub struct LockGuard<'a>(&'a mut FILE);
+impl<'a> Drop for LockGuard<'a> {
+    fn drop(&mut self) {
+        funlockfile(self.0);
+    }
 }
-impl fmt::Write for FILE {
-    fn write_str(&mut self, s: &str) -> Result {
-        if !self.can_write() {
+
+impl<'a> fmt::Write for LockGuard<'a> {
+    fn write_str(&mut self, s: &str) -> fmt::Result {
+        if !self.0.can_write() {
             return Err(Error);
         }
         let s = s.as_bytes();
-        if self.write(s) != s.len() {
+        if self.0.write(s) != s.len() {
             Err(Error)
         } else {
             Ok(())
         }
     }
 }
-impl Write for FILE {
-    fn write_u8(&mut self, byte: u8) -> Result {
-        if !self.can_write() {
+impl<'a> Write for LockGuard<'a> {
+    fn write_u8(&mut self, byte: u8) -> fmt::Result {
+        if !self.0.can_write() {
             return Err(Error);
         }
-        if self.write(&[byte]) != 1 {
+        if self.0.write(&[byte]) != 1 {
             Err(Error)
         } else {
             Ok(())
         }
     }
 }
-impl Read for FILE {
-    fn read_u8(&mut self, byte: &mut u8) -> bool {
-        let mut buf = [*byte];
-        let n = self.read(&mut buf);
-        *byte = buf[0];
-        n > 0
+impl<'a> Read for LockGuard<'a> {
+    fn read_u8(&mut self) -> Result<Option<u8>, ()> {
+        let mut buf = [0];
+        match self.0.read(&mut buf) {
+            0 => Ok(None),
+            _ => Ok(Some(buf[0]))
+        }
     }
 }
 
@@ -913,7 +927,7 @@ pub extern "C" fn ungetc(c: c_int, stream: &mut FILE) -> c_int {
 
 #[no_mangle]
 pub unsafe extern "C" fn vfprintf(file: &mut FILE, format: *const c_char, ap: va_list) -> c_int {
-    printf::printf(file, format, ap)
+    printf::printf(file.lock(), format, ap)
 }
 
 #[no_mangle]
@@ -942,7 +956,7 @@ pub unsafe extern "C" fn vsprintf(s: *mut c_char, format: *const c_char, ap: va_
 
 #[no_mangle]
 pub unsafe extern "C" fn vfscanf(file: &mut FILE, format: *const c_char, ap: va_list) -> c_int {
-    scanf::scanf(file, format, ap)
+    scanf::scanf(file.lock(), format, ap)
 }
 
 #[no_mangle]
diff --git a/src/stdio/src/scanf.rs b/src/stdio/src/scanf.rs
index 2a1ae921..2652c141 100644
--- a/src/stdio/src/scanf.rs
+++ b/src/stdio/src/scanf.rs
@@ -39,11 +39,15 @@ unsafe fn inner_scanf<R: Read>(
 
     macro_rules! read {
         () => {{
-            let n = r.read_u8(&mut byte);
-            if n {
-                count += 1;
+            match r.read_u8() {
+                Ok(Some(b)) => {
+                    byte = b;
+                    count += 1;
+                    true
+                },
+                Ok(None) => false,
+                Err(()) => return Err(-1)
             }
-            n
         }};
     }
 
-- 
GitLab