Skip to contentSkip to conversation

Fix recently introduced strnstr() to not search past NUL

PATCH In review André Goddard Rosa 5 participants 8 messages Jan 17, 2010 – Jan 23, 2010

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

cover Fix recently introduced strnstr() to not search past NUL

Also simplify stricmp(), so that we do not increase lib/string.o code size.

André Goddard Rosa (2):
string: simplify stricmp()
string: teach strnstr() to not search past NUL-terminator

 lib/string.c |   38 ++++++++++++++++++--------------------
 1 files changed, 18 insertions(+), 20 deletions(-)
#1 lore raw

PATCH 1/2 string: simplify stricmp()

Removes 32 bytes on core2 with gcc 4.4.1:

   text    data     bss     dec     hex filename
   3196       0       0    3196     c7c lib/string-BEFORE.o
   3164       0       0    3164     c5c lib/string-AFTER.o
cc Joe Perches <[email protected]>
cc Frederic Weisbecker <[email protected]>
cc Andrew Morton <[email protected]>
---
 lib/string.c |   34 +++++++++++++++-------------------
 1 files changed, 15 insertions(+), 19 deletions(-)
lib/string.c +15 -19
index a1cdcfc..0f86245 100644
@@ -36,25 +36,21 @@ int strnicmp(const char *s1, const char *s2, size_t len)
 	/* Yes, Virginia, it had better be unsigned */
 	unsigned char c1, c2;
 
-	c1 = c2 = 0;
-	if (len) {
-		do {
-			c1 = *s1;
-			c2 = *s2;
-			s1++;
-			s2++;
-			if (!c1)
-				break;
-			if (!c2)
-				break;
-			if (c1 == c2)
-				continue;
-			c1 = tolower(c1);
-			c2 = tolower(c2);
-			if (c1 != c2)
-				break;
-		} while (--len);
-	}
+	if (!len)
+		return 0;
+
+	do {
+		c1 = *s1++;
+		c2 = *s2++;
+		if (!c1 || !c2)
+			break;
+		if (c1 == c2)
+			continue;
+		c1 = tolower(c1);
+		c2 = tolower(c2);
+		if (c1 != c2)
+			break;
+	} while (--len);
 	return (int)c1 - (int)c2;
 }
 EXPORT_SYMBOL(strnicmp);
Signature · 1 line
1.6.6.201.g56119
maintainer
#2 lore raw

Re: [PATCH 1/2] string: simplify stricmp()

Quoted 48 lines · On Sat, 16 Jan 2010 18:57:00 -0200 Andr__ Goddard Rosa…

Removes 32 bytes on core2 with gcc 4.4.1:

   text    data     bss     dec     hex filename
   3196       0       0    3196     c7c lib/string-BEFORE.o
   3164       0       0    3164     c5c lib/string-AFTER.o
cc Joe Perches <[email protected]>
cc Frederic Weisbecker <[email protected]>
cc Andrew Morton <[email protected]>
---
 lib/string.c |   34 +++++++++++++++-------------------
 1 files changed, 15 insertions(+), 19 deletions(-)
lib/string.c +8 -19
index a1cdcfc..0f86245 100644
@@ -36,25 +36,21 @@ int strnicmp(const char *s1, const char *s2, size_t len)
 	/* Yes, Virginia, it had better be unsigned */
 	unsigned char c1, c2;
 
-	c1 = c2 = 0;
-	if (len) {
-		do {
-			c1 = *s1;
-			c2 = *s2;
-			s1++;
-			s2++;
-			if (!c1)
-				break;
-			if (!c2)
-				break;
-			if (c1 == c2)
-				continue;
-			c1 = tolower(c1);
-			c2 = tolower(c2);
-			if (c1 != c2)
-				break;
-		} while (--len);
-	}
+	if (!len)
+		return 0;
+
+	do {
+		c1 = *s1++;
+		c2 = *s2++;
+		if (!c1 || !c2)
+			break;

lib/string.c int strnicmp(const char *s1, const char *s2, size_t len) · line 56

Quoted 10 lines
lib/string.c +7 -0
+		if (c1 == c2)
+			continue;
+		c1 = tolower(c1);
+		c2 = tolower(c2);
+		if (c1 != c2)
+			break;
+	} while (--len);
 	return (int)c1 - (int)c2;
 }
 EXPORT_SYMBOL(strnicmp);

hm, that function seems a little broken.

If it reaches the end of s1 or s2 it will return (c1 - c2). If however it detects a difference due to other than end-of-string, it returns (tolower(c1) - tolower(c2)).

IOW, perhaps it should be performing tolower() in the I-reached-end-of-string case.

I wonder what strnicmp() is _supposed_ to return..

#3 lore raw

Re: [PATCH 1/2] string: simplify stricmp()

Quoted 9 lines · Andrew Morton

