Fix memmem behavior with empty needles.
Change-Id: I8b893d80c27b548652d843af9520d7adc8ba8902
This commit is contained in:
parent
228e747b6c
commit
cae33ade6c
3 changed files with 56 additions and 31 deletions
|
@ -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",
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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"));
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue