From 3bb3a3e3225f3488c796d1a9a5b03c053762f677 Mon Sep 17 00:00:00 2001
From: jD91mZM2 <me@krake.one>
Date: Tue, 7 Aug 2018 11:35:23 +0200
Subject: [PATCH] Fix strcpy

---
 src/crt0/src/lib.rs                 | 46 +++++++++++++++++++++--------
 src/string/src/lib.rs               | 40 +++++++++++++++----------
 tests/Makefile                      |  1 +
 tests/expected/string/strcpy.stderr |  0
 tests/expected/string/strcpy.stdout |  3 ++
 tests/string/strcpy.c               | 17 +++++++++++
 6 files changed, 78 insertions(+), 29 deletions(-)
 create mode 100644 tests/expected/string/strcpy.stderr
 create mode 100644 tests/expected/string/strcpy.stdout
 create mode 100644 tests/string/strcpy.c

diff --git a/src/crt0/src/lib.rs b/src/crt0/src/lib.rs
index c9cc2739..2d2ce8f5 100644
--- a/src/crt0/src/lib.rs
+++ b/src/crt0/src/lib.rs
@@ -53,6 +53,7 @@ impl Stack {
         &self.argv0 as *const *const u8
     }
 
+    #[cfg(not(target_os = "redox"))]
     fn envp(&self) -> *const *const u8 {
         unsafe { self.argv().offset(self.argc() + 1) }
     }
