From 50f79e9a0e251f3edafa740b348ffcc08634ac74 Mon Sep 17 00:00:00 2001
From: Alex Lyon <arcterus@mail.com>
Date: Fri, 9 Mar 2018 13:19:35 -0800
Subject: [PATCH] string: address performance concerns for strncmp()

---
 src/string/src/lib.rs  | 24 ++++++++----------------
 tests/.gitignore       |  1 +
 tests/Makefile         |  3 ++-
 tests/string/strncmp.c | 15 +++++++++++++++
 4 files changed, 26 insertions(+), 17 deletions(-)
 create mode 100644 tests/string/strncmp.c

diff --git a/src/string/src/lib.rs b/src/string/src/lib.rs
index c272d9211..ce2a68c7f 100644
--- a/src/string/src/lib.rs
+++ b/src/string/src/lib.rs
@@ -156,25 +156,17 @@ pub unsafe extern "C" fn strncat(s1: *mut c_char, s2: *const c_char, n: usize) -
 
 #[no_mangle]
 pub unsafe extern "C" fn strncmp(s1: *const c_char, s2: *const c_char, n: usize) -> c_int {
-    let s1 = platform::c_str_n(s1, n);
-    let s2 = platform::c_str_n(s2, n);
-
-    let min_len = n.min(s1.len()).min(s2.len());
-    for i in 0..min_len {
-        let val = s1[i] - s2[i];
-        if val != 0 {
-            return val as c_int;
+    let s1 = core::slice::from_raw_parts(s1 as *const c_uchar, n);
+    let s2 = core::slice::from_raw_parts(s2 as *const c_uchar, n);
+
+    for (&a, &b) in s1.iter().zip(s2.iter()) {
+        let val = (a as c_int) - (b as c_int);
+        if val != 0 || a == 0 {
+            return val;
         }
     }
 
-    // we can't just check for the NUL byte in the loop as c_str_n() removes it
-    if s1.len() > s2.len() {
-        s1[min_len] as c_int
-    } else if s1.len() < s2.len() {
-        -(s2[min_len] as c_int)
-    } else {
-        0
-    }
+    0
 }
 
 #[no_mangle]
diff --git a/tests/.gitignore b/tests/.gitignore
index 620d8c724..cd04e5ea8 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -27,5 +27,6 @@
 /rmdir
 /setid
 /stdlib/strtol
+/string/strncmp
 /unlink
 /write
diff --git a/tests/Makefile b/tests/Makefile
index ae73d603b..81c5bfe1f 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -21,7 +21,8 @@ BINS=\
 	rmdir \
 	setid \
 	sleep \
-  	stdlib/strtol \
+	stdlib/strtol \
+	string/strncmp \
 	unlink \
 	write
 
diff --git a/tests/string/strncmp.c b/tests/string/strncmp.c
new file mode 100644
index 000000000..3e96e5c36
--- /dev/null
+++ b/tests/string/strncmp.c
@@ -0,0 +1,15 @@
+#include <string.h>
+#include <stdio.h>
+
+int main(int argc, char* argv[]) {
+    printf("%d\n", strncmp("a", "aa", 2));
+    printf("%d\n", strncmp("a", "aä", 2));
+    printf("%d\n", strncmp("\xFF", "\xFE", 2));
+    printf("%d\n", strncmp("", "\xFF", 1));
+    printf("%d\n", strncmp("a", "c", 1));
+    printf("%d\n", strncmp("a", "a", 2));
+
+    puts("test");
+
+    return 0;
+}
-- 
GitLab