hm, that function seems a little broken.

If it reaches the end of s1 or s2 it will return (c1 - c2). If however it detects a difference due to other than end-of-string, it returns (tolower(c1) - tolower(c2)).

IOW, perhaps it should be performing tolower() in the I-reached-end-of-string case.

No, it doesn't matter. It's like strcmp - it returns "positive, negative or zero" depending on whether the string compared bigger than, smaller than or equal.

So "(int)c1 - (int)c2" is just a way to do that. And if the string ends and c1 or c2 is NUL, there's no point in doing the "tolower()", because it doesn't matter what the other character is: the sign is all that matters (or, if they are equally long, and both c1 and c2 are zero, then 0).

Quoted 1 line

I wonder what strnicmp() is _supposed_ to return..

Same as strncmp.

We could make it always return -1/0/+1 (many libraries do that - then the return value is guaranteed to also fit in a 'char', not just an 'int'), but it really shouldn't matter for any correct caller.

Linus

#4 lore raw

PATCH 2/2 string: teach strnstr() to not search past NUL-terminator

In reply to André Goddard Rosa

As noticed by Alex Riesen at:
http://marc.info/?l=linux-kernel&m=126364040821071&w=2

cc Li Zefan <[email protected]>
cc Alex Riesen <[email protected]>
cc Andrew Morton <[email protected]>
---
 lib/string.c |    4 +++-
 1 files changed, 3 insertions(+), 1 deletions(-)
lib/string.c +3 -1
index 0f86245..94bad34 100644
@@ -689,11 +689,13 @@ EXPORT_SYMBOL(strstr);
  */
 char *strnstr(const char *s1, const char *s2, size_t len)
 {
-	size_t l1 = len, l2;
+	size_t l1, l2;
 
 	l2 = strlen(s2);
 	if (!l2)
 		return (char *)s1;
+	l1 = strlen(s1);
+	l1 = (l1 <= len) ? l1 : len;
 	while (l1 >= l2) {
 		l1--;
 		if (!memcmp(s1, s2, l2))
Signature · 1 line
1.6.6.201.g56119
#5 lore raw

Re: [PATCH 2/2] string: teach strnstr() to not search past NUL-terminator

Quoted 6 lines · André Goddard Rosa
lib/string.c +0 -0
index 0f86245..94bad34 100644
@@ -689,11 +689,13 @@ EXPORT_SYMBOL(strstr);
  */

lib/string.c EXPORT_SYMBOL(strstr); · line 698

Quoted 10 lines
lib/string.c +3 -1
  char *strnstr(const char *s1, const char *s2, size_t len)
  {
-       size_t l1 = len, l2;
+       size_t l1, l2;
 
        l2 = strlen(s2);
        if (!l2)
                return (char *)s1;
+       l1 = strlen(s1);
+       l1 = (l1 <= len) ? l1 : len;

if (l1 > len)

       l1 = len;

Less code and easier to read.

#6 lore raw

Re: [PATCH 2/2] string: teach strnstr() to not search past NUL-terminator

In reply to André Goddard Rosa
Quoted 3 lines · André Goddard Rosa

As noticed by Alex Riesen at:
http://marc.info/?l=linux-kernel&m=126364040821071&w=2

Please don't make this change, it's the user's responsibility to make sure @len won't exceed @s1's length.

All the string functions of "n" version should work when @s1 is not null-terminated, so don't call strlen() on @s1.

Quoted 27 lines
cc Li Zefan <[email protected]>
cc Alex Riesen <[email protected]>
cc Andrew Morton <[email protected]>
---
 lib/string.c |    4 +++-
 1 files changed, 3 insertions(+), 1 deletions(-)
lib/string.c +3 -1
index 0f86245..94bad34 100644
@@ -689,11 +689,13 @@ EXPORT_SYMBOL(strstr);
  */
 char *strnstr(const char *s1, const char *s2, size_t len)
 {
-	size_t l1 = len, l2;
+	size_t l1, l2;
 
 	l2 = strlen(s2);
 	if (!l2)
 		return (char *)s1;
+	l1 = strlen(s1);
+	l1 = (l1 <= len) ? l1 : len;
 	while (l1 >= l2) {
 		l1--;
 		if (!memcmp(s1, s2, l2))
#7 lore raw

Re: [PATCH 2/2] string: teach strnstr() to not search past NUL-terminator

Quoted 9 lines · Li Zefan
Quoted 3 lines · André Goddard Rosa

As noticed by Alex Riesen at:
http://marc.info/?l=linux-kernel&m=126364040821071&w=2

Please don't make this change, it's the user's responsibility to make sure @len won't exceed @s1's length.

All the string functions of "n" version should work when @s1 is not null-terminated, so don't call strlen() on @s1.

Fair enough, agreed.

Thank you,
André