/*
* Copyright (c) 2023 Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "libc.h"
#include "morello.h"
static int test_strings(char *argv[], char *envp[]);
static int test_sprintf(char *argv[], char *envp[]);
static int test_morello(char *argv[], char *envp[]);
static int test_memcopy(char *argv[], char *envp[]);
int main(int argc, char *argv[], char *envp[])
{
int r = 0;
r += test_strings(argv, envp);
r += test_sprintf(argv, envp);
r += test_morello(argv, envp);
r += test_memcopy(argv, envp);
if (r) {
return printf("%d test(s) failed\n", r);
} else {
return 0;
}
}
#define TEST(code, test, fail) ({ \
count++; \
code; \
if ((test)) { \
printf("Test %s %2d passed: %s\n", name, count, #test); \
} else { \
r += 1; \
printf("Test %s %2d FAILED: %s\n", name, count, #test); \
fail; \
} \
})
#define STEST(exp, fmt, ...) \
TEST(int n = sprintf(str, fmt, __VA_ARGS__), \
strcmp(str, exp) == 0 && n == (sizeof((exp)) - 1), \
printf(" - output: `%s`\n", str))
static int test_strings(char *argv[], char *envp[])
{
int r = 0;
size_t count = 0;
const char name[] = "strings";
TEST({}, strcmp("abc", "ABC") > 0, {});
TEST({}, strcmp("ABC", "abc") < 0, {});
TEST({}, strcmp("123", "123") == 0, {});
TEST(const char *str = "01234567",
strcmp(str, cheri_bounds_set_exact(str, 4)) > 0, {});
TEST(const char *str = "01234567",
strcmp(cheri_bounds_set_exact(str, 5), str) < 0, {});
TEST({}, strcmp(NULL, NULL) == 0, {});
TEST(const char str[] = "",
strlen(str) == 0, {});
TEST(const char str[] = "01234",
strlen(str) == 5, {});
TEST(const char str[] = "0123456789",
strlen(cheri_bounds_set_exact(str, 3)) == 3, {});
TEST(const char str[] = "0123456789",
strlen(cheri_tag_clear(str)) == 0, {});
TEST(const char src[] = "0123456789"; char dst[64];
strcpy(dst, src),
strcmp(src, dst) == 0, {});
TEST(const char src[] = "0123456789"; char dst[64];
strcpy(dst, cheri_bounds_set_exact(src, 7)),
strcmp("0123456", dst) == 0, {});
TEST(const char src[] = "0123456789"; char dst[7];
strcpy(dst, src),
strcmp("0123456", dst) == 0, {});
TEST(char buf[8]; memset(buf, 'u', sizeof(buf)),
strcmp(buf, "uuuuuuuu") == 0, {});
TEST(char buf[8]; memset(buf, 'u', sizeof(buf)+10),
strcmp(buf, "uuuuuuuu") == 0, {});
TEST(char buf[8]; memset(buf, 'g', 4); memset(buf + 4, 0, 4),
strcmp(buf, "gggg") == 0, {});
return r;
}
static int test_sprintf(char *argv[], char *envp[])
{
int r = 0;
size_t count = 0;
const char name[] = "sprintf";
char str[256];
int m;
STEST("hello", "hello", 0);
STEST("hello", "%s", "hello");
STEST("(null)", "%s", NULL);
STEST("hello (null)", "%s %s", "hello", NULL);
STEST("hello 42 morello", "%s %d %s", "hello", 42, "morello");
STEST("CHERI % abc", "%c%c%c%c%c %% %s", 'C', 'H', 'E', 'R', 'I', "abc");
STEST("13", "%i", 13);
STEST("-987", "%d", -987);
STEST("+987", "%+d", 987);
STEST(" 987", "% d", 987);
STEST("1024", "%u", 1024);
STEST("c0ffee", "%x", 0xc0ffee);
STEST("223338299392", "%li", 13l << 34);
STEST("8681743812919296", "%ld", 987l << 43);
STEST("140737488355328", "%lu", 1024ul << 37);
STEST("303ffb800000000", "%lx", 0xc0ffeeul << 34);
STEST("0xc0ffee", "%#x", 0xc0ffee);
STEST("0001234", "%07x", 0x1234);
STEST("fffffffd", "%x", -3);
STEST("fffffffffffffffe", "%lx", -2l);
STEST("4294967293", "%u", -3);
STEST("18446744073709551614", "%lu", -2l);
STEST("0", "%p", NULL);
STEST("0:0000000000000000:0000000000000000", "%#p", NULL);
TEST(void *cap = NULL; const char exp[] = "0000000000000000 0 [0000000000000000:0000000000000000) ------------------ none 0 of 0";
m = sprintf(str, "%+#p", cap), strcmp(str, exp) == 0 && m == (sizeof(exp) - 1), {});
STEST(" hello", "%10s", "hello");
STEST("hello ", "%-10s", "hello");
STEST("hello", "%s%n", "hello", &m);
TEST(int q = 0; sprintf(str, "%-10d%n", 1, &q), q == 10, {});
STEST("mismatch 5 %s %c %u", "mismatch %d %s %c %u", 5);
STEST("mismatch 5", "mismatch %d", 5, "str", false, 2.71f);
STEST("unsupported 7 (invalid)", "unsupported %d %s", 7, (char *)42ul);
STEST("unsupported 7 %a (invalid)", "unsupported %d %a %s", 7, 99, (char *)42ul);
STEST("unsupported -1 %10.4f %-.5e (invalid)", "unsupported %d %10.4f %-.5e %s", -1, 1.2f, 3.14f, "string");
return r;
}
#undef STEST
static int test_morello(char *argv[], char *envp[])
{
int r = 0;
size_t count = 0;
const char name[] = "morello";
TEST({}, cheri_is_local(argv) == false, {});
TEST({}, cheri_is_deref(envp), {});
TEST({}, cheri_in_bounds(argv), {});
TEST({}, cheri_length_get_zero(NULL) == 0, {});
TEST({}, cheri_get_tail(NULL) == 0, {});
TEST({}, cheri_length_get_zero(argv) == cheri_get_tail(argv), {});
TEST({}, cheri_length_get_zero(argv) == cheri_length_get(argv), {});
TEST(char buf[64], strcmp(cap_perms_to_str(buf, argv), "GrRMwWL-----------") == 0, {});
TEST(void *pcc = cheri_pcc_get(); char buf[64],
strcmp(cap_perms_to_str(buf, pcc), "GrRM---xES--------") == 0, {});
TEST(void *sentry = main; char buf[64], strcmp(cap_seal_to_str(buf, sentry), "rb") == 0, {});
TEST(char buf[64], strcmp(cap_seal_to_str(buf, envp), "none") == 0, {});
TEST({}, cheri_get_limit(NULL) == NULL, {});
return r;
}
static int test_memcopy(char *argv[], char *envp[])
{
int r = 0;
size_t count = 0;
const char name[] = "memcopy";
char dst[64], src[64];
strcpy(src, "this is morello test 0123456789 for mem copy function 01 234567");
memset(dst, 0, sizeof(dst));
TEST(memcpy(dst, src, sizeof(dst)), strcmp(dst, src) == 0 && strlen(dst) == strlen(src), {
printf("output: `%s`\n", dst);
});
memset(dst, 0, sizeof(dst));
TEST(memcpy(dst, src, 15), strcmp(dst, "this is morello") == 0 && strlen(dst) == 15, {
printf("output: `%s`\n", dst);
});
memset(dst, 0, sizeof(dst));
TEST(memcpy(dst + 5, src, 15), strcmp(dst + 5, "this is morello") == 0 && strlen(dst + 5) == 15, {
printf("output: `%s`\n", dst);
});
memset(dst, 0, sizeof(dst));
TEST(memcpy(dst + 5, src + 5, 10), strcmp(dst + 5, "is morello") == 0 && strlen(dst + 5) == 10, {
printf("output: `%s`\n", dst);
});
double x = 3.14;
typedef struct { int x; bool y; char *p1; double *p2; long z; } object_t;
object_t s = { .x = 1, .y = true, .p1 = argv[0], .p2 = &x, .z = -1l };
object_t d = { .x = 2, .y = false, .p1 = NULL, .p2 = NULL, .z = -1l };
TEST(memcpy(&d, &s, sizeof(object_t)),
d.x == 1 && d.y && d.p1 == s.p1 && *d.p2 == x && d.z == -1l, {});
return r;
}
__attribute__((used))
void _start(int argc, char *argv[], char *envp[], auxv_t *auxv)
{
init(auxv, false);
exit(main(argc, argv, envp));
}