Browse Source

Merge branch 'socketpair' into 'master'

Various socket-related changes and other

See merge request redox-os/relibc!289
Jeremy Soller 4 years ago
parent
commit
c13ba64832
44 changed files with 280 additions and 119 deletions
  1. 119 10
      src/c_vec.rs
  2. 1 1
      src/header/_aio/cbindgen.toml
  3. 1 1
      src/header/_fenv/cbindgen.toml
  4. 1 1
      src/header/_template/cbindgen.toml
  5. 1 1
      src/header/_wctype/cbindgen.toml
  6. 1 1
      src/header/assert/cbindgen.toml
  7. 1 1
      src/header/ctype/cbindgen.toml
  8. 1 1
      src/header/dirent/cbindgen.toml
  9. 1 1
      src/header/dlfcn/cbindgen.toml
  10. 1 1
      src/header/errno/cbindgen.toml
  11. 1 1
      src/header/fcntl/cbindgen.toml
  12. 1 1
      src/header/float/cbindgen.toml
  13. 1 1
      src/header/fnmatch/cbindgen.toml
  14. 1 1
      src/header/getopt/cbindgen.toml
  15. 1 1
      src/header/grp/cbindgen.toml
  16. 1 1
      src/header/inttypes/cbindgen.toml
  17. 1 1
      src/header/libgen/cbindgen.toml
  18. 1 1
      src/header/limits/cbindgen.toml
  19. 1 1
      src/header/locale/cbindgen.toml
  20. 1 1
      src/header/netdb/cbindgen.toml
  21. 1 1
      src/header/poll/cbindgen.toml
  22. 1 1
      src/header/pwd/cbindgen.toml
  23. 1 1
      src/header/regex/cbindgen.toml
  24. 1 1
      src/header/semaphore/cbindgen.toml
  25. 1 1
      src/header/sgtty/cbindgen.toml
  26. 1 1
      src/header/signal/cbindgen.toml
  27. 1 1
      src/header/stdio/cbindgen.toml
  28. 5 2
      src/header/stdio/mod.rs
  29. 1 1
      src/header/stdlib/cbindgen.toml
  30. 1 1
      src/header/string/cbindgen.toml
  31. 1 1
      src/header/strings/cbindgen.toml
  32. 9 0
      src/header/sys_un/mod.rs
  33. 1 1
      src/header/termios/cbindgen.toml
  34. 1 1
      src/header/time/cbindgen.toml
  35. 1 1
      src/header/unistd/cbindgen.toml
  36. 1 1
      src/header/utime/cbindgen.toml
  37. 1 1
      src/header/wchar/cbindgen.toml
  38. 1 1
      src/header/wctype/cbindgen.toml
  39. 7 43
      src/platform/mod.rs
  40. 5 5
      src/platform/redox/epoll.rs
  41. 84 23
      src/platform/redox/socket.rs
  42. 4 0
      tests/expected/stdio/printf.stdout
  43. 12 0
      tests/stdio/printf.c
  44. 0 1
      tests/verify.sh

+ 119 - 10
src/c_vec.rs

