libs/libc/string: Fix sign extension in memset word fill pattern.

When the 'c' parameter has bit 7 set (e.g. 0x80), the int value gets
sign extended (to 0xffffff80 on the signed char platforms).  The word
sized fill pattern was built without truncating to unsigned char
first, so the fast word aligned path wrote the wrong bytes.

Fix both lib_memset.c and lib_bsdmemset.c by casting 'c' to unsigned
char before building the fill pattern, as required by C11 7.24.6.1
which states that memset converts 'c' to unsigned char.

Assisted-by: Claude:claude-opus-5
Signed-off-by: Bowen Wang <wangbowen6@xiaomi.com>
This commit is contained in:
Bowen Wang
2026-08-17 10:47:33 +02:00
committed by Alin Jerpelea
parent 7f5f0f5e53
commit c119a0c0fd
2 changed files with 4 additions and 2 deletions
+2 -1
View File
@@ -48,6 +48,7 @@ FAR void *memset(FAR void *m, int c, size_t n)
{
FAR libc_data_t *aligned_addr;
FAR char *s = (FAR char *)m;
unsigned int d = (unsigned char)c;
libc_data_t buffer;
int i;
@@ -70,7 +71,7 @@ FAR void *memset(FAR void *m, int c, size_t n)
/* If we get this far, we know that n is large and s is word-aligned. */
aligned_addr = (FAR libc_data_t *)s;
buffer = ((unsigned int)c << 8) | c;
buffer = (d << 8) | d;
buffer |= (buffer << 16);
for (i = 32; i < LITTLEBLOCKSIZE * 8; i <<= 1)
{
+2 -1
View File
@@ -50,7 +50,8 @@ FAR void *memset(FAR void *s, int c, size_t n)
*/
uintptr_t addr = (uintptr_t)s;
uint16_t val16 = ((uint16_t)c << 8) | (uint16_t)c;
uint8_t val8 = (uint8_t)c;
uint16_t val16 = ((uint16_t)val8 << 8) | (uint16_t)val8;
uint32_t val32 = ((uint32_t)val16 << 16) | (uint32_t)val16;
#ifdef CONFIG_LIBC_MEMSET_64BIT
uint64_t val64 = ((uint64_t)val32 << 32) | (uint64_t)val32;