Skip to content

Commit 4b768bf

Browse files
committed
Merge tag 'linux_kselftest-nolibc-6.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest
Pull nolibc updates from Shuah Khan: - add support for uname(2) - remove open-coded strnlen() - export strlen() - add tests for strlcat() and strlcpy() - fix memory error in realloc() - fix strlcat() and strlcpy() return code and size usage * tag 'linux_kselftest-nolibc-6.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest: tools/nolibc: add support for uname(2) tools/nolibc/string: remove open-coded strnlen() selftests/nolibc: Add tests for strlcat() and strlcpy() tools/nolibc: Fix strlcpy() return code and size usage tools/nolibc: Fix strlcat() return code and size usage tools/nolibc/string: export strlen() tools/nolibc/stdlib: fix memory error in realloc()
2 parents 5901037 + 0adab2b commit 4b768bf

File tree

4 files changed

+136
-21
lines changed

4 files changed

+136
-21
lines changed

tools/include/nolibc/stdlib.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ void *realloc(void *old_ptr, size_t new_size)
185185
if (__builtin_expect(!ret, 0))
186186
return NULL;
187187

188-
memcpy(ret, heap->user_p, heap->len);
188+
memcpy(ret, heap->user_p, user_p_len);
189189
munmap(heap, heap->len);
190190
return ret;
191191
}

tools/include/nolibc/string.h

Lines changed: 26 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ char *strcpy(char *dst, const char *src)
123123
* thus itself, hence the asm() statement below that's meant to disable this
124124
* confusing practice.
125125
*/
126-
static __attribute__((unused))
126+
__attribute__((weak,unused,section(".text.nolibc_strlen")))
127127
size_t strlen(const char *str)
128128
{
129129
size_t len;
@@ -187,39 +187,45 @@ char *strndup(const char *str, size_t maxlen)
187187
static __attribute__((unused))
188188
size_t strlcat(char *dst, const char *src, size_t size)
189189
{
190-
size_t len;
191-
char c;
192-
193-
for (len = 0; dst[len]; len++)
194-
;
195-
196-
for (;;) {
197-
c = *src;
198-
if (len < size)
199-
dst[len] = c;
200-
if (!c)
190+
size_t len = strnlen(dst, size);
191+
192+
/*
193+
* We want len < size-1. But as size is unsigned and can wrap
194+
* around, we use len + 1 instead.
195+
*/
196+
while (len + 1 < size) {
197+
dst[len] = *src;
198+
if (*src == '\0')
201199
break;
202200
len++;
203201
src++;
204202
}
205203

204+
if (len < size)
205+
dst[len] = '\0';
206+
207+
while (*src++)
208+
len++;
209+
206210
return len;
207211
}
208212

209213
static __attribute__((unused))
210214
size_t strlcpy(char *dst, const char *src, size_t size)
211215
{
212216
size_t len;
213-
char c;
214217

215-
for (len = 0;;) {
216-
c = src[len];
217-
if (len < size)
218-
dst[len] = c;
219-
if (!c)
220-
break;
221-
len++;
218+
for (len = 0; len < size; len++) {
219+
dst[len] = src[len];
220+
if (!dst[len])
221+
return len;
222222
}
223+
if (size)
224+
dst[size-1] = '\0';
225+
226+
while (src[len])
227+
len++;
228+
223229
return len;
224230
}
225231

tools/include/nolibc/sys.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include <linux/stat.h> /* for statx() */
2323
#include <linux/prctl.h>
2424
#include <linux/resource.h>
25+
#include <linux/utsname.h>
2526

2627
#include "arch.h"
2728
#include "errno.h"
@@ -1139,6 +1140,32 @@ int umount2(const char *path, int flags)
11391140
}
11401141

11411142

1143+
/*
1144+
* int uname(struct utsname *buf);
1145+
*/
1146+
1147+
struct utsname {
1148+
char sysname[65];
1149+
char nodename[65];
1150+
char release[65];
1151+
char version[65];
1152+
char machine[65];
1153+
char domainname[65];
1154+
};
1155+
1156+
static __attribute__((unused))
1157+
int sys_uname(struct utsname *buf)
1158+
{
1159+
return my_syscall1(__NR_uname, buf);
1160+
}
1161+
1162+
static __attribute__((unused))
1163+
int uname(struct utsname *buf)
1164+
{
1165+
return __sysret(sys_uname(buf));
1166+
}
1167+
1168+
11421169
/*
11431170
* int unlink(const char *path);
11441171
*/

tools/testing/selftests/nolibc/nolibc-test.c

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include <sys/syscall.h>
2828
#include <sys/sysmacros.h>
2929
#include <sys/time.h>
30+
#include <sys/utsname.h>
3031
#include <sys/wait.h>
3132
#include <dirent.h>
3233
#include <errno.h>
@@ -600,6 +601,25 @@ int expect_strne(const char *expr, int llen, const char *cmp)
600601
return ret;
601602
}
602603

604+
#define EXPECT_STRBUFEQ(cond, expr, buf, val, cmp) \
605+
do { if (!(cond)) result(llen, SKIPPED); else ret += expect_str_buf_eq(expr, buf, val, llen, cmp); } while (0)
606+
607+
static __attribute__((unused))
608+
int expect_str_buf_eq(size_t expr, const char *buf, size_t val, int llen, const char *cmp)
609+
{
610+
llen += printf(" = %lu <%s> ", expr, buf);
611+
if (strcmp(buf, cmp) != 0) {
612+
result(llen, FAIL);
613+
return 1;
614+
}
615+
if (expr != val) {
616+
result(llen, FAIL);
617+
return 1;
618+
}
619+
620+
result(llen, OK);
621+
return 0;
622+
}
603623

604624
/* declare tests based on line numbers. There must be exactly one test per line. */
605625
#define CASE_TEST(name) \
@@ -761,6 +781,45 @@ int test_stat_timestamps(void)
761781
return 0;
762782
}
763783

