Hi,
while inspecting the last changes in busybox code I hit some issues in
libbb/strrstr.c. The strrtstr function fails on some corner cases of a little
test program I wrote (and bombs out on NULL pointers):
char* strrstr(const char *haystack, const char *needle)
{
char *tmp = strrchr(haystack, *needle);
if (tmp == NULL || strcmp(tmp, needle) != 0)
return NULL;
return tmp;
}
./test
'baaabaaab' vs. 'aaa' : FAILED
'baaabaaaab' vs. 'aaa' : FAILED
'baaabaab' vs. 'aaa' : FAILED
'aaa' vs. 'aaa' : FAILED
'aaa' vs. 'a' : PASSED
'aaa' vs. 'bbb' : PASSED
'a' vs. 'aaa' : PASSED
'aaa' vs. '' : FAILED
'' vs. 'aaa' : PASSED
'' vs. '' : FAILED
Segmentation fault
I've tried to write a more robust variant:
/*
* The strrstr() function finds the last occurrence of the nul terminated
* substring needle in the nul terminated string haystack. The terminating
* nul characters or NULL pointers are not compared.
*/
char* strrstr(const char *haystack, const char *needle)
{
char *p = (char *)haystack;
char *s1;
char *s2;
if (!haystack || !needle)
return NULL;
while (*p++)
/* VOID */;
p--;
while (p-- != haystack) {
s1 = p;
s2 = (char *)needle;
while (*s1 && *s1++ == *s2++) {
if (!*s2)
return p;
}
}
return NULL;
}
This function passes all of the test cases I could think about:
./test
'baaabaaab' vs. 'aaa' : PASSED
'baaabaaaab' vs. 'aaa' : PASSED
'baaabaab' vs. 'aaa' : PASSED
'aaa' vs. 'aaa' : PASSED
'aaa' vs. 'a' : PASSED
'aaa' vs. 'bbb' : PASSED
'a' vs. 'aaa' : PASSED
'aaa' vs. '' : PASSED
'' vs. 'aaa' : PASSED
'' vs. '' : PASSED
'NULL' vs. 'NULL' : PASSED
'' vs. 'NULL' : PASSED
'NULL' vs. '' : PASSED
'aaa' vs. 'NULL' : PASSED
'NULL' vs. 'aaa' : PASSED
For the moment there is no diff but just a drop in replacement
for strrstr.c for testing and improvement by the list members.
There is a little size increase:
scripts/bloat-o-meter busybox_old busybox_unstripped
function old new delta
strrstr 53 73 +20
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/0 up/down: 20/0) Total: 20 bytes
The strrstr function at the moment is used only in depmod
so the depmod author should check if this new implementation
is suitable to be used.
Hints, critics and improvements are ,as always, welcome.
Ciao,
Tito
/* vi: set sw=4 ts=4: */
/*
* Utility routines.
*
* Copyright (C) 2008 Bernhard Fischer
* Copyright (C) 2008 Tito Ragusa
*
* Licensed under GPLv2 or later, see file License in this tarball for details.
*/
#include "libbb.h"
/*
* The strrstr() function finds the last occurrence of the nul terminated
* substring needle in the nul terminated string haystack. The terminating
* nul characters or NULL pointers are not compared.
*/
char* strrstr(const char *haystack, const char *needle)
{
char *p = (char *)haystack;
char *s1;
char *s2;
if (!haystack || !needle)
return NULL;
while (*p++)
/* VOID */;
p--;
while (p-- != haystack) {
s1 = p;
s2 = (char *)needle;
while (*s1 && *s1++ == *s2++) {
if (!*s2)
return p;
}
}
return NULL;
}
#ifdef STRRSTR_TEST
int main(int argc, char **argv)
{
int ret = 0;
int n;
char *tmp;
ret |= !(n = ((tmp = strrstr("baaabaaab", "aaa")) != NULL && strcmp(tmp, "aaab") == 0));
printf("'baaabaaab' vs. 'aaa' : %s\n", n ? "PASSED" : "FAILED");
ret |= !(n = ((tmp = strrstr("baaabaaaab", "aaa")) != NULL && strcmp(tmp, "aaab") == 0));
printf("'baaabaaaab' vs. 'aaa' : %s\n", n ? "PASSED" : "FAILED");
ret |= !(n = ((tmp = strrstr("baaabaab", "aaa")) != NULL && strcmp(tmp, "aaabaab") == 0));
printf("'baaabaab' vs. 'aaa' : %s\n", n ? "PASSED" : "FAILED");
ret |= !(n = (strrstr("aaa", "aaa") != NULL));
printf("'aaa' vs. 'aaa' : %s\n", n ? "PASSED" : "FAILED");
ret |= !(n = (strrstr("aaa", "a") != NULL));
printf("'aaa' vs. 'a' : %s\n", n ? "PASSED" : "FAILED");
ret |= !(n = (strrstr("aaa", "bbb") == NULL));
printf("'aaa' vs. 'bbb' : %s\n", n ? "PASSED" : "FAILED");
ret |= !(n = (strrstr("a", "aaa") == NULL));
printf("'a' vs. 'aaa' : %s\n", n ? "PASSED" : "FAILED");
ret |= !(n = (strrstr("aaa", "") == NULL));
printf("'aaa' vs. '' : %s\n", n ? "PASSED" : "FAILED");
ret |= !(n = (strrstr("", "aaa") == NULL));
printf("'' vs. 'aaa' : %s\n", n ? "PASSED" : "FAILED");
ret |= !(n = (strrstr("", "") == NULL));
printf("'' vs. '' : %s\n", n ? "PASSED" : "FAILED");
ret |= !(n = (strrstr(NULL, NULL) == NULL));
printf("'NULL' vs. 'NULL' : %s\n", n ? "PASSED" : "FAILED");
ret |= !(n = (strrstr("", NULL) == NULL));
printf("'' vs. 'NULL' : %s\n", n ? "PASSED" : "FAILED");
ret |= !(n = (strrstr(NULL, "") == NULL));
printf("'NULL' vs. '' : %s\n", n ? "PASSED" : "FAILED");
ret |= !(n = (strrstr("aaa", NULL) == NULL));
printf("'aaa' vs. 'NULL' : %s\n", n ? "PASSED" : "FAILED");
ret |= !(n = (strrstr(NULL, "aaa") == NULL));
printf("'NULL' vs. 'aaa' : %s\n", n ? "PASSED" : "FAILED");
return ret;
}
#endif
_______________________________________________
busybox mailing list
[email protected]
http://busybox.net/cgi-bin/mailman/listinfo/busybox