@@ -1,6 +1,10 @@
-use crate::platform::{self, types::*};
+use crate::{
+    io::{self, Write},
+    platform::{self, WriteByte, types::*},
+};
 use core::{
     cmp,
+    fmt,
     iter::IntoIterator,
     mem,
     ops::{Deref, DerefMut},
@@ -53,8 +57,13 @@ impl<T> CVec<T> {
     }
     unsafe fn resize(&mut self, cap: usize) -> Result<(), AllocError> {
         let size = Self::check_mul(cap, mem::size_of::<T>())?;
-        let ptr = NonNull::new(platform::realloc(self.ptr.as_ptr() as *mut c_void, size) as *mut T)
-            .ok_or(AllocError)?;
+        let ptr = if cap == 0 {
+            NonNull::dangling()
+        } else if self.cap > 0 {
+            NonNull::new(platform::realloc(self.ptr.as_ptr() as *mut c_void, size) as *mut T).ok_or(AllocError)?
+        } else {
+            NonNull::new((platform::alloc(size)) as *mut T).ok_or(AllocError)?
+        };
         self.ptr = ptr;
         self.cap = cap;
         Ok(())
@@ -67,14 +76,17 @@ impl<T> CVec<T> {
             start = start.add(1);
         }
     }
+
+    // Push stuff
+
     pub fn reserve(&mut self, required: usize) -> Result<(), AllocError> {
-        let reserved_len = self
+        let required_len = self
             .len
             .checked_add(required)
             .ok_or(AllocError)
             .and_then(Self::check_bounds)?;
-        let new_cap = cmp::min(reserved_len.next_power_of_two(), core::isize::MAX as usize);
-        if new_cap > self.cap {
+        if required_len > self.cap {
+            let new_cap = cmp::min(required_len.next_power_of_two(), core::isize::MAX as usize);
             unsafe {
                 self.resize(new_cap)?;
             }
@@ -82,8 +94,8 @@ impl<T> CVec<T> {
         Ok(())
     }
     pub fn push(&mut self, elem: T) -> Result<(), AllocError> {
+        self.reserve(1)?;
         unsafe {
-            self.reserve(1)?;
             ptr::write(self.ptr.as_ptr().add(self.len), elem);
         }
         self.len += 1; // no need to bounds check, as new len <= cap
@@ -93,21 +105,26 @@ impl<T> CVec<T> {
     where
         T: Copy,
     {
+        self.reserve(elems.len())?;
         unsafe {
-            self.reserve(elems.len())?;
             ptr::copy_nonoverlapping(elems.as_ptr(), self.ptr.as_ptr().add(self.len), elems.len());
         }
         self.len += elems.len(); // no need to bounds check, as new len <= cap
         Ok(())
     }
     pub fn append(&mut self, other: &mut Self) -> Result<(), AllocError> {
+        let len = other.len;
+        other.len = 0; // move
+        self.reserve(len)?;
         unsafe {
-            self.reserve(other.len())?;
-            ptr::copy_nonoverlapping(other.as_ptr(), self.ptr.as_ptr().add(self.len), other.len());
+            ptr::copy_nonoverlapping(other.as_ptr(), self.ptr.as_ptr().add(self.len), len);
         }
         self.len += other.len(); // no need to bounds check, as new len <= cap
         Ok(())
     }
+
+    // Pop stuff
+
     pub fn truncate(&mut self, len: usize) {
         if len < self.len {
             unsafe {
@@ -126,6 +143,18 @@ impl<T> CVec<T> {
         }
         Ok(())
     }
+    pub fn pop(&mut self) -> Option<T> {
+        if self.is_empty() {
+            None
+        } else {
+            let elem = unsafe { ptr::read(self.as_ptr().add(self.len - 1)) };
+            self.len -= 1;
+            Some(elem)
+        }
+    }
+
+    // Misc stuff
+
     pub fn capacity(&self) -> usize {
         self.cap
     }
@@ -176,3 +205,83 @@ impl<'a, T> IntoIterator for &'a mut CVec<T> {
         <&mut [T]>::into_iter(&mut *self)
     }
 }
+
+impl Write for CVec<u8> {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        self.extend_from_slice(buf).map_err(|err| io::Error::new(
+            io::ErrorKind::Other,
+            "AllocStringWriter::write failed to allocate",
+        ))?;
+        Ok(buf.len())
+    }
+    fn flush(&mut self) -> io::Result<()> {
+        Ok(())
+    }
+}
+impl fmt::Write for CVec<u8> {
+    fn write_str(&mut self, s: &str) -> fmt::Result {
+        self.write(s.as_bytes()).map_err(|_| fmt::Error)?;
+        Ok(())
+    }
+}
+impl WriteByte for CVec<u8> {
+    fn write_u8(&mut self, byte: u8) -> fmt::Result {
+        self.write(&[byte]).map_err(|_| fmt::Error)?;
+        Ok(())
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::CVec;
+
+    #[test]
+    fn push_pop() {
+        let mut vec = CVec::new();
+        vec.push(1).unwrap();
+        vec.push(2).unwrap();
+        vec.push(3).unwrap();
+        assert_eq!(&vec[..], &[1, 2, 3]);
+        assert_eq!(vec.pop().unwrap(), 3);
+        assert_eq!(&vec[..], &[1, 2]);
+    }
+    #[test]
+    fn extend_from_slice() {
+        use core_io::Write;
+
+        let mut vec = CVec::new();
+        vec.extend_from_slice(&[1, 2, 3]).unwrap();
+        vec.extend_from_slice(&[4, 5, 6]).unwrap();
+        assert_eq!(&vec[..], &[1, 2, 3, 4, 5, 6]);
+        assert_eq!(vec.write(&[7, 8, 9]).unwrap(), 3);
+        assert_eq!(&vec[..], &[1, 2, 3, 4, 5, 6, 7, 8, 9]);
+    }
+    #[test]
+    fn dropped() {
+        use alloc::rc::Rc;
+
+        let counter = Rc::new(());
+        let mut vec = CVec::with_capacity(3).unwrap();
+        vec.push(Rc::clone(&counter)).unwrap();
+        vec.push(Rc::clone(&counter)).unwrap();
+        vec.push(Rc::clone(&counter)).unwrap();
+        assert_eq!(Rc::strong_count(&counter), 4);
+
+        let popped = vec.pop().unwrap();
+        assert_eq!(Rc::strong_count(&counter), 4);
+        drop(popped);
+        assert_eq!(Rc::strong_count(&counter), 3);
+
+        vec.push(Rc::clone(&counter)).unwrap();
+        vec.push(Rc::clone(&counter)).unwrap();
+        vec.push(Rc::clone(&counter)).unwrap();
+
+        assert_eq!(vec.len(), 5);
+        assert_eq!(Rc::strong_count(&counter), 6);
+        vec.truncate(1);
+        assert_eq!(Rc::strong_count(&counter), 2);
+
+        drop(vec);
+        assert_eq!(Rc::strong_count(&counter), 1);
+    }
+}

+ 1 - 1
src/header/_aio/cbindgen.toml

@@ -1,5 +1,5 @@
 sys_includes = []
-include_guard = "_AIO_H"
+include_guard = "_RELIBC_AIO_H"
 language = "C"
 style = "Tag"
 no_includes = true

+ 1 - 1
src/header/_fenv/cbindgen.toml

@@ -1,5 +1,5 @@
 sys_includes = ["stdint.h", "sys/types.h"]
-include_guard = "_FENV_H"
+include_guard = "_RELIBC_FENV_H"
 language = "C"
 style = "Tag"
 no_includes = true

+ 1 - 1
src/header/_template/cbindgen.toml

@@ -1,5 +1,5 @@
 sys_includes = []
-include_guard = "_TEMPLATE_H"
+include_guard = "_RELIBC_TEMPLATE_H"
 language = "C"
 style = "Tag"
 no_includes = true

+ 1 - 1
src/header/_wctype/cbindgen.toml

@@ -1,5 +1,5 @@
 sys_includes = []
-include_guard = "_WCTYPE_H"
+include_guard = "_RELIBC_WCTYPE_H"
 language = "C"
 style = "Tag"
 no_includes = true

+ 1 - 1
src/header/assert/cbindgen.toml

@@ -1,5 +1,5 @@
 sys_includes = ["bits/assert.h"]
-include_guard = "_ASSERT_H"
+include_guard = "_RELIBC_ASSERT_H"
 language = "C"
 style = "Tag"
 no_includes = true

+ 1 - 1
src/header/ctype/cbindgen.toml

@@ -1,5 +1,5 @@
 sys_includes = ["bits/ctype.h"]
-include_guard = "_CTYPE_H"
+include_guard = "_RELIBC_CTYPE_H"
 language = "C"
 style = "Tag"
 no_includes = true

+ 1 - 1
src/header/dirent/cbindgen.toml

@@ -1,5 +1,5 @@
 sys_includes = ["sys/types.h"]
-include_guard = "_DIRENT_H"
+include_guard = "_RELIBC_DIRENT_H"
 language = "C"
 style = "Both"
 trailer = "#include <bits/dirent.h>"

+ 1 - 1
src/header/dlfcn/cbindgen.toml

@@ -1,5 +1,5 @@
 sys_includes = []
-include_guard = "_DLFCN_H"
+include_guard = "_RELIBC_DLFCN_H"
 language = "C"
 style = "Type"
 no_includes = true

+ 1 - 1
src/header/errno/cbindgen.toml

@@ -1,5 +1,5 @@
 sys_includes = ["bits/errno.h"]
-include_guard = "_ERRNO_H"
+include_guard = "_RELIBC_ERRNO_H"
 language = "C"
 style = "Tag"
 no_includes = true

+ 1 - 1
src/header/fcntl/cbindgen.toml

@@ -1,5 +1,5 @@
 sys_includes = ["stdarg.h", "sys/types.h"]
-include_guard = "_FCNTL_H"
+include_guard = "_RELIBC_FCNTL_H"
 trailer = "#include <bits/fcntl.h>"
 language = "C"
 style = "Tag"

+ 1 - 1
src/header/float/cbindgen.toml

@@ -1,5 +1,5 @@
 sys_includes = ["sys/types.h", "bits/float.h"]
-include_guard = "_FLOAT_H"
+include_guard = "_RELIBC_FLOAT_H"
 language = "C"
 style = "Tag"
 no_includes = true

+ 1 - 1
src/header/fnmatch/cbindgen.toml

@@ -1,4 +1,4 @@
-include_guard = "_FNMATCH_H"
+include_guard = "_RELIBC_FNMATCH_H"
 language = "C"
 style = "Tag"
 no_includes = true

+ 1 - 1
src/header/getopt/cbindgen.toml

@@ -1,5 +1,5 @@
 sys_includes = ["unistd.h"]
-include_guard = "_GETOPT_H"
+include_guard = "_RELIBC_GETOPT_H"
 language = "C"
 style = "Tag"
 no_includes = true

+ 1 - 1
src/header/grp/cbindgen.toml

@@ -1,5 +1,5 @@
 sys_includes = []
-include_guard = "_GRP_H"
+include_guard = "_RELIBC_GRP_H"
 language = "C"
 style = "Tag"
 no_includes = true

+ 1 - 1
src/header/inttypes/cbindgen.toml

@@ -1,5 +1,5 @@
 sys_includes = ["stdint.h", "wchar.h"]
-include_guard = "_INTTYPES_H"
+include_guard = "_RELIBC_INTTYPES_H"
 trailer = "#include <bits/inttypes.h>"
 language = "C"
 style = "Type"

+ 1 - 1
src/header/libgen/cbindgen.toml

@@ -1,5 +1,5 @@
 sys_includes = []
-include_guard = "_LIBGEN_H"
+include_guard = "_RELIBC_LIBGEN_H"
 language = "C"
 style = "Tag"
 no_includes = true

+ 1 - 1
src/header/limits/cbindgen.toml

@@ -1,5 +1,5 @@
 sys_includes = []
-include_guard = "_LIMITS_H"
+include_guard = "_RELIBC_LIMITS_H"
 trailer = "#include <bits/limits.h>"
 language = "C"
 style = "Tag"

+ 1 - 1
src/header/locale/cbindgen.toml

@@ -1,4 +1,4 @@
-include_guard = "_LOCALE_H"
+include_guard = "_RELIBC_LOCALE_H"
 trailer = "#include <bits/locale.h>"
 language = "C"
 style = "Tag"

+ 1 - 1
src/header/netdb/cbindgen.toml

@@ -1,5 +1,5 @@
 sys_includes = ["sys/socket.h", "netinet/in.h"]
-include_guard = "_NETDB_H"
+include_guard = "_RELIBC_NETDB_H"
 trailer = "#include <bits/netdb.h>"
 language = "C"
 style = "Tag"

+ 1 - 1
src/header/poll/cbindgen.toml

@@ -1,5 +1,5 @@
 sys_includes = []
-include_guard = "_POLL_H"
+include_guard = "_RELIBC_POLL_H"
 language = "C"
 style = "Tag"
 no_includes = true

+ 1 - 1
src/header/pwd/cbindgen.toml

@@ -1,5 +1,5 @@
 sys_includes = ["stddef.h", "sys/types.h"]
-include_guard = "_PWD_H"
+include_guard = "_RELIBC_PWD_H"
 language = "C"
 style = "Tag"
 no_includes = true

+ 1 - 1
src/header/regex/cbindgen.toml

@@ -1,5 +1,5 @@
 sys_includes = ["sys/types.h"]
-include_guard = "_REGEX_H"
+include_guard = "_RELIBC_REGEX_H"
 language = "C"
 style = "Type"
 no_includes = true

+ 1 - 1
src/header/semaphore/cbindgen.toml

@@ -1,5 +1,5 @@
 sys_includes = []
-include_guard = "_SEMAPHORE_H"
+include_guard = "_RELIBC_SEMAPHORE_H"
 language = "C"
 style = "Tag"
 no_includes = true

+ 1 - 1
src/header/sgtty/cbindgen.toml

@@ -1,5 +1,5 @@
 sys_includes = ["sys/ioctl.h"]
-include_guard = "_SGTTY_H"
+include_guard = "_RELIBC_SGTTY_H"
 language = "C"
 style = "Tag"
 no_includes = true

+ 1 - 1
src/header/signal/cbindgen.toml

@@ -1,5 +1,5 @@
 sys_includes = ["stdint.h", "sys/types.h"]
-include_guard = "_SIGNAL_H"
+include_guard = "_RELIBC_SIGNAL_H"
 trailer = "#include <bits/signal.h>"
 language = "C"
 style = "Tag"

+ 1 - 1
src/header/stdio/cbindgen.toml

@@ -1,5 +1,5 @@
 sys_includes = ["stdarg.h", "stddef.h", "stdint.h", "sys/types.h"]
-include_guard = "_STDIO_H"
+include_guard = "_RELIBC_STDIO_H"
 trailer = "#include <bits/stdio.h>"
 language = "C"
 style = "Type"

+ 5 - 2
src/header/stdio/mod.rs

@@ -16,6 +16,7 @@ use core::{
 
 use crate::{
     c_str::CStr,
+    c_vec::CVec,
     fs::File,
     header::{
         errno::{self, STR_ERROR},
@@ -1021,9 +1022,11 @@ pub unsafe extern "C" fn vasprintf(
     format: *const c_char,
     ap: va_list,
 ) -> c_int {
-    let mut alloc_writer = platform::AllocStringWriter(ptr::null_mut(), 0);
+    let mut alloc_writer = CVec::new();
     let ret = printf::printf(&mut alloc_writer, format, ap);
-    *strp = alloc_writer.0 as *mut c_char;
+    alloc_writer.push(0).unwrap();
+    alloc_writer.shrink_to_fit().unwrap();
+    *strp = alloc_writer.leak() as *mut c_char;
     ret
 }
 

+ 1 - 1
src/header/stdlib/cbindgen.toml

@@ -1,5 +1,5 @@
 sys_includes = ["stddef.h", "alloca.h"]
-include_guard = "_STDLIB_H"
+include_guard = "_RELIBC_STDLIB_H"
 trailer = "#include <bits/stdlib.h>"
 language = "C"
 style = "Type"

+ 1 - 1
src/header/string/cbindgen.toml

@@ -1,5 +1,5 @@
 sys_includes = ["stddef.h", "stdint.h", "strings.h"]
-include_guard = "_STRING_H"
+include_guard = "_RELIBC_STRING_H"
 language = "C"
 style = "Tag"
 no_includes = true

+ 1 - 1
src/header/strings/cbindgen.toml

@@ -1,5 +1,5 @@
 sys_includes = ["stddef.h", "stdint.h"]
-include_guard = "_STRINGS_H"
+include_guard = "_RELIBC_STRINGS_H"
 language = "C"
 style = "Tag"
 no_includes = true

+ 9 - 0
src/header/sys_un/mod.rs

@@ -5,3 +5,12 @@ pub struct sockaddr_un {
     pub sun_family: sa_family_t,
     pub sun_path: [c_char; 108],
 }
+
+impl sockaddr_un {
+    pub fn path_offset(&self) -> usize {
+        let base = self as *const _ as usize;
+        let path = &self.sun_path as *const _ as usize;
+        trace!("base: {:#X}, path: {:#X}", base, path);
+        path - base
+    }
+}

+ 1 - 1
src/header/termios/cbindgen.toml

@@ -1,5 +1,5 @@
 sys_includes = ["stdint.h"]
-include_guard = "_TERMIOS_H"
+include_guard = "_RELIBC_TERMIOS_H"
 language = "C"
 style = "Tag"
 no_includes = true

+ 1 - 1
src/header/time/cbindgen.toml

@@ -1,5 +1,5 @@
 sys_includes = ["sys/types.h", "stdint.h", "stddef.h"]
-include_guard = "_TIME_H"
+include_guard = "_RELIBC_TIME_H"
 language = "C"
 style = "Tag"
 no_includes = true

+ 1 - 1
src/header/unistd/cbindgen.toml

@@ -1,5 +1,5 @@
 sys_includes = ["stddef.h", "stdint.h", "sys/types.h"]
-include_guard = "_UNISTD_H"
+include_guard = "_RELIBC_UNISTD_H"
 trailer = "#include <bits/fcntl.h>\n#include <bits/unistd.h>"
 language = "C"
 style = "Tag"

+ 1 - 1
src/header/utime/cbindgen.toml

@@ -1,5 +1,5 @@
 sys_includes = []
-include_guard = "_UTIME_H"
+include_guard = "_RELIBC_UTIME_H"
 language = "C"
 style = "Tag"
 no_includes = true

+ 1 - 1
src/header/wchar/cbindgen.toml

@@ -1,5 +1,5 @@
 sys_includes = ["stddef.h", "stdint.h", "time.h", "stdio.h" ]
-include_guard = "_WCHAR_H"
+include_guard = "_RELIBC_WCHAR_H"
 header = "#include <bits/wchar.h>"
 language = "C"
 style = "Type"

+ 1 - 1
src/header/wctype/cbindgen.toml

@@ -1,5 +1,5 @@
 sys_includes = ["stddef.h", "stdint.h", "time.h", "stdio.h" ]
-include_guard = "_WCTYPE_H"
+include_guard = "_RELIBC_WCTYPE_H"
 header = "#include <bits/wctype.h>"
 language = "C"
 style = "Type"

+ 7 - 43
src/platform/mod.rs

@@ -104,45 +104,6 @@ impl Read for FileReader {
     }
 }
 
-pub struct AllocStringWriter(pub *mut u8, pub usize);
-impl Write for AllocStringWriter {
-    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
-        let ptr = unsafe { realloc(self.0 as *mut c_void, self.1 + buf.len() + 1) as *mut u8 };
-        if ptr.is_null() {
-            return Err(io::Error::new(
-                io::ErrorKind::Other,
-                "AllocStringWriter::write failed to allocate",
-            ));
-        }
-        self.0 = ptr;
-
-        unsafe {
-            ptr::copy_nonoverlapping(buf.as_ptr(), self.0.add(self.1), buf.len());
-            self.1 += buf.len();
-            *self.0.add(self.1) = 0;
-        }
-
-        Ok(buf.len())
-    }
-    fn flush(&mut self) -> io::Result<()> {
-        Ok(())
-    }
-}
-impl fmt::Write for AllocStringWriter {
-    fn write_str(&mut self, s: &str) -> fmt::Result {
-        // can't fail
-        self.write(s.as_bytes()).unwrap();
-        Ok(())
-    }
-}
-impl WriteByte for AllocStringWriter {
-    fn write_u8(&mut self, byte: u8) -> fmt::Result {
-        // can't fail
-        self.write(&[byte]).unwrap();
-        Ok(())
-    }
-}
-
 pub struct StringWriter(pub *mut u8, pub usize);
 impl Write for StringWriter {
     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
@@ -155,11 +116,14 @@ impl Write for StringWriter {
                 self.0 = self.0.add(copy_size);
                 *self.0 = 0;
             }
-
-            Ok(copy_size)
-        } else {
-            Ok(0)
         }
+
+        // Pretend the entire slice was written. This is because many functions
+        // (like snprintf) expects a return value that reflects how many bytes
+        // *would have* been written. So keeping track of this information is
+        // good, and then if we want the *actual* written size we can just go
+        // `cmp::min(written, maxlen)`.
+        Ok(buf.len())
     }
     fn flush(&mut self) -> io::Result<()> {
         Ok(())

+ 5 - 5
src/platform/redox/epoll.rs

@@ -29,9 +29,9 @@ impl PalEpoll for Sys {
                         id: fd as usize,
                         flags: syscall::EventFlags::from_bits(unsafe { (*event).events as usize })
                             .expect("epoll: invalid bit pattern"),
-                        // NOTE: Danger when using non 64-bit systems. If this is
-                        // needed, use a box or something
-                        data: unsafe { mem::transmute((*event).data) },
+                        // NOTE: Danger when using something smaller than 64-bit
+                        // systems. If this is needed, use a box or something
+                        data: unsafe { (*event).data.u64 as usize },
                     },
                 ) as c_int
             }
@@ -102,7 +102,7 @@ impl PalEpoll for Sys {
         if bytes_read == -1 {
             return -1;
         }
-        let read = bytes_read as usize / mem::size_of::<epoll_event>();
+        let read = bytes_read as usize / mem::size_of::<syscall::Event>();
 
         let mut count = 0;
         for i in 0..read {
@@ -117,7 +117,7 @@ impl PalEpoll for Sys {
                 }
                 *event_ptr = epoll_event {
                     events: event.flags.bits() as _,
-                    data: mem::transmute(event.data),
+                    data: epoll_data { u64: event.data as u64, },
                     ..Default::default()
                 };
                 count += 1;

+ 84 - 23
src/platform/redox/socket.rs

@@ -9,6 +9,7 @@ use super::{
 use crate::header::{
     arpa_inet::inet_aton,
     netinet_in::{in_port_t, sockaddr_in, in_addr},
+    string::strnlen,
     sys_socket::{constants::*, sa_family_t, sockaddr, socklen_t},
     sys_time::timeval,
     sys_un::sockaddr_un,
@@ -32,13 +33,17 @@ macro_rules! bind_or_connect {
         0
     }};
     ($mode:ident copy, $socket:expr, $address:expr, $address_len:expr) => {{
-        if ($address_len as usize) < mem::size_of::<sockaddr>() {
+        if ($address_len as usize) < mem::size_of::<sa_family_t>() {
             errno = syscall::EINVAL;
             return -1;
         }
 
         let path = match (*$address).sa_family as c_int {
             AF_INET => {
+                if ($address_len as usize) != mem::size_of::<sockaddr_in>() {
+                    errno = syscall::EINVAL;
+                    return -1;
+                }
                 let data = &*($address as *const sockaddr_in);
                 let addr = slice::from_raw_parts(
                     &data.sin_addr.s_addr as *const _ as *const u8,
@@ -58,14 +63,32 @@ macro_rules! bind_or_connect {
             },
             AF_UNIX => {
                 let data = &*($address as *const sockaddr_un);
+
+                // NOTE: It's UB to access data in given address that exceeds
+                // the given address length.
+
+                let maxlen = cmp::min(
+                    // Max path length of the full-sized struct
+                    data.sun_path.len(),
+                    // Length inferred from given addrlen
+                    $address_len as usize - data.path_offset()
+                );
+                let len = cmp::min(
+                    // The maximum length of the address
+                    maxlen,
+                    // The first NUL byte, if any
+                    strnlen(&data.sun_path as *const _, maxlen as size_t),
+                );
+
                 let addr = slice::from_raw_parts(
                     &data.sun_path as *const _ as *const u8,
-                    mem::size_of_val(&data.sun_path),
+                    len,
                 );
                 let path = format!(
                     "{}",
                     str::from_utf8(addr).unwrap()
                 );
+                trace!("path: {:?}", path);
 
                 path
             },
@@ -91,7 +114,7 @@ unsafe fn inner_af_unix(buf: &[u8], address: *mut sockaddr, address_len: *mut so
 
     let path = slice::from_raw_parts_mut(
         &mut data.sun_path as *mut _ as *mut u8,
-        mem::size_of_val(&data.sun_path),
+        data.sun_path.len(),
     );
 
     let len = cmp::min(path.len(), buf.len());
@@ -165,6 +188,19 @@ unsafe fn inner_get_name(
     Ok(0)
 }
 
+fn socket_kind(mut kind: c_int) -> (c_int, usize) {
+    let mut flags = O_RDWR;
+    if kind & SOCK_NONBLOCK == SOCK_NONBLOCK {
+        kind &= !SOCK_NONBLOCK;
+        flags |= O_NONBLOCK;
+    }
+    if kind & SOCK_CLOEXEC == SOCK_CLOEXEC {
+        kind &= !SOCK_CLOEXEC;
+        flags |= O_CLOEXEC;
+    }
+    (kind, flags)
+}
+
 impl PalSocket for Sys {
     unsafe fn accept(socket: c_int, address: *mut sockaddr, address_len: *mut socklen_t) -> c_int {
         let stream = e(syscall::dup(socket as usize, b"listen")) as c_int;
@@ -357,7 +393,7 @@ impl PalSocket for Sys {
         e(Err(syscall::Error::new(syscall::ENOSYS))) as c_int
     }
 
-    unsafe fn socket(domain: c_int, mut kind: c_int, protocol: c_int) -> c_int {
+    unsafe fn socket(domain: c_int, kind: c_int, protocol: c_int) -> c_int {
         if domain != AF_INET && domain != AF_UNIX {
             errno = syscall::EAFNOSUPPORT;
             return -1;
@@ -367,15 +403,7 @@ impl PalSocket for Sys {
         //     return -1;
         // }
 
-        let mut flags = O_RDWR;
-        if kind & SOCK_NONBLOCK == SOCK_NONBLOCK {
-            kind &= !SOCK_NONBLOCK;
-            flags |= O_NONBLOCK;
-        }
-        if kind & SOCK_CLOEXEC == SOCK_CLOEXEC {
-            kind &= !SOCK_CLOEXEC;
-            flags |= O_CLOEXEC;
-        }
+        let (kind, flags) = socket_kind(kind);
 
         // The tcp: and udp: schemes allow using no path,
         // and later specifying one using `dup`.
@@ -386,19 +414,52 @@ impl PalSocket for Sys {
             _ => {
                 errno = syscall::EPROTONOSUPPORT;
                 -1
-            }
+            },
         }
     }
 
     fn socketpair(domain: c_int, kind: c_int, protocol: c_int, sv: &mut [c_int; 2]) -> c_int {
-        eprintln!(
-            "socketpair({}, {}, {}, {:p})",
-            domain,
-            kind,
-            protocol,
-            sv.as_mut_ptr()
-        );
-        unsafe { errno = syscall::ENOSYS };
-        return -1;
+        let (kind, flags) = socket_kind(kind);
+
+        match (domain, kind) {
+            (AF_UNIX, SOCK_STREAM) => {
+                let listener = e(syscall::open("chan:", flags | O_CREAT));
+                if listener == !0 {
+                    return -1;
+                }
+
+                // For now, chan: lets connects be instant, and instead blocks
+                // on any I/O performed. So we don't need to mark this as
+                // nonblocking.
+
+                let fd0 = e(syscall::dup(listener, b"connect"));
+                if fd0 == !0 {
+                    let _ = syscall::close(listener);
+                    return -1;
+                }
+
+                let fd1 = e(syscall::dup(listener, b"listen"));
+                if fd1 == !0 {
+                    let _ = syscall::close(fd0);
+                    let _ = syscall::close(listener);
+                    return -1;
+                }
+
+                sv[0] = fd0 as c_int;
+                sv[1] = fd1 as c_int;
+                0
+            },
+            _ => unsafe {
+                eprintln!(
+                    "socketpair({}, {}, {}, {:p})",
+                    domain,
+                    kind,
+                    protocol,
+                    sv.as_mut_ptr()
+                );
+                errno = syscall::EPROTONOSUPPORT;
+                -1
+            },
+        }
     }
 }

+ 4 - 0
tests/expected/stdio/printf.stdout

@@ -60,3 +60,7 @@ Non-finite float madness:
 %F: INF -INF NAN -NAN
 %g: inf -inf nan -nan
 %G: INF -INF NAN -NAN
+Testing asprintf...
+printed: test string, value: 11
+printed: test string 2, value: 13
+printed: test string 2, value: 13

+ 12 - 0
tests/stdio/printf.c

@@ -74,4 +74,16 @@ int main(void) {
         }
         printf("\n");
     }
+
+    puts("Testing asprintf...");
+    char *s = NULL;
+    int res = asprintf(&s, "test string");
+    printf("printed: %s, value: %d\n", s, res);
+    free(s);
+    res = asprintf(&s, "test string %d", 2);
+    printf("printed: %s, value: %d\n", s, res);
+    free(s);
+    res = asprintf(&s, "test %s %d", "string", 2);
+    printf("printed: %s, value: %d\n", s, res);
+    free(s);
 }

+ 0 - 1
tests/verify.sh

@@ -40,6 +40,5 @@ do
     if [ "${status}" != "0" ]
     then
         echo "# ${name}: failed with status ${status} #"
-        exit 1
     fi
 done