784+
int test_uname(void)
785+
{
786+
struct utsname buf;
787+
char osrelease[sizeof(buf.release)];
788+
ssize_t r;
789+
int fd;
790+
791+
memset(&buf.domainname, 'P', sizeof(buf.domainname));
792+
793+
if (uname(&buf))
794+
return 1;
795+
796+
if (strncmp("Linux", buf.sysname, sizeof(buf.sysname)))
797+
return 1;
798+
799+
fd = open("/proc/sys/kernel/osrelease", O_RDONLY);
800+
if (fd == -1)
801+
return 1;
802+
803+
r = read(fd, osrelease, sizeof(osrelease));
804+
if (r == -1)
805+
return 1;
806+
807+
close(fd);
808+
809+
if (osrelease[r - 1] == '\n')
810+
r--;
811+
812+
/* Validate one of the later fields to ensure field sizes are correct */
813+
if (strncmp(osrelease, buf.release, r))
814+
return 1;
815+
816+
/* Ensure the field domainname is set, it is missing from struct old_utsname */
817+
if (strnlen(buf.domainname, sizeof(buf.domainname)) == sizeof(buf.domainname))
818+
return 1;
819+
820+
return 0;
821+
}
822+
764823
int test_mmap_munmap(void)
765824
{
766825
int ret, fd, i, page_size;
@@ -966,6 +1025,8 @@ int run_syscall(int min, int max)
9661025
CASE_TEST(stat_fault); EXPECT_SYSER(1, stat(NULL, &stat_buf), -1, EFAULT); break;
9671026
CASE_TEST(stat_timestamps); EXPECT_SYSZR(1, test_stat_timestamps()); break;
9681027
CASE_TEST(symlink_root); EXPECT_SYSER(1, symlink("/", "/"), -1, EEXIST); break;
1028+
CASE_TEST(uname); EXPECT_SYSZR(proc, test_uname()); break;
1029+
CASE_TEST(uname_fault); EXPECT_SYSER(1, uname(NULL), -1, EFAULT); break;
9691030
CASE_TEST(unlink_root); EXPECT_SYSER(1, unlink("/"), -1, EISDIR); break;
9701031
CASE_TEST(unlink_blah); EXPECT_SYSER(1, unlink("/proc/self/blah"), -1, ENOENT); break;
9711032
CASE_TEST(wait_child); EXPECT_SYSER(1, wait(&tmp), -1, ECHILD); break;
@@ -991,6 +1052,14 @@ int run_stdlib(int min, int max)
9911052
for (test = min; test >= 0 && test <= max; test++) {
9921053
int llen = 0; /* line length */
9931054

1055+
/* For functions that take a long buffer, like strlcat()
1056+
* Add some more chars after the \0, to test functions that overwrite the buffer set
1057+
* the \0 at the exact right position.
1058+
*/
1059+
char buf[10] = "test123456";
1060+
buf[4] = '\0';
1061+
1062+
9941063
/* avoid leaving empty lines below, this will insert holes into
9951064
* test numbers.
9961065
*/
@@ -1007,6 +1076,19 @@ int run_stdlib(int min, int max)
10071076
CASE_TEST(strchr_foobar_z); EXPECT_STRZR(1, strchr("foobar", 'z')); break;
10081077
CASE_TEST(strrchr_foobar_o); EXPECT_STREQ(1, strrchr("foobar", 'o'), "obar"); break;
10091078
CASE_TEST(strrchr_foobar_z); EXPECT_STRZR(1, strrchr("foobar", 'z')); break;
1079+
#ifdef NOLIBC
1080+
CASE_TEST(strlcat_0); EXPECT_STRBUFEQ(1, strlcat(buf, "bar", 0), buf, 3, "test"); break;
1081+
CASE_TEST(strlcat_1); EXPECT_STRBUFEQ(1, strlcat(buf, "bar", 1), buf, 4, "test"); break;
1082+
CASE_TEST(strlcat_5); EXPECT_STRBUFEQ(1, strlcat(buf, "bar", 5), buf, 7, "test"); break;
1083+
CASE_TEST(strlcat_6); EXPECT_STRBUFEQ(1, strlcat(buf, "bar", 6), buf, 7, "testb"); break;
1084+
CASE_TEST(strlcat_7); EXPECT_STRBUFEQ(1, strlcat(buf, "bar", 7), buf, 7, "testba"); break;
1085+
CASE_TEST(strlcat_8); EXPECT_STRBUFEQ(1, strlcat(buf, "bar", 8), buf, 7, "testbar"); break;
1086+
CASE_TEST(strlcpy_0); EXPECT_STRBUFEQ(1, strlcpy(buf, "bar", 0), buf, 3, "test"); break;
1087+
CASE_TEST(strlcpy_1); EXPECT_STRBUFEQ(1, strlcpy(buf, "bar", 1), buf, 3, ""); break;
1088+
CASE_TEST(strlcpy_2); EXPECT_STRBUFEQ(1, strlcpy(buf, "bar", 2), buf, 3, "b"); break;
1089+
CASE_TEST(strlcpy_3); EXPECT_STRBUFEQ(1, strlcpy(buf, "bar", 3), buf, 3, "ba"); break;
1090+
CASE_TEST(strlcpy_4); EXPECT_STRBUFEQ(1, strlcpy(buf, "bar", 4), buf, 3, "bar"); break;
1091+
#endif
10101092
CASE_TEST(memcmp_20_20); EXPECT_EQ(1, memcmp("aaa\x20", "aaa\x20", 4), 0); break;
10111093
CASE_TEST(memcmp_20_60); EXPECT_LT(1, memcmp("aaa\x20", "aaa\x60", 4), 0); break;
10121094
CASE_TEST(memcmp_60_20); EXPECT_GT(1, memcmp("aaa\x60", "aaa\x20", 4), 0); break;

0 commit comments

Comments
 (0)