OSDN Git Service

Fix memmem behavior with empty needles.
authorElliott Hughes <enh@google.com>
Mon, 15 Aug 2016 21:14:40 +0000 (14:14 -0700)
committerElliott Hughes <enh@google.com>
Tue, 16 Aug 2016 19:28:58 +0000 (12:28 -0700)
Change-Id: I8b893d80c27b548652d843af9520d7adc8ba8902

libc/Android.bp
libc/bionic/memmem.cpp [moved from libc/bionic/memmem.c with 59% similarity]
tests/string_test.cpp

index c706935..6ba8ae6 100644 (file)
@@ -7,7 +7,6 @@ libc_common_src_files = [
     "bionic/getpriority.c",
     "bionic/initgroups.c",
     "bionic/isatty.c",
-    "bionic/memmem.c",
     "bionic/pututline.c",
     "bionic/sched_cpualloc.c",
     "bionic/sched_cpucount.c",
@@ -1245,6 +1244,7 @@ cc_library_static {
         "bionic/mbrtoc16.cpp",
         "bionic/mbrtoc32.cpp",
         "bionic/mbstate.cpp",
+        "bionic/memmem.cpp",
         "bionic/mempcpy.cpp",
         "bionic/mkdir.cpp",
         "bionic/mkfifo.cpp",
similarity index 59%
rename from libc/bionic/memmem.c
rename to libc/bionic/memmem.cpp
index e72501b..61d681f 100644 (file)
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
-/*
- * This uses the "Not So Naive" algorithm, a very simple but
- * usually effective algorithm, see:
- * http://www-igm.univ-mlv.fr/~lecroq/string/
- */
+
 #include <string.h>
 
-void *memmem(const void *haystack, size_t n, const void *needle, size_t m)
-{
-    if (m > n || !m || !n)
-        return NULL;
+void* memmem(const void* void_haystack, size_t n, const void* void_needle, size_t m) {
+  const unsigned char* haystack = reinterpret_cast<const unsigned char*>(void_haystack);
+  const unsigned char* needle = reinterpret_cast<const unsigned char*>(void_needle);
+
+  if (n < m) return nullptr;
+
+  if (m == 0) return const_cast<void*>(void_haystack);
+  if (m == 1) return memchr(haystack, needle[0], n);
 
-    if (__builtin_expect((m > 1), 1)) {
-        const unsigned char*  y = (const unsigned char*) haystack;
-        const unsigned char*  x = (const unsigned char*) needle;
-        size_t                j = 0;
-        size_t                k = 1, l = 2;
+  // This uses the "Not So Naive" algorithm, a very simple but usually effective algorithm.
+  // http://www-igm.univ-mlv.fr/~lecroq/string/
+  const unsigned char* y = haystack;
+  const unsigned char* x = needle;
+  size_t j = 0;
+  size_t k = 1, l = 2;
 
-        if (x[0] == x[1]) {
-            k = 2;
-            l = 1;
-        }
-        while (j <= n-m) {
-            if (x[1] != y[j+1]) {
-                j += k;
-            } else {
-                if (!memcmp(x+2, y+j+2, m-2) && x[0] == y[j])
-                    return (void*) &y[j];
-                j += l;
-            }
-        }
+  if (x[0] == x[1]) {
+    k = 2;
+    l = 1;
+  }
+  while (j <= n-m) {
+    if (x[1] != y[j+1]) {
+      j += k;
     } else {
-        /* degenerate case */
-        return memchr(haystack, ((unsigned char*)needle)[0], n);
+      if (!memcmp(x+2, y+j+2, m-2) && x[0] == y[j]) return const_cast<unsigned char*>(&y[j]);
+      j += l;
     }
-    return NULL;
+  }
+  return nullptr;
 }
index 763d65c..385fe33 100644 (file)
@@ -1455,3 +1455,32 @@ TEST(STRING_TEST, memcpy_src_dst_same) {
   }
   RunSingleBufferAlignTest(MEDIUM, DoMemcpySameTest);
 }
+
+TEST(STRING_TEST, memmem_strstr_empty_needle) {
+  const char* some_haystack = "haystack";
+  const char* empty_haystack = "";
+
+  ASSERT_EQ(some_haystack, memmem(some_haystack, 8, "", 0));
+  ASSERT_EQ(empty_haystack, memmem(empty_haystack, 0, "", 0));
+
+  ASSERT_EQ(some_haystack, strstr(some_haystack, ""));
+  ASSERT_EQ(empty_haystack, strstr(empty_haystack, ""));
+}
+
+TEST(STRING_TEST, memmem_smoke) {
+  const char haystack[] = "big\0daddy\0giant\0haystacks";
+  ASSERT_EQ(haystack, memmem(haystack, sizeof(haystack), "", 0));
+  ASSERT_EQ(haystack + 3, memmem(haystack, sizeof(haystack), "", 1));
+  ASSERT_EQ(haystack + 0, memmem(haystack, sizeof(haystack), "b", 1));
+  ASSERT_EQ(haystack + 1, memmem(haystack, sizeof(haystack), "i", 1));
+  ASSERT_EQ(haystack + 4, memmem(haystack, sizeof(haystack), "da", 2));
+  ASSERT_EQ(haystack + 8, memmem(haystack, sizeof(haystack), "y\0g", 3));
+}
+
+TEST(STRING_TEST, strstr_smoke) {
+  const char* haystack = "big daddy/giant haystacks";
+  ASSERT_EQ(haystack, strstr(haystack, ""));
+  ASSERT_EQ(haystack + 0, strstr(haystack, "b"));
+  ASSERT_EQ(haystack + 1, strstr(haystack, "i"));
+  ASSERT_EQ(haystack + 4, strstr(haystack, "da"));
+}