All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] tools/nolibc/string: fix memcmp() implementation
@ 2022-10-21  6:01 Willy Tarreau
  0 siblings, 0 replies; 3+ messages in thread
From: Willy Tarreau @ 2022-10-21  6:01 UTC (permalink / raw)
  To: Paul E. McKenney; +Cc: Rasmus Villemoes, linux-kernel, Willy Tarreau

From: Rasmus Villemoes <linux@rasmusvillemoes.dk>

The C standard says that memcmp() must treat the buffers as consisting
of "unsigned chars". If char happens to be unsigned, the casts are ok,
but then obviously the c1 variable can never contain a negative
value. And when char is signed, the casts are wrong, and there's still
a problem with using an 8-bit quantity to hold the difference, because
that can range from -255 to +255.

For example, assuming char is signed, comparing two 1-byte buffers,
one containing 0x00 and another 0x80, the current implementation would
return -128 for both memcmp(a, b, 1) and memcmp(b, a, 1), whereas one
of those should of course return something positive.

Signed-off-by: Rasmus Villemoes <linux@rasmusvillemoes.dk>
Fixes: 66b6f755ad45 ("rcutorture: Import a copy of nolibc")
Cc: stable@vger.kernel.org # v5.0+
Signed-off-by: Willy Tarreau <w@1wt.eu>
---

Paul,

please also include this patch to your series of fixes. I messed up
with memcmp() making it possibly return a wrong sign depending on the
distance between input bytes. It could for example affect a use case
where it would be used in the same way as with qsort() (even though
we do not implement qsort). I'm sending you separately a second patch
to include a selftest for this one; the selftest does not need to be
backported.

Thank you!
Willy

---

 tools/include/nolibc/string.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/tools/include/nolibc/string.h b/tools/include/nolibc/string.h
index bef35bee9c44..cc1bddcb5927 100644
--- a/tools/include/nolibc/string.h
+++ b/tools/include/nolibc/string.h
@@ -19,9 +19,9 @@ static __attribute__((unused))
 int memcmp(const void *s1, const void *s2, size_t n)
 {
 	size_t ofs = 0;
-	char c1 = 0;
+	int c1 = 0;
 
-	while (ofs < n && !(c1 = ((char *)s1)[ofs] - ((char *)s2)[ofs])) {
+	while (ofs < n && !(c1 = ((unsigned char *)s1)[ofs] - ((unsigned char *)s2)[ofs])) {
 		ofs++;
 	}
 	return c1;
-- 
2.17.5


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [PATCH] tools/nolibc/string: fix memcmp() implementation
  2022-10-10 11:36 Rasmus Villemoes
@ 2022-10-13  6:56 ` Willy Tarreau
  0 siblings, 0 replies; 3+ messages in thread
From: Willy Tarreau @ 2022-10-13  6:56 UTC (permalink / raw)
  To: Rasmus Villemoes; +Cc: linux-kernel

Hi Rasmus,

On Mon, Oct 10, 2022 at 01:36:06PM +0200, Rasmus Villemoes wrote:
> The C standard says that memcmp() must treat the buffers as consisting
> of "unsigned chars". If char happens to be unsigned, the casts are ok,
> but then obviously the c1 variable can never contain a negative
> value. And when char is signed, the casts are wrong, and there's still
> a problem with using an 8-bit quantity to hold the difference, because
> that can range from -255 to +255.
> 
> For example, assuming char is signed, comparing two 1-byte buffers,
> one containing 0x00 and another 0x80, the current implementation would
> return -128 for both memcmp(a, b, 1) and memcmp(b, a, 1), whereas one
> of those should of course return something positive.

You're totally right of course, thank you for spotting this one! I'm
queuing it now.

Regards,
Willy

^ permalink raw reply	[flat|nested] 3+ messages in thread

* [PATCH] tools/nolibc/string: fix memcmp() implementation
@ 2022-10-10 11:36 Rasmus Villemoes
  2022-10-13  6:56 ` Willy Tarreau
  0 siblings, 1 reply; 3+ messages in thread
From: Rasmus Villemoes @ 2022-10-10 11:36 UTC (permalink / raw)
  To: Willy Tarreau; +Cc: Rasmus Villemoes, linux-kernel

The C standard says that memcmp() must treat the buffers as consisting
of "unsigned chars". If char happens to be unsigned, the casts are ok,
but then obviously the c1 variable can never contain a negative
value. And when char is signed, the casts are wrong, and there's still
a problem with using an 8-bit quantity to hold the difference, because
that can range from -255 to +255.

For example, assuming char is signed, comparing two 1-byte buffers,
one containing 0x00 and another 0x80, the current implementation would
return -128 for both memcmp(a, b, 1) and memcmp(b, a, 1), whereas one
of those should of course return something positive.

Signed-off-by: Rasmus Villemoes <linux@rasmusvillemoes.dk>
---
 tools/include/nolibc/string.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/tools/include/nolibc/string.h b/tools/include/nolibc/string.h
index bef35bee9c44..cc1bddcb5927 100644
--- a/tools/include/nolibc/string.h
+++ b/tools/include/nolibc/string.h
@@ -19,9 +19,9 @@ static __attribute__((unused))
 int memcmp(const void *s1, const void *s2, size_t n)
 {
 	size_t ofs = 0;
-	char c1 = 0;
+	int c1 = 0;
 
-	while (ofs < n && !(c1 = ((char *)s1)[ofs] - ((char *)s2)[ofs])) {
+	while (ofs < n && !(c1 = ((unsigned char *)s1)[ofs] - ((unsigned char *)s2)[ofs])) {
 		ofs++;
 	}
 	return c1;
-- 
2.37.2


^ permalink raw reply related	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2022-10-21  6:02 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-10-21  6:01 [PATCH] tools/nolibc/string: fix memcmp() implementation Willy Tarreau
  -- strict thread matches above, loose matches on Subject: below --
2022-10-10 11:36 Rasmus Villemoes
2022-10-13  6:56 ` Willy Tarreau

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.