@@ -62,30 +63,43 @@ impl Stack {
 #[no_mangle]
 pub unsafe extern "C" fn _start_rust(sp: &'static Stack) -> ! {
     extern "C" {
+        #[cfg(not(target_os = "redox"))]
         fn main(argc: isize, argv: *const *const c_char, envp: *const *const c_char) -> c_int;
+        #[cfg(target_os = "redox")]
+        fn main(argc: isize, argv: *const *const c_char) -> c_int;
     }
 
     let argc = sp.argc();
     let argv = sp.argv();
 
-    let envp = sp.envp();
-    let mut len = 0;
-    while *envp.offset(len) != ptr::null() {
-        len += 1;
+    #[cfg(target_os = "redox")]
+    {
+        // TODO: Redox will support environ like on linux, eventually.
+        // We could implement it using the env: scheme here, but eh.
+        platform::inner_environ = Vec::with_capacity(1);
     }
-    platform::inner_environ = Vec::with_capacity(len as usize + 1);
-    for i in 0..len {
-        let mut item = *envp.offset(i);
+    #[cfg(not(target_os = "redox"))]
+    let envp = sp.envp();
+    #[cfg(not(target_os = "redox"))]
+    {
         let mut len = 0;
-        while *item.offset(len) != 0 {
+        while *envp.offset(len) != ptr::null() {
             len += 1;
         }
-
-        let buf = platform::alloc(len as usize + 1) as *mut c_char;
-        for i in 0..=len {
-            *buf.offset(i) = *item.offset(i) as c_char;
+        platform::inner_environ = Vec::with_capacity(len as usize + 1);
+        for i in 0..len {
+            let mut item = *envp.offset(i);
+            let mut len = 0;
+            while *item.offset(len) != 0 {
+                len += 1;
+            }
+
+            let buf = platform::alloc(len as usize + 1) as *mut c_char;
+            for i in 0..=len {
+                *buf.offset(i) = *item.offset(i) as c_char;
+            }
+            platform::inner_environ.push(buf);
         }
-        platform::inner_environ.push(buf);
     }
     platform::inner_environ.push(ptr::null_mut());
     platform::environ = platform::inner_environ.as_mut_ptr();
@@ -95,11 +109,17 @@ pub unsafe extern "C" fn _start_rust(sp: &'static Stack) -> ! {
     stdio::stdout = stdio::default_stdout.get();
     stdio::stderr = stdio::default_stderr.get();
 
+    #[cfg(not(target_os = "redox"))]
     platform::exit(main(
         argc,
         argv as *const *const c_char,
         envp as *const *const c_char,
     ));
+    #[cfg(target_os = "redox")]
+    platform::exit(main(
+        argc,
+        argv as *const *const c_char,
+    ));
 }
 
 #[panic_implementation]
diff --git a/src/string/src/lib.rs b/src/string/src/lib.rs
index ea9606dc..7960febb 100644
--- a/src/string/src/lib.rs
+++ b/src/string/src/lib.rs
@@ -150,8 +150,21 @@ pub unsafe extern "C" fn strcoll(s1: *const c_char, s2: *const c_char) -> c_int
 }
 
 #[no_mangle]
-pub unsafe extern "C" fn strcpy(s1: *mut c_char, s2: *const c_char) -> *mut c_char {
-    strncpy(s1, s2, usize::MAX)
+pub unsafe extern "C" fn strcpy(dst: *mut c_char, src: *const c_char) -> *mut c_char {
+    let mut i = 0;
+
+    loop {
+        let byte = *src.offset(i);
+        *dst.offset(i) = byte;
+
+        if byte == 0 {
+            break;
+        }
+
+        i += 1;
+    }
+
+    dst
 }
 
 pub unsafe fn inner_strspn(s1: *const c_char, s2: *const c_char, cmp: bool) -> size_t {
@@ -270,24 +283,19 @@ pub unsafe extern "C" fn strncmp(s1: *const c_char, s2: *const c_char, n: usize)
 }
 
 #[no_mangle]
-pub unsafe extern "C" fn strncpy(s1: *mut c_char, s2: *const c_char, n: usize) -> *mut c_char {
-    let s2_slice = platform::c_str_n(s2, n);
-    let s2_len = s2_slice.len();
-
-    //memcpy(s1 as *mut _, s2 as *const _, cmp::min(n, s2_len));
-    let mut idx = 0;
-    for _ in 0..cmp::min(n, s2_len) {
-        *s1.offset(idx as isize) = s2_slice[idx] as c_char;
-        idx += 1;
+pub unsafe extern "C" fn strncpy(dst: *mut c_char, src: *const c_char, n: usize) -> *mut c_char {
+    let mut i = 0;
+
+    while *src.offset(i) != 0 && (i as usize) < n {
+        *dst.offset(i) = *src.offset(i);
+        i += 1;
     }
 
-    // if length of s2 < n, pad s1 with zeroes
-    while idx < s2_len {
-        *s1.offset(idx as isize) = 0;
-        idx += 1;
+    for i in i..n as isize {
+        *dst.offset(i) = 0;
     }
 
-    s1
+    dst
 }
 
 #[no_mangle]
diff --git a/tests/Makefile b/tests/Makefile
index 82bd1f80..de3e0b85 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -32,6 +32,7 @@ EXPECT_BINS=\
 	stdlib/system \
 	string/mem \
 	string/strchr \
+	string/strcpy \
 	string/strcspn \
 	string/strncmp \
 	string/strpbrk \
diff --git a/tests/expected/string/strcpy.stderr b/tests/expected/string/strcpy.stderr
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/expected/string/strcpy.stdout b/tests/expected/string/strcpy.stdout
new file mode 100644
index 00000000..84caf120
--- /dev/null
+++ b/tests/expected/string/strcpy.stdout
@@ -0,0 +1,3 @@
+strcpy works!
+strncpy works!
+strncpy shaaaaaaaaa
diff --git a/tests/string/strcpy.c b/tests/string/strcpy.c
new file mode 100644
index 00000000..f0c7d792
--- /dev/null
+++ b/tests/string/strcpy.c
@@ -0,0 +1,17 @@
+#include <stdio.h>
+#include <string.h>
+
+int main() {
+    char dst[20];
+
+    strcpy(dst, "strcpy works!");
+    puts(dst);
+    strncpy(dst, "strncpy works!", 20);
+    puts(dst);
+
+    // Make sure no NUL is placed
+    memset(dst, 'a', 20);
+    dst[19] = 0;
+    strncpy(dst, "strncpy should work here too", 10);
+    puts(dst);
+}
-- 
GitLab