Fix memmem behavior with empty needles.

Change-Id: I8b893d80c27b548652d843af9520d7adc8ba8902
This commit is contained in:
Elliott Hughes 2016-08-15 14:14:40 -07:00
parent 228e747b6c
commit cae33ade6c
3 changed files with 56 additions and 31 deletions

View 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",

View file

@ -25,40 +25,36 @@
* 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 (__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;
if (n < m) return nullptr;
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 (m == 0) return const_cast<void*>(void_haystack);
if (m == 1) return memchr(haystack, needle[0], n);
// 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 {
/* 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;
}

View 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"));
}