user: implement mlibc as the libc, finally.

It's finally done..

Signed-off-by: kaguya <vpshinomiya@protonmail.com>
This commit is contained in:
kaguya
2026-05-02 03:31:49 -04:00
parent 2fa39ad85a
commit 9a9b91c940
2387 changed files with 152741 additions and 315 deletions
+16
View File
@@ -0,0 +1,16 @@
#include <stdlib.h>
#include <assert.h>
#include <limits.h>
int main(){
assert(abs(-10) == 10);
assert(abs(2021) == 2021);
assert(labs(-256) == 256);
assert(labs(10034890) == 10034890);
assert(llabs(-0x2deadbeef) == 0x2deadbeef);
assert(llabs(49238706947) == 49238706947);
return 0;
}
+39
View File
@@ -0,0 +1,39 @@
#include <stdlib.h>
#include <assert.h>
#include <stdint.h>
#include <errno.h>
int main() {
void *p;
p = aligned_alloc(sizeof(void *), sizeof(void *));
assert(p != NULL && (uintptr_t)p % sizeof(void *) == 0);
free(p);
p = aligned_alloc(256, 256);
assert(p != NULL && (uintptr_t)p % 256 == 0);
free(p);
// small alignments are okay
p = aligned_alloc(1, 8);
assert(p != NULL);
free(p);
p = aligned_alloc(1, 1);
assert(p != NULL);
free(p);
// It seems that glibc doesn't report error in these cases.
#if !(defined(USE_HOST_LIBC) && defined(__GLIBC__))
// size % align must be 0
p = aligned_alloc(256, 1);
assert(errno == EINVAL);
assert(p == NULL);
// align must be a 'valid alignment supported by the implementation'
p = aligned_alloc(3, 1);
assert(errno == EINVAL);
assert(p == NULL);
#endif
return 0;
}
+22
View File
@@ -0,0 +1,22 @@
#include <assert.h>
#include <errno.h>
#include <limits.h>
#include <stdint.h>
#include <stdlib.h>
int main() {
errno = 0;
void *ptr = calloc((SIZE_MAX / 2) + 2, 2);
assert(!ptr);
assert(errno);
errno = 0;
ptr = calloc(10, sizeof(size_t));
assert(ptr);
for(size_t i = 0; i < 10; i++) {
size_t *p = ptr;
assert(!p[i]);
}
return 0;
}
@@ -0,0 +1,39 @@
#include <assert.h>
#include <math.h>
#include <complex.h>
// FIXME: We should create a proper floating point facility
// in order for other functions to be tested properly
#define APPROXIMATELY_EQUAL(calculated, expected) fabs((calculated) - (expected)) <= 0.0000005
#define APPROXIMATELY_EQUALF(calculated, expected) fabsf((calculated) - (expected)) <= 0.0000005f
#define APPROXIMATELY_EQUALL(calculated, expected) fabsl((calculated) - (expected)) <= 0.0000005L
#define IS_COMPLEX_NUMBER(Z) \
_Generic((Z), \
double complex: 1, \
float complex: 1, \
long double complex: 1, \
default: 0 \
)
int main() {
#if !(defined(USE_HOST_LIBC) && defined(__clang__))
assert(IS_COMPLEX_NUMBER(CMPLX(5.2, 4.3)));
double complex cz = CMPLX(5.2, 4.3);
assert(APPROXIMATELY_EQUAL(creal(cz), 5.2));
assert(APPROXIMATELY_EQUAL(cimag(cz), 4.3));
assert(IS_COMPLEX_NUMBER(CMPLXF(1.2f, 2.5f)));
float complex czf = CMPLXF(1.2f, 2.5f);
assert(APPROXIMATELY_EQUALF(crealf(czf), 1.2f));
assert(APPROXIMATELY_EQUALF(cimagf(czf), 2.5f));
assert(IS_COMPLEX_NUMBER(CMPLXL(0.1L, 123.54L)));
long double complex czl = CMPLXL(0.1L, 123.54L);
assert(APPROXIMATELY_EQUALL(creall(czl), 0.1L));
assert(APPROXIMATELY_EQUALL(cimagl(czl), 123.54L));
#endif
return 0;
}
+100
View File
@@ -0,0 +1,100 @@
#include <assert.h>
#include <stdbool.h>
#include <fenv.h>
#include <float.h>
#include <math.h>
/* qemu-m68k < version 9.1.0 cannot run the test due to missing FPU logic. */
#ifdef __m68k__
int main() {
return 0;
}
#else
#define NO_OPTIMIZE(x) asm volatile("" :: "r,m" (x) : "memory")
static void div_by_zero() {
volatile float zero = 0.0f;
NO_OPTIMIZE(69.0f / zero);
}
static bool float_cmp(float a, float b) {
return a == b || fabs(a - b) < (fabs(a) + fabs(b)) * FLT_EPSILON;
}
static void test_rounding(float expectation1, float expectation2) {
float x;
volatile float f = 1.968750f;
volatile float m = 0x1.0p23f;
NO_OPTIMIZE(x = f + m);
assert(float_cmp(expectation1, x));
NO_OPTIMIZE(x = x - m);
assert(x == expectation2);
}
void test0() {
// test whether the divide-by-zero exception is raised
feclearexcept(FE_ALL_EXCEPT);
assert(fetestexcept(FE_ALL_EXCEPT) == 0);
div_by_zero();
int raised = fetestexcept(FE_DIVBYZERO);
assert((raised & FE_DIVBYZERO));
}
void test1() {
// test various rounding modes
feclearexcept(FE_DIVBYZERO);
assert(fetestexcept(FE_ALL_EXCEPT) == 0);
fesetround(FE_UPWARD);
assert(fegetround() == FE_UPWARD);
test_rounding(8388610.0f, 2.0f);
fesetround(FE_DOWNWARD);
assert(fegetround() == FE_DOWNWARD);
test_rounding(8388609.0f, 1.0f);
fesetround(FE_TONEAREST);
assert(fegetround() == FE_TONEAREST);
test_rounding(8388610.0f, 2.0f);
fesetround(FE_TOWARDZERO);
assert(fegetround() == FE_TOWARDZERO);
test_rounding(8388609.0f, 1.0f);
}
void test2() {
// test feraiseexcept
feclearexcept(FE_ALL_EXCEPT);
assert(fetestexcept(FE_ALL_EXCEPT) == 0);
assert(feraiseexcept(FE_DIVBYZERO | FE_OVERFLOW) == 0);
assert(fetestexcept(FE_ALL_EXCEPT) == (FE_DIVBYZERO | FE_OVERFLOW));
}
void test3() {
// test fe{get,set}env
feclearexcept(FE_ALL_EXCEPT);
assert(fetestexcept(FE_ALL_EXCEPT) == 0);
assert(feraiseexcept(FE_OVERFLOW) == 0);
fenv_t state;
assert(fegetenv(&state) == 0);
assert(fetestexcept(FE_ALL_EXCEPT) == FE_OVERFLOW);
div_by_zero();
assert(fetestexcept(FE_ALL_EXCEPT) == (FE_DIVBYZERO | FE_OVERFLOW));
assert(fesetenv(&state) == 0);
assert(fetestexcept(FE_ALL_EXCEPT) == FE_OVERFLOW);
}
int main() {
test0();
test1();
test2();
test3();
return 0;
}
#endif
+35
View File
@@ -0,0 +1,35 @@
#include <assert.h>
#include <stdio.h>
int main(int argc, char *argv[]) {
(void) argc;
FILE *f = fopen(argv[0], "r");
assert(f);
int ret = fseek(f, 0, SEEK_SET);
assert(!ret);
fpos_t start_pos;
ret = fgetpos(f, &start_pos);
assert(!ret);
ret = fseek(f, 0, SEEK_END);
assert(!ret);
long end_off = ftell(f);
fpos_t end_pos;
ret = fgetpos(f, &end_pos);
assert(!ret);
ret = fsetpos(f, &start_pos);
assert(!ret);
assert(ftell(f) == 0);
ret = fsetpos(f, &end_pos);
assert(!ret);
assert(ftell(f) == end_off);
return 0;
}
+59
View File
@@ -0,0 +1,59 @@
#include <stdio.h>
#include <assert.h>
#include <string.h>
#ifdef USE_HOST_LIBC
#define TEST_FILE "fopen-host-libc.tmp"
#else
#define TEST_FILE "fopen.tmp"
#endif
int main() {
FILE *file;
char str[] = "mlibc fopen test";
char str2[] = " mlibc appending";
char completestr[] = "mlibc fopen test mlibc appending";
char buffer[100];
char buffer2[100];
// Clear all the buffers to zero.
memset(buffer, 0, sizeof(buffer));
memset(buffer2, 0, sizeof(buffer2));
// Open the file for writing.
file = fopen(TEST_FILE, "w");
assert(file);
// Write string minus null terminator, flush and close.
fwrite(str, 1, sizeof(str) - 1, file);
fflush(file);
fclose(file);
// Open the file for reading.
file = fopen(TEST_FILE, "r");
assert(file);
// Verify that we read back the written string and close the file.
assert(fread(buffer, 1, sizeof(str) - 1, file));
assert(!strcmp(buffer, str));
fclose(file);
// Open the file in appending mode, append string 2 (minus the null terminator) to the file, flush and close.
file = fopen(TEST_FILE, "a");
fwrite(str2, 1, sizeof(str2) - 1, file);
fflush(file);
fclose(file);
// Open the file for reading again, verify the contents, close the file and return.
file = fopen(TEST_FILE, "r");
assert(fread(buffer2, 1, sizeof(completestr) - 1, file));
assert(!strcmp(buffer2, completestr));
fclose(file);
// Check that stdout, stdin and stderr can be closed by the application (issue #12).
fclose(stdout);
fclose(stdin);
fclose(stderr);
return 0;
}
+41
View File
@@ -0,0 +1,41 @@
#include <assert.h>
#include <stdio.h>
#include <string.h>
#ifdef USE_HOST_LIBC
#define TEST_FILE "fputs-host-libc.tmp"
#else
#define TEST_FILE "fputs.tmp"
#endif
int main() {
FILE *file;
char str[] = "mlibc fputs test";
char buffer[100];
// Clear the buffer to zero.
memset(buffer, 0, sizeof(buffer));
// Open the file for writing.
file = fopen(TEST_FILE, "w");
assert(file);
// Verify that we can write an empty string.
assert(fputs("", file) != EOF);
// Write string, flush and close.
assert(fputs(str, file) != EOF);
fflush(file);
fclose(file);
// Open the file for reading.
file = fopen(TEST_FILE, "r");
assert(file);
// Verify that we read back the written string and close.
assert(fread(buffer, 1, sizeof(str) - 1, file));
assert(!strcmp(buffer, str));
fclose(file);
return 0;
}
+49
View File
@@ -0,0 +1,49 @@
#include <assert.h>
#include <stdio.h>
#include <string.h>
#ifdef USE_HOST_LIBC
#define TEST_FILE "freopen-host-libc.tmp"
#else
#define TEST_FILE "freopen.tmp"
#endif
int main() {
FILE *file = fopen(TEST_FILE, "w");
assert(file);
assert(freopen("/dev/null", "w", file));
char str[] = "mlibc freopen test";
fwrite(str, 1, sizeof(str) - 1, file);
fflush(file);
fclose(file);
file = fopen(TEST_FILE, "r");
assert(file);
char buf[sizeof(str)];
memset(buf, 0, sizeof(buf));
int ret = fread(buf, 1, sizeof(buf) - 1, file);
fprintf(stderr, "ret %d\n", ret);
assert(ret == 0);
fclose(file);
file = fopen("/dev/null", "w");
assert(file);
assert(freopen(TEST_FILE, "w", file));
fwrite(str, 1, sizeof(str) - 1, file);
fflush(file);
fclose(file);
memset(buf, 0, sizeof(buf));
file = fopen(TEST_FILE, "r");
assert(fread(buf, 1, sizeof(buf) - 1, file));
fprintf(stderr, "buffer content '%s'\n", buf);
assert(!strcmp(buf, "mlibc freopen test"));
fclose(file);
return 0;
}
+72
View File
@@ -0,0 +1,72 @@
#include <assert.h>
#include <stdio.h>
#include <string.h>
#ifdef USE_HOST_LIBC
#define TEST_FILE "ftell-host-libc.tmp"
#else
#define TEST_FILE "ftell.tmp"
#endif
int main() {
FILE *file;
char str[] = "mlibc ftell test";
size_t str_size = sizeof(str) - 1;
char buffer[20];
// Clear buffer to zero
memset(buffer, 0, sizeof(buffer));
// Open the file for writing in binary mode, because ftell is unspecified
// in text mode.
file = fopen(TEST_FILE, "wb");
assert(file);
// Write string minus null terminator, flush and close.
assert(fwrite(str, 1, str_size, file) == str_size);
fflush(file);
fclose(file);
// Open the file for reading in binary mode.
file = fopen(TEST_FILE, "rb");
assert(file);
// Check position indicator at the start of the file.
assert(ftell(file) == 0);
// Read 4 bytes and check fread and ftell.
assert(fread(buffer, 1, 4, file) == 4);
assert(ftell(file) == 4);
// Rewind and check position indicator at the start of the file.
rewind(file);
assert(ftell(file) == 0);
// Read the entire file and check fread and ftell.
assert(fread(buffer, 1, str_size, file) == str_size);
assert((size_t) ftell(file) == str_size);
// Rewind and check how ftell interacts with getc.
rewind(file);
assert(fgetc(file) == 'm');
assert(ftell(file) == 1);
assert(fgetc(file) == 'l');
assert(ftell(file) == 2);
assert(fgetc(file) == 'i');
assert(ftell(file) == 3);
// Check whether ftell is decremented after ungetc
assert(ungetc('X', file) == 'X');
int ftell_after_ungetc = ftell(file);
fprintf(stderr, "ftell_after_ungetc: %d\n", ftell_after_ungetc);
assert(ftell_after_ungetc == 2);
ungetc('Y', file);
assert(ftell(file) == 1);
// Check if rewind undoes ungetc's effects on ftell
rewind(file);
assert(ftell(file) == 0);
fclose(file);
return 0;
}
+18
View File
@@ -0,0 +1,18 @@
#include <stdio.h>
#include <wchar.h>
#include <limits.h>
#include <locale.h>
#include <assert.h>
int main() {
wchar_t c = 0xC9;
unsigned char buf[MB_LEN_MAX] = { 0 };
setlocale(LC_ALL, "");
if (sprintf(buf, "%lc", c) < 0)
return -1;
assert(buf[0] == 0xc3 && buf[1] == 0x89
&& buf[2] == '\0' && buf[3] == '\0');
return 0;
}
+31
View File
@@ -0,0 +1,31 @@
#include <stdio.h>
#include <setjmp.h>
#include <stdnoreturn.h>
#include <assert.h>
jmp_buf buf;
noreturn void do_jump(int arg) {
longjmp(buf, 2 * arg);
}
int main(void) {
volatile int times_called = 0;
if (setjmp(buf) != 8) {
do_jump(++times_called);
}
assert(times_called == 4);
times_called = 0;
int ret = setjmp(buf);
assert(ret == times_called);
if (!ret) {
times_called = 1;
longjmp(buf, 0);
}
return 0;
}
+55
View File
@@ -0,0 +1,55 @@
#include <assert.h>
#include <locale.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <uchar.h>
struct {
size_t ret;
char32_t c32;
uint8_t bytes[4];
} expected_results[] = {
{1, 0x7A, {0x7A, 0, 0, 0}},
{2, 0xDF, {0xC3, 0x9F, 0, 0}},
{3, 0x6C34, {0xE6, 0xB0, 0xB4, 0}},
{4, 0x1F34C, {0xF0, 0x9F, 0x8D, 0x8C}},
};
int main() {
setlocale(LC_ALL, "en_US.utf8");
size_t ret = 0;
char *str = "z\u00df\u6c34\U0001F34C";
fprintf(stderr, "string: '%s'\n", str);
mbstate_t state = {};
char32_t c32;
size_t loop = 0;
while((ret = mbrtoc32(&c32, str, strlen(str), &state))) {
assert(ret != (size_t)-3);
if(ret == (size_t)-1)
break;
if(ret == (size_t)-2)
break;
fprintf(stderr, "Next UTF-32 char: 0x%x obtained from %zu bytes [", c32, ret);
for(size_t n = 0; n < ret; ++n) {
fprintf(stderr, " 0x%02x ", (uint8_t) str[n]);
}
fprintf(stderr, "]\n");
assert(ret == expected_results[loop].ret);
assert(c32 == expected_results[loop].c32);
for(size_t n = 0; n < ret; ++n) {
assert((uint8_t) str[n] == expected_results[loop].bytes[n]);
}
str += ret;
loop++;
}
return 0;
}
+24
View File
@@ -0,0 +1,24 @@
#include <string.h>
#include <assert.h>
int main() {
char *haystack = "abc123\0x45";
char *needle1 = "abc";
void *rv = memmem(haystack, strlen(haystack), needle1, strlen(needle1));
assert(rv == haystack);
char *needle2 = "123";
rv = memmem(haystack, strlen(haystack), needle2, strlen(needle2));
assert(rv == haystack + 3);
char *needle3 = "1234";
rv = memmem(haystack, strlen(haystack), needle3, strlen(needle3));
assert(rv == NULL);
char *needle4 = "23\0x45";
rv = memmem(haystack, 10, needle4, 6);
assert(rv == haystack + 4);
return 0;
}
+31
View File
@@ -0,0 +1,31 @@
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
static const char *arr[] = { "xyz", "abc", "ghi", "def" };
static const size_t magic = 0xDEADBEEF;
static int cmpstringp(const void *p1, const void *p2, void *ctx) {
/* The actual arguments to this function are "pointers to
* pointers to char", but strcmp(3) arguments are "pointers
* to char", hence the following cast plus dereference. */
assert(*(size_t *) ctx == magic);
return strcmp(*(const char **) p1, *(const char **) p2);
}
int main() {
qsort_r(&arr[0], sizeof(arr) / sizeof(*arr), sizeof(char *), cmpstringp, (void *) &magic);
assert(!strcmp(arr[0], "abc"));
assert(!strcmp(arr[1], "def"));
assert(!strcmp(arr[2], "ghi"));
assert(!strcmp(arr[3], "xyz"));
for(size_t i = 0; i < sizeof(arr) / sizeof(*arr); i++) {
fprintf(stderr, "%s\n", arr[i]);
}
return 0;
}
+424
View File
@@ -0,0 +1,424 @@
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <math.h>
#include <wctype.h>
int main() {
char buffer[10];
int ret = snprintf(buffer, 10, "%d", 123456789);
assert(strncmp("123456789", buffer, 10) == 0);
assert(ret == 9);
// We deliberately induce a warning here.
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat-truncation"
ret = snprintf(buffer, 10, "%d", 1234567890);
assert(strncmp("123456789", buffer, 10) == 0);
assert(ret == 10);
#pragma GCC diagnostic pop
// mlibc issue #118.
ret = snprintf(NULL, 0, "%d", 123456789);
assert(ret == 9);
char buf[128];
assert(snprintf(buf, 2, "a") == 1);
assert(strcmp(buf, "a") == 0);
assert(snprintf(buf, 3, "abc") == 3);
assert(strcmp(buf, "ab") == 0);
assert(snprintf(buf, 128, "%%") == 1);
assert(strcmp(buf, "%") == 0);
assert(snprintf(buf, 128, "a%cc%c", 'b', 'd') == 4);
assert(strcmp(buf, "abcd") == 0);
assert(snprintf(buf, 128, "a%lcc%lc", (wint_t)L'b', (wint_t)L'd') == 4);
assert(strcmp(buf, "abcd") == 0);
assert(snprintf(buf, 128, "%s", "hello") == 5);
assert(strcmp(buf, "hello") == 0);
assert(snprintf(buf, 128, "%ls", L"hello") == 5);
assert(strcmp(buf, "hello") == 0);
assert(snprintf(buf, 128, "%d", 1234) == 4);
assert(strcmp(buf, "1234") == 0);
assert(snprintf(buf, 128, "%d", 0) == 1);
assert(strcmp(buf, "0") == 0);
assert(snprintf(buf, 128, "%d", -1234) == 5);
assert(strcmp(buf, "-1234") == 0);
assert(snprintf(buf, 128, "%hhd", 123) == 3);
assert(strcmp(buf, "123") == 0);
assert(snprintf(buf, 128, "%hd", 1234) == 4);
assert(strcmp(buf, "1234") == 0);
assert(snprintf(buf, 128, "%ld", 1234L) == 4);
assert(strcmp(buf, "1234") == 0);
assert(snprintf(buf, 128, "%lld", 1234LL) == 4);
assert(strcmp(buf, "1234") == 0);
assert(snprintf(buf, 128, "%jd", (intmax_t) 1234) == 4);
assert(strcmp(buf, "1234") == 0);
assert(snprintf(buf, 128, "%zd", (ssize_t) 1234) == 4);
assert(strcmp(buf, "1234") == 0);
assert(snprintf(buf, 128, "%td", (ptrdiff_t) 1234) == 4);
assert(strcmp(buf, "1234") == 0);
assert(snprintf(buf, 128, "%i", 1234) == 4);
assert(strcmp(buf, "1234") == 0);
assert(snprintf(buf, 128, "%i", 0) == 1);
assert(strcmp(buf, "0") == 0);
assert(snprintf(buf, 128, "%i", -1234) == 5);
assert(strcmp(buf, "-1234") == 0);
assert(snprintf(buf, 128, "%hhi", 123) == 3);
assert(strcmp(buf, "123") == 0);
assert(snprintf(buf, 128, "%hi", 1234) == 4);
assert(strcmp(buf, "1234") == 0);
assert(snprintf(buf, 128, "%li", 1234L) == 4);
assert(strcmp(buf, "1234") == 0);
assert(snprintf(buf, 128, "%lli", 1234LL) == 4);
assert(strcmp(buf, "1234") == 0);
assert(snprintf(buf, 128, "%ji", (intmax_t) 1234) == 4);
assert(strcmp(buf, "1234") == 0);
assert(snprintf(buf, 128, "%zi", (ssize_t) 1234) == 4);
assert(strcmp(buf, "1234") == 0);
assert(snprintf(buf, 128, "%ti", (ptrdiff_t) 1234) == 4);
assert(strcmp(buf, "1234") == 0);
assert(snprintf(buf, 128, "%b", 0b1011) == 4);
assert(strcmp(buf, "1011") == 0);
assert(snprintf(buf, 128, "%b", 0) == 1);
assert(strcmp(buf, "0") == 0);
assert(snprintf(buf, 128, "%hhb", 0b1011) == 4);
assert(strcmp(buf, "1011") == 0);
assert(snprintf(buf, 128, "%hb", 0b1011) == 4);
assert(strcmp(buf, "1011") == 0);
assert(snprintf(buf, 128, "%lb", 0b1011UL) == 4);
assert(strcmp(buf, "1011") == 0);
assert(snprintf(buf, 128, "%llb", 0b1011ULL) == 4);
assert(strcmp(buf, "1011") == 0);
assert(snprintf(buf, 128, "%jb", (uintmax_t) 0b1011) == 4);
assert(strcmp(buf, "1011") == 0);
assert(snprintf(buf, 128, "%zb", (size_t) 0b1011) == 4);
assert(strcmp(buf, "1011") == 0);
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat"
assert(snprintf(buf, 128, "%tb", 0b1011UL) == 4);
assert(strcmp(buf, "1011") == 0);
#pragma GCC diagnostic pop
assert(snprintf(buf, 128, "%o", 01234) == 4);
assert(strcmp(buf, "1234") == 0);
assert(snprintf(buf, 128, "%o", 0) == 1);
assert(strcmp(buf, "0") == 0);
assert(snprintf(buf, 128, "%o", -01234) == 11);
assert(strcmp(buf, "37777776544") == 0);
assert(snprintf(buf, 128, "%hho", 012) == 2);
assert(strcmp(buf, "12") == 0);
assert(snprintf(buf, 128, "%ho", 01234) == 4);
assert(strcmp(buf, "1234") == 0);
assert(snprintf(buf, 128, "%lo", 01234UL) == 4);
assert(strcmp(buf, "1234") == 0);
assert(snprintf(buf, 128, "%llo", 01234ULL) == 4);
assert(strcmp(buf, "1234") == 0);
assert(snprintf(buf, 128, "%jo", (uintmax_t) 01234) == 4);
assert(strcmp(buf, "1234") == 0);
assert(snprintf(buf, 128, "%zo", (size_t) 01234) == 4);
assert(strcmp(buf, "1234") == 0);
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat"
assert(snprintf(buf, 128, "%to", 01234UL) == 4);
assert(strcmp(buf, "1234") == 0);
#pragma GCC diagnostic pop
assert(snprintf(buf, 128, "%x", 0x1234AB) == 6);
assert(strcmp(buf, "1234ab") == 0);
assert(snprintf(buf, 128, "%x", 0) == 1);
assert(strcmp(buf, "0") == 0);
assert(snprintf(buf, 128, "%x", -0x1234AB) == 8);
assert(strcmp(buf, "ffedcb55") == 0);
assert(snprintf(buf, 128, "%X", 0x1234AB) == 6);
assert(strcmp(buf, "1234AB") == 0);
assert(snprintf(buf, 128, "%hhx", 0xAB) == 2);
assert(strcmp(buf, "ab") == 0);
assert(snprintf(buf, 128, "%hx", 0x12AB) == 4);
assert(strcmp(buf, "12ab") == 0);
assert(snprintf(buf, 128, "%lx", 0x1234ABUL) == 6);
assert(strcmp(buf, "1234ab") == 0);
assert(snprintf(buf, 128, "%llx", 0x1234ABULL) == 6);
assert(strcmp(buf, "1234ab") == 0);
assert(snprintf(buf, 128, "%jx", (uintmax_t) 0x1234AB) == 6);
assert(strcmp(buf, "1234ab") == 0);
assert(snprintf(buf, 128, "%zx", (size_t) 0x1234AB) == 6);
assert(strcmp(buf, "1234ab") == 0);
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat"
assert(snprintf(buf, 128, "%tx", 0x1234ABUL) == 6);
assert(strcmp(buf, "1234ab") == 0);
#pragma GCC diagnostic pop
assert(snprintf(buf, 128, "%u", 1234) == 4);
assert(strcmp(buf, "1234") == 0);
assert(snprintf(buf, 128, "%u", 0) == 1);
assert(strcmp(buf, "0") == 0);
assert(snprintf(buf, 128, "%u", -1234) == 10);
assert(strcmp(buf, "4294966062") == 0);
assert(snprintf(buf, 128, "%hhu", 123) == 3);
assert(strcmp(buf, "123") == 0);
assert(snprintf(buf, 128, "%hu", 1234) == 4);
assert(strcmp(buf, "1234") == 0);
assert(snprintf(buf, 128, "%lu", 1234UL) == 4);
assert(strcmp(buf, "1234") == 0);
assert(snprintf(buf, 128, "%llu", 1234ULL) == 4);
assert(strcmp(buf, "1234") == 0);
assert(snprintf(buf, 128, "%ju", (uintmax_t) 1234) == 4);
assert(strcmp(buf, "1234") == 0);
assert(snprintf(buf, 128, "%zu", (size_t) 1234) == 4);
assert(strcmp(buf, "1234") == 0);
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat"
assert(snprintf(buf, 128, "%tu", 1234UL) == 4);
assert(strcmp(buf, "1234") == 0);
#pragma GCC diagnostic pop
assert(snprintf(buf, 128, "%f", 1234.1234567) == 11);
assert(strcmp(buf, "1234.123457") == 0);
assert(snprintf(buf, 128, "%f", 0.0) == 8);
assert(strcmp(buf, "0.000000") == 0);
assert(snprintf(buf, 128, "%f", -1234.123456) == 12);
assert(strcmp(buf, "-1234.123456") == 0);
assert(snprintf(buf, 128, "%f", INFINITY) == 3);
assert(strcmp(buf, "inf") == 0);
assert(snprintf(buf, 128, "%04f", INFINITY) == 4);
assert(strcmp(buf, " inf") == 0);
assert(snprintf(buf, 128, "%-4f", INFINITY) == 4);
assert(strcmp(buf, "inf ") == 0);
assert(snprintf(buf, 128, "%f", NAN) == 3);
assert(strcmp(buf, "nan") == 0);
assert(snprintf(buf, 128, "%lf", 1234.123456) == 11);
assert(strcmp(buf, "1234.123456") == 0);
assert(snprintf(buf, 128, "%Lf", 1234.123456L) == 11);
assert(strcmp(buf, "1234.123456") == 0);
assert(snprintf(buf, 128, "%F", 1234.123456) == 11);
assert(strcmp(buf, "1234.123456") == 0);
assert(snprintf(buf, 128, "%F", INFINITY) == 3);
assert(strcmp(buf, "INF") == 0);
assert(snprintf(buf, 128, "%F", NAN) == 3);
assert(strcmp(buf, "NAN") == 0);
assert(snprintf(buf, 128, "%lF", 1234.123456) == 11);
assert(strcmp(buf, "1234.123456") == 0);
assert(snprintf(buf, 128, "%LF", 1234.123456L) == 11);
assert(strcmp(buf, "1234.123456") == 0);
assert(snprintf(buf, 128, "%e", 1.123456) == 12);
assert(strcmp(buf, "1.123456e+00") == 0);
assert(snprintf(buf, 128, "%e", 0.0) == 12);
assert(strcmp(buf, "0.000000e+00") == 0);
assert(snprintf(buf, 128, "%e", -1.123456) == 13);
assert(strcmp(buf, "-1.123456e+00") == 0);
assert(snprintf(buf, 128, "%e", 1.123456e12) == 12);
assert(strcmp(buf, "1.123456e+12") == 0);
assert(snprintf(buf, 128, "%e", -1.123456e12) == 13);
assert(strcmp(buf, "-1.123456e+12") == 0);
assert(snprintf(buf, 128, "%e", -1.123456e-12) == 13);
assert(strcmp(buf, "-1.123456e-12") == 0);
assert(snprintf(buf, 128, "%e", INFINITY) == 3);
assert(strcmp(buf, "inf") == 0);
assert(snprintf(buf, 128, "%e", NAN) == 3);
assert(strcmp(buf, "nan") == 0);
assert(snprintf(buf, 128, "%le", 1.123456e12) == 12);
assert(strcmp(buf, "1.123456e+12") == 0);
assert(snprintf(buf, 128, "%Le", 1.123456e12L) == 12);
assert(strcmp(buf, "1.123456e+12") == 0);
assert(snprintf(buf, 128, "%E", 1.123456e12) == 12);
assert(strcmp(buf, "1.123456E+12") == 0);
assert(snprintf(buf, 128, "%E", INFINITY) == 3);
assert(strcmp(buf, "INF") == 0);
assert(snprintf(buf, 128, "%E", NAN) == 3);
assert(strcmp(buf, "NAN") == 0);
assert(snprintf(buf, 128, "%lE", 1.123456e12) == 12);
assert(strcmp(buf, "1.123456E+12") == 0);
assert(snprintf(buf, 128, "%LE", 1.123456e12L) == 12);
assert(strcmp(buf, "1.123456E+12") == 0);
/*assert(snprintf(buf, 128, "%a", 0x1.123456p0) == 13);
assert(strcmp(buf, "0x1.123456p+0") == 0);
assert(snprintf(buf, 128, "%a", 0.0) == 6);
assert(strcmp(buf, "0x0p+0") == 0);
assert(snprintf(buf, 128, "%a", 0x1.123456p12) == 14);
assert(strcmp(buf, "0x1.123456p+12") == 0);
assert(snprintf(buf, 128, "%a", -0x1.123456p-12) == 15);
assert(strcmp(buf, "-0x1.123456p-12") == 0);
assert(snprintf(buf, 128, "%a", INFINITY) == 3);
assert(strcmp(buf, "inf") == 0);
assert(snprintf(buf, 128, "%a", NAN) == 3);
assert(strcmp(buf, "nan") == 0);
assert(snprintf(buf, 128, "%la", 0x1.123456p12) == 14);
assert(strcmp(buf, "0x1.123456p+12") == 0);
assert(snprintf(buf, 128, "%La", 0x1.123456p12L) == 12);
assert(strcmp(buf, "0x8.91a2bp+9") == 0);
assert(snprintf(buf, 128, "%A", 0x1.123456p12) == 14);
assert(strcmp(buf, "0X1.123456P+12") == 0);
assert(snprintf(buf, 128, "%A", INFINITY) == 3);
assert(strcmp(buf, "INF") == 0);
assert(snprintf(buf, 128, "%A", NAN) == 3);
assert(strcmp(buf, "NAN") == 0);
assert(snprintf(buf, 128, "%lA", 0x1.123456p12) == 14);
assert(strcmp(buf, "0X1.123456P+12") == 0);
assert(snprintf(buf, 128, "%LA", 0x1.123456p12L) == 12);
assert(strcmp(buf, "0X8.91A2BP+9") == 0);*/
assert(snprintf(buf, 128, "%g", 1.1234) == 6);
assert(strcmp(buf, "1.1234") == 0);
assert(snprintf(buf, 128, "%g", 0.0) == 1);
assert(strcmp(buf, "0") == 0);
assert(snprintf(buf, 128, "%g", -1.1234) == 7);
assert(strcmp(buf, "-1.1234") == 0);
assert(snprintf(buf, 128, "%g", 1.1234e12) == 10);
assert(strcmp(buf, "1.1234e+12") == 0);
assert(snprintf(buf, 128, "%g", -1.1234e-12) == 11);
assert(strcmp(buf, "-1.1234e-12") == 0);
assert(snprintf(buf, 128, "%g", INFINITY) == 3);
assert(strcmp(buf, "inf") == 0);
assert(snprintf(buf, 128, "%g", NAN) == 3);
assert(strcmp(buf, "nan") == 0);
assert(snprintf(buf, 128, "%lg", 1.1234e12) == 10);
assert(strcmp(buf, "1.1234e+12") == 0);
assert(snprintf(buf, 128, "%Lg", 1.1234e12L) == 10);
assert(strcmp(buf, "1.1234e+12") == 0);
assert(snprintf(buf, 128, "%G", 1.1234) == 6);
assert(strcmp(buf, "1.1234") == 0);
assert(snprintf(buf, 128, "%G", 1.1234e12) == 10);
assert(strcmp(buf, "1.1234E+12") == 0);
assert(snprintf(buf, 128, "%G", INFINITY) == 3);
assert(strcmp(buf, "INF") == 0);
assert(snprintf(buf, 128, "%G", NAN) == 3);
assert(strcmp(buf, "NAN") == 0);
assert(snprintf(buf, 128, "%lG", 1.1234e12) == 10);
assert(strcmp(buf, "1.1234E+12") == 0);
assert(snprintf(buf, 128, "%LG", 1.1234e12L) == 10);
assert(strcmp(buf, "1.1234E+12") == 0);
signed char char_value = 0;
assert(snprintf(buf, 128, "ab%hhnc", &char_value) == 3);
assert(strcmp(buf, "abc") == 0);
assert(char_value == 2);
short short_value = 0;
assert(snprintf(buf, 128, "ab%hnc", &short_value) == 3);
assert(strcmp(buf, "abc") == 0);
assert(short_value == 2);
int int_value = 0;
assert(snprintf(buf, 128, "ab%nc", &int_value) == 3);
assert(strcmp(buf, "abc") == 0);
assert(int_value == 2);
long long_value = 0;
assert(snprintf(buf, 128, "ab%lnc", &long_value) == 3);
assert(strcmp(buf, "abc") == 0);
assert(long_value == 2);
long long long_long_value = 0;
assert(snprintf(buf, 128, "ab%llnc", &long_long_value) == 3);
assert(strcmp(buf, "abc") == 0);
assert(long_long_value == 2);
intmax_t intmax_value = 0;
assert(snprintf(buf, 128, "ab%jnc", &intmax_value) == 3);
assert(strcmp(buf, "abc") == 0);
assert(intmax_value == 2);
ssize_t size_value = 0;
assert(snprintf(buf, 128, "ab%znc", &size_value) == 3);
assert(strcmp(buf, "abc") == 0);
assert(size_value == 2);
ptrdiff_t ptrdiff_value = 0;
assert(snprintf(buf, 128, "ab%tnc", &ptrdiff_value) == 3);
assert(strcmp(buf, "abc") == 0);
assert(ptrdiff_value == 2);
#if UINTPTR_MAX == UINT64_MAX
uintptr_t ptr_value = 0xFFFFFFFFFFFFFFFF;
assert(snprintf(buf, 128, "%p", (void *)ptr_value) == 18);
assert(strcmp(buf, "0xffffffffffffffff") == 0);
#else
uintptr_t ptr_value = 0xFFFFFFFF;
assert(snprintf(buf, 128, "%p", (void*)ptr_value) == 10);
assert(strcmp(buf, "0xffffffff") == 0);
#endif
ptr_value = 0xFFFF;
assert(snprintf(buf, 128, "%p", (void*)ptr_value) == 6);
assert(strcmp(buf, "0xffff") == 0);
assert(snprintf(buf, 128, "%-4dhello", 12) == 9);
assert(strcmp(buf, "12 hello") == 0);
assert(snprintf(buf, 128, "%-4dhello", -12) == 9);
assert(strcmp(buf, "-12 hello") == 0);
assert(snprintf(buf, 128, "%#-4xhello", 0x12) == 9);
assert(strcmp(buf, "0x12hello") == 0);
assert(snprintf(buf, 128, "%#-4Xhello", 0x12) == 9);
assert(strcmp(buf, "0X12hello") == 0);
assert(snprintf(buf, 128, "%#b", 0b1011) == 6);
assert(strcmp(buf, "0b1011") == 0);
assert(snprintf(buf, 128, "%#B", 0b1011) == 6);
assert(strcmp(buf, "0B1011") == 0);
assert(snprintf(buf, 128, "%+d", 1234) == 5);
assert(strcmp(buf, "+1234") == 0);
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat"
assert(snprintf(buf, 128, "%+ d", 1234) == 5);
assert(strcmp(buf, "+1234") == 0);
#pragma GCC diagnostic pop
assert(snprintf(buf, 128, "% d", 1234) == 5);
assert(strcmp(buf, " 1234") == 0);
assert(snprintf(buf, 128, "%4dhello", 12) == 9);
assert(strcmp(buf, " 12hello") == 0);
assert(snprintf(buf, 128, "%2dhello", 1234) == 9);
assert(strcmp(buf, "1234hello") == 0);
int width = 4;
assert(snprintf(buf, 128, "%*dhello", width, 12) == 9);
assert(strcmp(buf, " 12hello") == 0);
width = -4;
assert(snprintf(buf, 128, "%*dhello", width, 12) == 9);
assert(strcmp(buf, "12 hello") == 0);
assert(snprintf(buf, 128, "%04dhello", 12) == 9);
assert(strcmp(buf, "0012hello") == 0);
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat"
assert(snprintf(buf, 128, "%-04dhello", 12) == 9);
assert(strcmp(buf, "12 hello") == 0);
assert(snprintf(buf, 128, "%04.2dhello", 1) == 9);
assert(strcmp(buf, " 01hello") == 0);
#pragma GCC diagnostic pop
assert(snprintf(buf, 128, "%.d", 0) == 0);
assert(strcmp(buf, "") == 0);
assert(snprintf(buf, 128, "%.0d", 0) == 0);
assert(strcmp(buf, "") == 0);
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat"
assert(snprintf(buf, 128, "%04.d", 0) == 4);
assert(strcmp(buf, " ") == 0);
assert(snprintf(buf, 128, "%#04.x", 0) == 4);
assert(strcmp(buf, " ") == 0);
assert(snprintf(buf, 128, "%+04.d", 0) == 4);
assert(strcmp(buf, " +") == 0);
assert(snprintf(buf, 128, "%+0.d", 0) == 1);
assert(strcmp(buf, "+") == 0);
#pragma GCC diagnostic pop
int precision = 0;
assert(snprintf(buf, 128, "%.*d", precision, 0) == 0);
assert(strcmp(buf, "") == 0);
precision = -1;
assert(snprintf(buf, 128, "%.*d", precision, 0) == 1);
assert(strcmp(buf, "0") == 0);
assert(snprintf(buf, 128, "%.6d", 1234) == 6);
assert(strcmp(buf, "001234") == 0);
assert(snprintf(buf, 128, "%.o", 0) == 0);
assert(strcmp(buf, "") == 0);
assert(snprintf(buf, 128, "%.0o", 0) == 0);
assert(strcmp(buf, "") == 0);
return 0;
}
+371
View File
@@ -0,0 +1,371 @@
#include <fenv.h>
#include <stdio.h>
#include <assert.h>
#include <math.h>
#include <string.h>
int main() {
char buf[64] = { 0 };
sprintf(buf, "%d", 12);
assert(!strcmp(buf, "12"));
sprintf(buf, "%f", 3.14);
assert(!strcmp(buf, "3.140000"));
sprintf(buf, "%.1f", 0.0);
assert(!strcmp(buf, "0.0"));
// Test %g
sprintf(buf, "%g", 0.0);
assert(!strcmp(buf, "0"));
sprintf(buf, "%.2g", 0.01234);
assert(!strcmp(buf, "0.012"));
sprintf(buf, "%.3g", 1.1);
assert(!strcmp(buf, "1.1"));
sprintf(buf, "%#.5g", 1.1);
assert(!strcmp(buf, "1.1000"));
sprintf(buf, "%g", 0.0000123);
assert(!strcmp(buf, "1.23e-05"));
// Test %e
sprintf(buf, "%4.3e", 0.0);
assert(!strcmp(buf, "0.000e+00"));
sprintf(buf, "%.3e", 6.9e27);
assert(!strcmp(buf, "6.900e+27"));
// Test %c right padding.
sprintf(buf, "%-2c", 'a');
assert(!strcmp(buf, "a "));
// Test %c left padding.
sprintf(buf, "%2c", 'a');
assert(!strcmp(buf, " a"));
// Test %d right padding - mlibc issue #58.
sprintf(buf, "%-2d", 1);
assert(!strcmp(buf, "1 "));
sprintf(buf, "%-2.2d", 1);
assert(!strcmp(buf, "01"));
sprintf(buf, "%-3.2d", 1);
assert(!strcmp(buf, "01 "));
sprintf(buf, "%-3.2d", 12);
assert(!strcmp(buf, "12 "));
sprintf(buf, "%-3.2d", 123);
assert(!strcmp(buf, "123"));
sprintf(buf, "%-3.2u", 12);
assert(!strcmp(buf, "12 "));
// Test %d left padding.
sprintf(buf, "%2d", 1);
assert(!strcmp(buf, " 1"));
sprintf(buf, "%3.2d", 1);
assert(!strcmp(buf, " 01"));
sprintf(buf, "%3.2d", 12);
assert(!strcmp(buf, " 12"));
sprintf(buf, "%3.2d", 123);
assert(!strcmp(buf, "123"));
sprintf(buf, "%3.2u", 12);
assert(!strcmp(buf, " 12"));
// Disable -Wformat here since we deliberately induce some warnings.
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat"
sprintf(buf, "%04.3u", 12);
assert(!strcmp(buf, " 012"));
#pragma GCC diagnostic pop
sprintf(buf, "%+04d", 0);
assert(!strcmp(buf, "+000"));
// Test %f padding.
// TODO: Test printing of huge numbers (larger than 2^64)
sprintf(buf, "%2.f", 1.2);
assert(!strcmp(buf, " 1"));
sprintf(buf, "%2.f", 12.3);
assert(!strcmp(buf, "12"));
sprintf(buf, "%5.2f", 1.0);
assert(!strcmp(buf, " 1.00"));
sprintf(buf, "%.1f", -4.0);
assert(!strcmp(buf, "-4.0"));
sprintf(buf, "%-3.f", 8.0);
assert(!strcmp(buf, "8 "));
sprintf(buf, "%4f", INFINITY);
assert(!strcmp(buf, " inf") || !strcmp(buf, "infinity"));
sprintf(buf, "%4f", NAN);
assert(!strcmp(buf, " nan"));
sprintf(buf, "%4F", INFINITY);
assert(!strcmp(buf, " INF") || !strcmp(buf, "INFINITY"));
sprintf(buf, "%4F", NAN);
assert(!strcmp(buf, " NAN"));
sprintf(buf, "%05.2f", 1.0);
assert(!strcmp(buf, "01.00"));
sprintf(buf, "%09f", INFINITY); // 0 ignored when padding infs
assert(!strcmp(buf, " inf") || !strcmp(buf, " infinity"));
// Test %f rounding
sprintf(buf, "%5.2f", 1.2);
assert(!strcmp(buf, " 1.20"));
sprintf(buf, "%5.2f", 1.23);
assert(!strcmp(buf, " 1.23"));
sprintf(buf, "%5.2f", 1.234);
assert(!strcmp(buf, " 1.23"));
sprintf(buf, "%5.2f", 12.345);
assert(!strcmp(buf, "12.35"));
sprintf(buf, "%-5.2f", 1.2);
assert(!strcmp(buf, "1.20 "));
// Test '+' and ' ' flags - mlibc issue #229.
// Disable -Wformat here since we deliberately induce some warnings.
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat"
sprintf(buf, "%+d", 12);
assert(!strcmp(buf, "+12"));
sprintf(buf, "% d", 12);
assert(!strcmp(buf, " 12"));
sprintf(buf, "% +d", 12);
assert(!strcmp(buf, "+12"));
sprintf(buf, "%+ d", 12);
assert(!strcmp(buf, "+12"));
sprintf(buf, "%+d", -12);
assert(!strcmp(buf, "-12"));
sprintf(buf, "% d", -12);
assert(!strcmp(buf, "-12"));
sprintf(buf, "% +d", -12);
assert(!strcmp(buf, "-12"));
sprintf(buf, "%+ d", -12);
assert(!strcmp(buf, "-12"));
#pragma GCC diagnostic pop
// Test '#' flag.
// TODO: Test with a, A, e, E, f, F, g, G conversions.
sprintf(buf, "%#x", 12);
assert(!strcmp(buf, "0xc"));
sprintf(buf, "%#X", 12);
assert(!strcmp(buf, "0XC"));
sprintf(buf, "%#o", 12);
assert(!strcmp(buf, "014"));
sprintf(buf, "%#x", 0);
assert(!strcmp(buf, "0"));
sprintf(buf, "%#X", 0);
assert(!strcmp(buf, "0"));
sprintf(buf, "%#o", 0);
assert(!strcmp(buf, "0"));
// Disable -Wformat here because the compiler might not know about the b specifier.
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat"
sprintf(buf, "%#b", 12);
assert(!strcmp(buf, "0b1100"));
sprintf(buf, "%#B", 12);
assert(!strcmp(buf, "0B1100"));
sprintf(buf, "%#b", 0);
assert(!strcmp(buf, "0"));
sprintf(buf, "%#B", 0);
assert(!strcmp(buf, "0"));
#pragma GCC diagnostic pop
// Test 'd' with different size mods to see
// if they work
sprintf(buf, "%d", 12);
assert(!strcmp(buf, "12"));
sprintf(buf, "%ld", 12L);
assert(!strcmp(buf, "12"));
sprintf(buf, "%lld", 12LL);
assert(!strcmp(buf, "12"));
sprintf(buf, "%zd", (size_t)12);
assert(!strcmp(buf, "12"));
sprintf(buf, "%hd", (short) 12);
assert(!strcmp(buf, "12"));
sprintf(buf, "%hhd", (char) 12);
assert(!strcmp(buf, "12"));
// Test 'x' with different size mods to see
// if they work
sprintf(buf, "%x", 12);
assert(!strcmp(buf, "c"));
sprintf(buf, "%lx", 12L);
assert(!strcmp(buf, "c"));
sprintf(buf, "%llx", 12LL);
assert(!strcmp(buf, "c"));
sprintf(buf, "%zx", (size_t)12);
assert(!strcmp(buf, "c"));
sprintf(buf, "%hx", (unsigned short) 12);
assert(!strcmp(buf, "c"));
sprintf(buf, "%hhx", (unsigned char) 12);
assert(!strcmp(buf, "c"));
// Test 'X' with different size mods to see
// if they work
sprintf(buf, "%X", 12);
assert(!strcmp(buf, "C"));
sprintf(buf, "%lX", 12L);
assert(!strcmp(buf, "C"));
sprintf(buf, "%llX", 12LL);
assert(!strcmp(buf, "C"));
sprintf(buf, "%zX", (size_t)12);
assert(!strcmp(buf, "C"));
sprintf(buf, "%hX", (unsigned short) 12);
assert(!strcmp(buf, "C"));
sprintf(buf, "%hhX", (unsigned char) 12);
assert(!strcmp(buf, "C"));
// Test 'o' with different size mods to see
// if they work
sprintf(buf, "%o", 12);
assert(!strcmp(buf, "14"));
sprintf(buf, "%lo", 12L);
assert(!strcmp(buf, "14"));
sprintf(buf, "%llo", 12LL);
assert(!strcmp(buf, "14"));
sprintf(buf, "%zo", (size_t)12);
assert(!strcmp(buf, "14"));
sprintf(buf, "%ho", (unsigned short) 12);
assert(!strcmp(buf, "14"));
sprintf(buf, "%hho", (unsigned char) 12);
assert(!strcmp(buf, "14"));
// Disable -Wformat here because the compiler might not know about the b specifier.
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat"
// Test 'b' with different size mods to see
// if they work
sprintf(buf, "%b", 12);
assert(!strcmp(buf, "1100"));
sprintf(buf, "%lb", 12L);
assert(!strcmp(buf, "1100"));
sprintf(buf, "%llb", 12LL);
assert(!strcmp(buf, "1100"));
sprintf(buf, "%zb", (size_t)12);
assert(!strcmp(buf, "1100"));
sprintf(buf, "%hb", (unsigned short) 12);
assert(!strcmp(buf, "1100"));
sprintf(buf, "%hhb", (unsigned char) 12);
assert(!strcmp(buf, "1100"));
#pragma GCC diagnostic pop
// Test %n$ syntax.
sprintf(buf, "%1$d", 12);
assert(!strcmp(buf, "12"));
sprintf(buf, "%1$d %1$d", 12);
assert(!strcmp(buf, "12 12"));
sprintf(buf, "%1$d %2$d %1$d", 12, 14);
assert(!strcmp(buf, "12 14 12"));
sprintf(buf, "%1$d %2$s %2$s", 12, "foo");
assert(!strcmp(buf, "12 foo foo"));
sprintf(buf, "%1$s%5$s%6$s%3$s%4$s%2$s", "a", "b", "u", "n", "h", "N");
assert(!strcmp(buf, "ahNunb"));
// test negative precision
sprintf(buf, "%.*g", -2, 15.1234567);
assert(!strcmp(buf, "15.1235"));
sprintf(buf, "%*g", -5, 15.1);
assert(!strcmp(buf, "15.1 "));
// Disable -Wformat as the compiler rightfully warns that the '0' flag is ignored
// when the '0' flag is used
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat"
sprintf(buf, "%0-6g", 69.2);
assert(!strcmp(buf, "69.2 "));
#pragma GCC diagnostic pop
// More extensive floating point tests.
// Test zero and negative zero
sprintf(buf, "%f", 0.0);
assert(!strcmp(buf, "0.000000"));
sprintf(buf, "%f", -0.0);
assert(!strcmp(buf, "-0.000000"));
sprintf(buf, "%e", 0.0);
assert(!strcmp(buf, "0.000000e+00"));
sprintf(buf, "%e", -0.0);
assert(!strcmp(buf, "-0.000000e+00"));
sprintf(buf, "%g", 0.0);
assert(!strcmp(buf, "0"));
sprintf(buf, "%g", -0.0);
assert(!strcmp(buf, "-0"));
// Test rounding
sprintf(buf, "%.2f", 1.235);
assert(!strcmp(buf, "1.24"));
sprintf(buf, "%.2f", -1.235);
assert(!strcmp(buf, "-1.24"));
// 1.2349999999999998 is a double literal that is slightly less than 1.235
sprintf(buf, "%.2f", 1.2349999999999998);
assert(!strcmp(buf, "1.23"));
sprintf(buf, "%.0f", 0.49);
assert(!strcmp(buf, "0"));
sprintf(buf, "%.0f", -0.49);
assert(!strcmp(buf, "-0"));
// Test round-to-even behavior
fesetround(FE_TONEAREST);
sprintf(buf, "%.0f", 0.5);
assert(!strcmp(buf, "0"));
sprintf(buf, "%.0f", -0.5);
assert(!strcmp(buf, "-0"));
sprintf(buf, "%.0f", 0.51);
assert(!strcmp(buf, "1"));
sprintf(buf, "%.0f", -0.51);
assert(!strcmp(buf, "-1"));
sprintf(buf, "%.0f", 2.5);
assert(!strcmp(buf, "2"));
sprintf(buf, "%.0f", -2.5);
assert(!strcmp(buf, "-2"));
sprintf(buf, "%.0f", 2.51);
assert(!strcmp(buf, "3"));
sprintf(buf, "%.0f", -2.51);
assert(!strcmp(buf, "-3"));
// Test %e/%E
sprintf(buf, "%.3e", 12345.0);
assert(!strcmp(buf, "1.234e+04"));
sprintf(buf, "%.3E", 12345.0);
assert(!strcmp(buf, "1.234E+04"));
sprintf(buf, "%.3e", 0.00012345);
assert(!strcmp(buf, "1.234e-04"));
sprintf(buf, "%.3E", -0.00012345);
assert(!strcmp(buf, "-1.234E-04"));
// Test %g/%G behavior
sprintf(buf, "%g", 123456.0); // Should not use e-notation
assert(!strcmp(buf, "123456"));
sprintf(buf, "%g", 1234567.0); // Should use e-notation
assert(!strcmp(buf, "1.23457e+06"));
sprintf(buf, "%g", 12345.0);
assert(!strcmp(buf, "12345"));
sprintf(buf, "%g", 1.2345);
assert(!strcmp(buf, "1.2345"));
sprintf(buf, "%g", 0.00012345); // Should not use e-notation
assert(!strcmp(buf, "0.00012345"));
sprintf(buf, "%g", 0.000012345); // Should use e-notation
assert(!strcmp(buf, "1.2345e-05"));
// %g precision
sprintf(buf, "%.3g", 12345.0);
assert(!strcmp(buf, "1.23e+04"));
sprintf(buf, "%.3G", 12345.0);
assert(!strcmp(buf, "1.23E+04"));
sprintf(buf, "%.3g", 1.234);
assert(!strcmp(buf, "1.23"));
sprintf(buf, "%.3g", 0.001234);
assert(!strcmp(buf, "0.00123"));
sprintf(buf, "%.3g", 0.0001234); // Should not use e-notation
assert(!strcmp(buf, "0.000123"));
sprintf(buf, "%.3g", 0.00001234); // Should use e-notation
assert(!strcmp(buf, "1.23e-05"));
sprintf(buf, "%08.1g", 69.2);
assert(!strcmp(buf, "0007e+01"));
sprintf(buf, "%#08.4g", 69.29854);
assert(!strcmp(buf, "00069.30"));
// %g trailing zeros
sprintf(buf, "%g", 1.200);
assert(!strcmp(buf, "1.2"));
sprintf(buf, "%#g", 1.200);
assert(!strcmp(buf, "1.20000"));
sprintf(buf, "%g", 1200.0);
assert(!strcmp(buf, "1200"));
sprintf(buf, "%#g", 1200.0);
assert(!strcmp(buf, "1200.00"));
return 0;
}
+516
View File
@@ -0,0 +1,516 @@
#include <math.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <wchar.h>
struct format_test_cases {
const char *format;
const char *data;
int expected_int;
enum {
T_INT,
T_UINT,
T_CHAR,
T_NONE,
} type;
int ret;
} formats[] = {
{"%i", "0x420", 0x420, T_INT, 1},
{"%i", "0420", 0420, T_INT, 1},
{"%i", "420", 420, T_INT, 1},
{"%i", "-420", -420, T_INT, 1},
{"%d", "-12345", -12345, T_INT, 1},
{"%u", "69", 69, T_UINT, 1},
{"%u", "0420", 420, T_UINT, 1},
{"%o", "0420", 0420, T_UINT, 1},
{"%x", "0xCB7", 0xCB7, T_UINT, 1},
#ifndef USE_HOST_LIBC
{"%b", "0b1011", 0b1011, T_UINT, 1},
{"%b", "0B1011", 0b1011, T_UINT, 1},
#endif
{"%%", "%", 0, T_NONE, 0},
{"%c", " I am not a fan of this solution.", ' ', T_CHAR, 1},
{" %c", " CBT (capybara therapy)", 'C', T_CHAR, 1},
{"%d %d %d", " 111111 I<3Managarm 1234", 111111, T_UINT, 1},
{"%c %d", "C", 'C', T_CHAR, 1}
};
#pragma GCC diagnostic ignored "-Wformat-security"
static void test_matrix() {
for(size_t i = 0; i < (sizeof(formats) / sizeof(*formats)); i++) {
struct format_test_cases *f = &formats[i];
int ret = -1;
int data_int;
unsigned int data_uint;
char data_char;
switch(f->type) {
case T_INT: {
ret = sscanf(f->data, f->format, &data_int);
assert(data_int == f->expected_int);
break;
}
case T_UINT: {
ret = sscanf(f->data, f->format, &data_uint);
assert(data_uint == (unsigned int) f->expected_int);
break;
}
case T_CHAR: {
ret = sscanf(f->data, f->format, &data_char);
assert(data_char == (unsigned char) f->expected_int);
break;
}
case T_NONE: {
ret = sscanf(f->data, f->format);
break;
}
}
assert(ret == f->ret);
}
}
int main() {
{
int x = 0;
char buf[] = "12345";
sscanf(buf, "%d", &x);
assert(x == 12345);
}
{
char c;
int n1;
int n2;
char buf[] = "z$ 7 5 440";;
int count = sscanf(buf, "%*c%c %d %*d %d", &c, &n1, &n2);
assert(count == 3);
assert(c == '$');
assert(n1 == 7);
assert(n2 == 440);
}
{
// From dsda-doom
char buf[] = "process_priority 0\n";
char def[80], strparm[128];
memset(def, '!', 80);
memset(strparm, '!', 128);
sscanf(buf, "%s %[^\n]\n", def, strparm);
assert(!strcmp(def, "process_priority"));
assert(!strcmp(strparm, "0"));
}
{
char buf[] = "fffff100";
unsigned long y = 0;
sscanf(buf, "%lx", &y);
assert(y == 0xfffff100);
}
#if !defined(__i386__) && !defined(__m68k__)
{
char buf[] = "fffffffff100";
unsigned long y = 0;
sscanf(buf, "%lx", &y);
assert(y == 0xfffffffff100);
}
#endif
{
char buf[] = "410dc000";
unsigned long y = 0;
sscanf(buf, "%lx", &y);
assert(y == 0x410dc000);
}
{
// From webkitgtk
char buf[] = "MemTotal: 16299664 kB\n";
char token[51] = {0};
size_t amount = 0;
int ret = sscanf(buf, "%50s%zukB", token, &amount);
assert(ret == 2);
assert(!strcmp(token, "MemTotal:"));
assert(amount == 16299664);
}
{
char buf[] = "SIGINT";
int sig;
int ret = sscanf(buf, "%d", &sig);
assert(!ret);
}
{
char buf[50];
int ret = sscanf("", "%s", buf);
assert(ret == EOF);
}
{
char *str = NULL;
int ret = sscanf("Managarm", "%ms", &str);
assert(ret == 1);
assert(str != NULL);
assert(!strcmp(str, "Managarm"));
free(str);
}
test_matrix();
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat-zero-length"
assert(sscanf("", "") == 0);
#pragma GCC diagnostic pop
assert(sscanf("", "a") == EOF);
assert(sscanf(" \t\na", " a") == 0);
assert(sscanf("a%", "a%%") == 0);
assert(sscanf("ab", "abcd") == EOF);
assert(sscanf("abab", "abcd") == 0);
char char_value[8];
wchar_t wchar_value[8];
assert(sscanf("a", "%c", char_value) == 1);
assert(char_value[0] == 'a');
assert(sscanf("a", "%lc", wchar_value) == 1);
assert(wchar_value[0] == L'a');
assert(sscanf("hello", "%s", char_value) == 1);
assert(strcmp(char_value, "hello") == 0);
assert(sscanf("", "%s", char_value) == EOF);
assert(sscanf(" ", "%s", char_value) == EOF);
assert(sscanf(" a", "%sb", char_value) == 1);
assert(sscanf("hello", "%ls", wchar_value) == 1);
assert(wcscmp(wchar_value, L"hello") == 0);
assert(sscanf("abcd", "%[ac]bcd", char_value) == 1);
assert(strcmp(char_value, "a") == 0);
assert(sscanf("abcd", "%l[ac]bcd", wchar_value) == 1);
assert(wcscmp(wchar_value, L"a") == 0);
assert(sscanf("aacd", "%[ac]bcd", char_value) == 1);
assert(strcmp(char_value, "aac") == 0);
assert(sscanf("aacd", "%[ac]bcd", char_value) == 1);
assert(strcmp(char_value, "aac") == 0);
assert(sscanf("]", "%[]]", char_value) == 1);
assert(strcmp(char_value, "]") == 0);
assert(sscanf("]", "%[^]]", char_value) == 0);
assert(sscanf("abcd", "%[^ac]bcd", char_value) == 0);
assert(sscanf("aacd", "%[^ac]bcd", char_value) == 0);
assert(sscanf("aacd", "%[^ac]bcd", char_value) == 0);
assert(sscanf("ddd", "%[^ac]bcd", char_value) == 1);
assert(strcmp(char_value, "ddd") == 0);
assert(sscanf("abcd", "%[0-9]", char_value) == 0);
assert(sscanf("2a", "%[0-9]", char_value) == 1);
assert(strcmp(char_value, "2") == 0);
unsigned char uchar_value;
signed char schar_value;
unsigned short ushort_value;
short short_value;
unsigned int uint_value;
int int_value;
unsigned long ulong_value;
long long_value;
unsigned long long ulonglong_value;
long long longlong_value;
uintmax_t uintmax_value;
intmax_t intmax_value;
size_t size_value;
ptrdiff_t ptrdiff_value;
assert(sscanf("1234abc", "%d", &int_value) == 1);
assert(int_value == 1234);
assert(sscanf("123", "%hhd", &schar_value) == 1);
assert(schar_value == 123);
assert(sscanf("1234", "%hd", &short_value) == 1);
assert(short_value == 1234);
assert(sscanf("1234", "%ld", &long_value) == 1);
assert(long_value == 1234);
assert(sscanf("1234", "%lld", &longlong_value) == 1);
assert(longlong_value == 1234);
assert(sscanf("1234", "%jd", &intmax_value) == 1);
assert(intmax_value == 1234);
assert(sscanf("1234", "%zd", &size_value) == 1);
assert(size_value == 1234);
assert(sscanf("1234", "%td", &ptrdiff_value) == 1);
assert(ptrdiff_value == 1234);
assert(sscanf(" 1235abc", "%d", &int_value) == 1);
assert(int_value == 1235);
assert(sscanf("+1234abc", "%d", &int_value) == 1);
assert(int_value == 1234);
assert(sscanf("-1234abc", "%d", &int_value) == 1);
assert(int_value == -1234);
assert(sscanf("-abc", "%d", &int_value) == 0);
assert(sscanf("-", "%d", &int_value) == 0);
assert(sscanf("1234abc", "%i", &int_value) == 1);
assert(int_value == 1234);
assert(sscanf("123", "%hhi", &schar_value) == 1);
assert(schar_value == 123);
assert(sscanf("1234", "%hi", &short_value) == 1);
assert(short_value == 1234);
assert(sscanf("1234", "%li", &long_value) == 1);
assert(long_value == 1234);
assert(sscanf("1234", "%lli", &longlong_value) == 1);
assert(longlong_value == 1234);
assert(sscanf("1234", "%ji", &intmax_value) == 1);
assert(intmax_value == 1234);
assert(sscanf("1234", "%zi", &size_value) == 1);
assert(size_value == 1234);
assert(sscanf("1234", "%ti", &ptrdiff_value) == 1);
assert(ptrdiff_value == 1234);
assert(sscanf(" 1235abc", "%i", &int_value) == 1);
assert(int_value == 1235);
assert(sscanf("+1234abc", "%i", &int_value) == 1);
assert(int_value == 1234);
assert(sscanf("-1234abc", "%i", &int_value) == 1);
assert(int_value == -1234);
assert(sscanf("-abc", "%i", &int_value) == 0);
assert(sscanf(" 0b1011", "%i", &int_value) == 1);
assert(int_value == 0b1011);
assert(sscanf(" 0B1010", "%i", &int_value) == 1);
assert(int_value == 0b1010);
assert(sscanf(" +0b1011", "%i", &int_value) == 1);
assert(int_value == 0b1011);
assert(sscanf(" -0b1111", "%i", &int_value) == 1);
assert(int_value == -0b1111);
assert(sscanf(" 01234", "%i", &int_value) == 1);
assert(int_value == 01234);
assert(sscanf(" +01234", "%i", &int_value) == 1);
assert(int_value == 01234);
assert(sscanf(" -01234", "%i", &int_value) == 1);
assert(int_value == -01234);
assert(sscanf(" 0xab12", "%i", &int_value) == 1);
assert(int_value == 0xAB12);
assert(sscanf(" 0xAB12", "%i", &int_value) == 1);
assert(int_value == 0xAB12);
assert(sscanf(" 0Xab12", "%i", &int_value) == 1);
assert(int_value == 0xAB12);
assert(sscanf(" +0xab12", "%i", &int_value) == 1);
assert(int_value == 0xAB12);
assert(sscanf(" -0xab12", "%i", &int_value) == 1);
assert(int_value == -0xAB12);
assert(sscanf("1234abc", "%u", &uint_value) == 1);
assert(uint_value == 1234);
assert(sscanf("123", "%hhu", &uchar_value) == 1);
assert(uchar_value == 123);
assert(sscanf("1234", "%hu", &ushort_value) == 1);
assert(ushort_value == 1234);
assert(sscanf("1234", "%lu", &ulong_value) == 1);
assert(ulong_value == 1234);
assert(sscanf("1234", "%llu", &ulonglong_value) == 1);
assert(ulonglong_value == 1234);
assert(sscanf("1234", "%ju", &uintmax_value) == 1);
assert(uintmax_value == 1234);
assert(sscanf("1234", "%zu", &size_value) == 1);
assert(size_value == 1234);
assert(sscanf("1234", "%tu", &ptrdiff_value) == 1);
assert(ptrdiff_value == 1234);
assert(sscanf(" 1235abc", "%u", &int_value) == 1);
assert(int_value == 1235);
assert(sscanf("+1234abc", "%u", &int_value) == 1);
assert(int_value == 1234);
assert(sscanf("-1234abc", "%u", &int_value) == 1);
assert(int_value == -1234);
assert(sscanf("-abc", "%d", &int_value) == 0);
assert(sscanf(" 12345", "%o", &int_value) == 1);
assert(int_value == 012345);
assert(sscanf("12", "%hho", &uchar_value) == 1);
assert(uchar_value == 012);
assert(sscanf("1234", "%ho", &ushort_value) == 1);
assert(ushort_value == 01234);
assert(sscanf("1234", "%lo", &ulong_value) == 1);
assert(ulong_value == 01234);
assert(sscanf("1234", "%llo", &ulonglong_value) == 1);
assert(ulonglong_value == 01234);
assert(sscanf("1234", "%jo", &uintmax_value) == 1);
assert(uintmax_value == 01234);
assert(sscanf("1234", "%zo", &size_value) == 1);
assert(size_value == 01234);
assert(sscanf("1234", "%to", &ptrdiff_value) == 1);
assert(ptrdiff_value == 01234);
assert(sscanf(" 01234", "%o", &int_value) == 1);
assert(int_value == 01234);
assert(sscanf(" +01234", "%o", &int_value) == 1);
assert(int_value == 01234);
assert(sscanf(" -01234", "%o", &int_value) == 1);
assert(int_value == -01234);
assert(sscanf(" 1234ab", "%x", &int_value) == 1);
assert(int_value == 0x1234AB);
assert(sscanf("12", "%hhx", &uchar_value) == 1);
assert(uchar_value == 0x12);
assert(sscanf("1234", "%hx", &ushort_value) == 1);
assert(ushort_value == 0x1234);
assert(sscanf("1234", "%lx", &ulong_value) == 1);
assert(ulong_value == 0x1234);
assert(sscanf("1234", "%llx", &ulonglong_value) == 1);
assert(ulonglong_value == 0x1234);
assert(sscanf("1234", "%jx", &uintmax_value) == 1);
assert(uintmax_value == 0x1234);
assert(sscanf("1234", "%zx", &size_value) == 1);
assert(size_value == 0x1234);
assert(sscanf("1234", "%tx", &ptrdiff_value) == 1);
assert(ptrdiff_value == 0x1234);
assert(sscanf(" 1234ABC", "%x", &int_value) == 1);
assert(int_value == 0x1234ABC);
assert(sscanf(" 1234ab", "%X", &int_value) == 1);
assert(int_value == 0x1234AB);
assert(sscanf(" 0x1234", "%x", &int_value) == 1);
assert(int_value == 0x1234);
assert(sscanf(" 0x1234A", "%x", &int_value) == 1);
assert(int_value == 0x1234A);
assert(sscanf(" 0X1234AB", "%x", &int_value) == 1);
assert(int_value == 0x1234AB);
assert(sscanf(" +0x1234", "%x", &int_value) == 1);
assert(int_value == 0x1234);
assert(sscanf(" -0x1234", "%x", &int_value) == 1);
assert(int_value == -0x1234);
assert(sscanf("abc", "abc%n", &int_value) == 0);
assert(int_value == 3);
assert(sscanf("1234", "1234%hhn", &uchar_value) == 0);
assert(uchar_value == 4);
assert(sscanf("1234", "1234%hn", &ushort_value) == 0);
assert(ushort_value == 4);
assert(sscanf("1234", "1234%ln", &ulong_value) == 0);
assert(ulong_value == 4);
assert(sscanf("1234", "1234%lln", &ulonglong_value) == 0);
assert(ulonglong_value == 4);
assert(sscanf("1234", "1234%jn", &uintmax_value) == 0);
assert(uintmax_value == 4);
assert(sscanf("1234", "1234%zn", &size_value) == 0);
assert(size_value == 4);
assert(sscanf("1234", "1234%tn", &ptrdiff_value) == 0);
assert(ptrdiff_value == 4);
assert(sscanf("abcd", "ab%nc%c", &int_value, char_value) == 1);
assert(int_value == 2);
assert(char_value[0] == 'd');
float float_value;
double double_value;
long double long_double_value;
(void)float_value;
(void)double_value;
(void)long_double_value;
/*assert(sscanf("1.123", "%a", &float_value) == 1);
assert(float_value >= 1.123f - 0.01 && float_value <= 1.123f + 0.01);
assert(sscanf("1.123", "%la", &double_value) == 1);
assert(double_value >= 1.123 - 0.01 && double_value <= 1.123 + 0.01);
assert(sscanf("1.123", "%La", &long_double_value) == 1);
assert(long_double_value >= 1.123L - 0.01 && long_double_value <= 1.123L + 0.01);
assert(sscanf("1.1234", "%A", &float_value) == 1);
assert(float_value >= 1.1234f - 0.01 && float_value <= 1.1234f + 0.01);
assert(sscanf("1.123", "%e", &float_value) == 1);
assert(float_value >= 1.123f - 0.01 && float_value <= 1.123f + 0.01);
assert(sscanf("1.123", "%le", &double_value) == 1);
assert(double_value >= 1.123 - 0.01 && double_value <= 1.123 + 0.01);
assert(sscanf("1.123", "%Le", &long_double_value) == 1);
assert(long_double_value >= 1.123L - 0.01 && long_double_value <= 1.123L + 0.01);
assert(sscanf("1.1234", "%E", &float_value) == 1);
assert(float_value >= 1.1234f - 0.01 && float_value <= 1.1234f + 0.01);
assert(sscanf("1.123", "%f", &float_value) == 1);
assert(float_value >= 1.123f - 0.01 && float_value <= 1.123f + 0.01);
assert(sscanf("1.123", "%lf", &double_value) == 1);
assert(double_value >= 1.123 - 0.01 && double_value <= 1.123 + 0.01);
assert(sscanf("1.123", "%Lf", &long_double_value) == 1);
assert(long_double_value >= 1.123L - 0.01 && long_double_value <= 1.123L + 0.01);
assert(sscanf("1.1234", "%F", &float_value) == 1);
assert(float_value >= 1.1234f - 0.01 && float_value <= 1.1234f + 0.01);
assert(sscanf("1.123", "%g", &float_value) == 1);
assert(float_value >= 1.123f - 0.01 && float_value <= 1.123f + 0.01);
assert(sscanf("1.123", "%lg", &double_value) == 1);
assert(double_value >= 1.123 - 0.01 && double_value <= 1.123 + 0.01);
assert(sscanf("1.123", "%Lg", &long_double_value) == 1);
assert(long_double_value >= 1.123L - 0.01 && long_double_value <= 1.123L + 0.01);
assert(sscanf("1.1234", "%G", &float_value) == 1);
assert(float_value >= 1.1234f - 0.01 && float_value <= 1.1234f + 0.01);
assert(sscanf("+1.1234", "%f", &float_value) == 1);
assert(float_value >= 1.1234f - 0.01 && float_value <= 1.1234f + 0.01);
assert(sscanf("-1.1234", "%f", &float_value) == 1);
assert(float_value >= -1.1234f - 0.01 && float_value <= -1.1234f + 0.01);
assert(sscanf("1.1234e3", "%f", &float_value) == 1);
assert(float_value >= 1.1234E3f - 0.01 && float_value <= 1.1234E3f + 0.01);
assert(sscanf("1.1234E3", "%f", &float_value) == 1);
assert(float_value >= 1.1234E3f - 0.01 && float_value <= 1.1234E3f + 0.01);
assert(sscanf("0x1234", "%f", &float_value) == 1);
assert(float_value >= 0x1234P0f - 0.01 && float_value <= 0x1234P0f + 0.01);
assert(sscanf("0X1234", "%f", &float_value) == 1);
assert(float_value >= 0x1234P0f - 0.01 && float_value <= 0x1234P0f + 0.01);
assert(sscanf("0x1.1234", "%f", &float_value) == 1);
assert(float_value >= 0x1.1234P0 - 0.01 && float_value <= 0x1.1234P0 + 0.01);
assert(sscanf("0x1.abcdP3", "%f", &float_value) == 1);
assert(float_value >= 0x1.ABCDP3 - 0.01 && float_value <= 0x1.ABCDP3 + 0.01);
assert(sscanf("0x1.abcdP+3", "%f", &float_value) == 1);
assert(float_value >= 0x1.ABCDP3 - 0.01 && float_value <= 0x1.ABCDP3 + 0.01);
assert(sscanf("0x1.abcdP-3", "%f", &float_value) == 1);
assert(float_value >= 0x1.ABCDP-3 - 0.01 && float_value <= 0x1.ABCDP-3 + 0.01);
assert(sscanf("0x1.AbCdP-3", "%f", &float_value) == 1);
assert(float_value >= 0x1.ABCDP-3 - 0.01 && float_value <= 0x1.ABCDP-3 + 0.01);
assert(sscanf("inf", "%f", &float_value) == 1);
assert(isinf(float_value));
assert(sscanf("InF", "%f", &float_value) == 1);
assert(isinf(float_value));
assert(sscanf("+inf", "%f", &float_value) == 1);
assert(isinf(float_value));
assert(sscanf("-inf", "%f", &float_value) == 1);
assert(isinf(float_value));
assert(sscanf("INF", "%f", &float_value) == 1);
assert(isinf(float_value));
assert(sscanf("infinity", "%f", &float_value) == 1);
assert(isinf(float_value));
assert(sscanf("INFINITY", "%f", &float_value) == 1);
assert(isinf(float_value));
assert(sscanf("nan", "%f", &float_value) == 1);
assert(isnan(float_value));
assert(sscanf("NaN", "%f", &float_value) == 1);
assert(isnan(float_value));
assert(sscanf("+nan", "%f", &float_value) == 1);
assert(isnan(float_value));
assert(sscanf("-nan", "%f", &float_value) == 1);
assert(isnan(float_value));
assert(sscanf("0xhello", "%f", &float_value) == 0);
assert(sscanf("0x1hello", "%f", &float_value) == 1);
assert(float_value >= 0x1P0f - 0.01 && float_value <= 0x1P0f + 0.01);
assert(sscanf("ab1.1234", "%f", &float_value) == 0);
assert(sscanf(" 1.123", "%f", &float_value) == 1);
assert(float_value >= 1.123f - 0.01 && float_value <= 1.123f + 0.01);*/
void* ptr;
assert(sscanf("hello", "%p", &ptr) == 0);
#if UINTPTR_MAX == UINT64_MAX
assert(sscanf("0xabcdef12abcdef12", "%p", &ptr) == 1);
assert(ptr == (void*)0xabcdef12abcdef12);
#else
assert(sscanf("0xabcdef12", "%p", &ptr) == 1);
assert(ptr == (void*)0xabcdef12);
#endif
assert(sscanf("a", "%*c") == 0);
char_value[2] = 'q';
assert(sscanf("abcd", "%2c", char_value) == 1);
assert(char_value[2] == 'q');
char_value[2] = 0;
assert(strcmp(char_value, "ab") == 0);
assert(sscanf("cdef", "%2s", char_value) == 1);
assert(strcmp(char_value, "cd") == 0);
assert(sscanf("c def", "%2s", char_value) == 1);
assert(strcmp(char_value, "c") == 0);
assert(sscanf("aacd", "%2[ac]", char_value) == 1);
assert(strcmp(char_value, "aa") == 0);
return 0;
}
+20
View File
@@ -0,0 +1,20 @@
#include <assert.h>
#include <string.h>
#include <stddef.h>
int main() {
char str[] = "This is a sample string";
char *pch;
// The character 's' is at position 4, 7, 11 and 18
pch = strchr(str, 's');
assert(pch - str + 1 == 4);
pch = strchr(pch + 1, 's');
assert(pch - str + 1 == 7);
pch = strchr(pch + 1, 's');
assert(pch - str + 1 == 11);
pch = strchr(pch + 1, 's');
assert(pch - str + 1 == 18);
pch = strchr(pch + 1, 's');
assert(pch == NULL);
return 0;
}
+71
View File
@@ -0,0 +1,71 @@
#include <string.h>
#include <time.h>
#include <assert.h>
#include <locale.h>
#include <stdio.h>
int main() {
// Date representation depends on locale, here only C is tested.
// Maybe consider testing more locales?
if (setlocale (LC_ALL, "C") == NULL) {
fputs("strftime testcase could not set locale, errors may be expected!", stderr);
}
char timebuf[32];
char result[32] = " 8";
struct tm tm;
tm.tm_sec = 0;
tm.tm_min = 17;
tm.tm_hour = 17;
tm.tm_mday = 8;
tm.tm_mon = 2;
tm.tm_year = 121;
tm.tm_wday = 2;
tm.tm_yday = 39;
tm.tm_gmtoff = 3600;
strftime(timebuf, sizeof(timebuf), "%e", &tm);
assert(!strcmp(timebuf, result));
memset(timebuf, 0, sizeof(timebuf));
strftime(timebuf, sizeof(timebuf), "%x", &tm);
assert(!strcmp(timebuf, "03/08/21"));
memset(timebuf, 0, sizeof(timebuf));
strftime(timebuf, sizeof(timebuf), "%X", &tm);
assert(!strcmp(timebuf, "17:17:00"));
memset(timebuf, 0, sizeof(timebuf));
strftime(timebuf, sizeof(timebuf), "%D", &tm);
assert(!strcmp(timebuf, "03/08/21"));
memset(timebuf, 0, sizeof(timebuf));
strftime(timebuf, sizeof(timebuf), "%OB %Ob", &tm);
assert(!strcmp(timebuf, "March Mar"));
memset(timebuf, 0, sizeof(timebuf));
strftime(timebuf, sizeof(timebuf), "%c", &tm);
memset(result, 0, sizeof(result));
strftime(result, sizeof(result), "%a %b %e %H:%M:%S %Y", &tm);
assert(!strcmp(timebuf, result));
memset(timebuf, 0, sizeof(timebuf));
strftime(timebuf, sizeof(timebuf), "%k %p %P%n", &tm);
assert(!strcmp(timebuf, "17 PM pm\n"));
memset(timebuf, 0, sizeof(timebuf));
strftime(timebuf, sizeof(timebuf), "%a %A", &tm);
assert(!strcmp(timebuf, "Tue Tuesday"));
memset(timebuf, 0, sizeof(timebuf));
strftime(timebuf, sizeof(timebuf), "%b %B %h", &tm);
assert(!strcmp(timebuf, "Mar March Mar"));
memset(timebuf, 0, sizeof(timebuf));
assert(!strftime(timebuf, sizeof(timebuf), "%a %A %a %A %b %B %h", &tm));
memset(timebuf, 0, sizeof(timebuf));
strftime(timebuf, sizeof(timebuf), "%z", &tm);
assert(!strcmp(timebuf, "+0100"));
return 0;
}
+11
View File
@@ -0,0 +1,11 @@
#include <string.h>
#include <assert.h>
int main() {
char str[] = "This is a sample string";
char *pch;
pch = strrchr(str, 's');
// The last occurence of 's' is at position 18
assert(pch - str + 1 == 18);
return 0;
}
+83
View File
@@ -0,0 +1,83 @@
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <math.h>
#define FLT_RANGE 0.000001f
#define DBL_RANGE 0.000001
#define LDBL_RANGE 0.000001
#define DO_TEST(str, value, off, func, range) ({ \
char s[] = (str); \
char *pEnd = NULL; \
__typeof(func(s, &pEnd)) result = func(s, &pEnd); \
assert(result >= (value) - (range)); \
assert(result <= (value) + (range)); \
assert(pEnd == (off == -1 ? s + strlen(s) : s + off)); })
#define DO_TEST_SUCCESS_FUNC(str, success_func, off, func) ({ \
char s[] = (str); \
char *pEnd = NULL; \
assert(success_func(func(s, &pEnd))); \
assert(pEnd == (off == -1 ? s + strlen(s) : s + off)); })
int main () {
DO_TEST("0", 0.0f, -1, strtof, FLT_RANGE);
DO_TEST("0.12", 0.12f, -1, strtof, FLT_RANGE);
DO_TEST("12", 12.0f, -1, strtof, FLT_RANGE);
DO_TEST("12.13", 12.13f, -1, strtof, FLT_RANGE);
DO_TEST("10.0e1", 100.0f, -1, strtof, FLT_RANGE);
DO_TEST("10.0e10", 100000000000.0f, -1, strtof, FLT_RANGE);
DO_TEST("100.0e-1", 10.0f, -1, strtof, FLT_RANGE);
DO_TEST("0x0", 0.0f, -1, strtof, FLT_RANGE);
DO_TEST("0x0.12", 0.0703125f, -1, strtof, FLT_RANGE);
DO_TEST("0x12", 18.0f, -1, strtof, FLT_RANGE);
DO_TEST("0x12.13", 18.07421875f, -1, strtof, FLT_RANGE);
DO_TEST("0x10.0p1", 32.0f, -1, strtof, FLT_RANGE);
DO_TEST("0x10.0p10", 16384.0f, -1, strtof, FLT_RANGE);
DO_TEST("0x100.0p-1", 128.0f, -1, strtof, FLT_RANGE);
DO_TEST_SUCCESS_FUNC("NAN", isnan, -1, strtof);
DO_TEST_SUCCESS_FUNC("nan", isnan, -1, strtof);
DO_TEST_SUCCESS_FUNC("INF", isinf, -1, strtof);
DO_TEST_SUCCESS_FUNC("INFINITY", isinf, -1, strtof);
DO_TEST("0", 0.0, -1, strtod, DBL_RANGE);
DO_TEST("0.12", 0.12, -1, strtod, DBL_RANGE);
DO_TEST("12", 12.0, -1, strtod, DBL_RANGE);
DO_TEST("12.13", 12.13, -1, strtod, DBL_RANGE);
DO_TEST("10.0e1", 100.0, -1, strtod, DBL_RANGE);
DO_TEST("10.0e10", 100000000000.0, -1, strtod, DBL_RANGE);
DO_TEST("100.0e-1", 10.0, -1, strtod, DBL_RANGE);
DO_TEST("0x0", 0.0, -1, strtod, DBL_RANGE);
DO_TEST("0x0.12", 0.0703125, -1, strtod, DBL_RANGE);
DO_TEST("0x12", 18.0, -1, strtod, DBL_RANGE);
DO_TEST("0x12.13", 18.07421875, -1, strtod, DBL_RANGE);
DO_TEST("0x10.0p1", 32.0, -1, strtod, DBL_RANGE);
DO_TEST("0x10.0p10", 16384.0, -1, strtod, DBL_RANGE);
DO_TEST("0x100.0p-1", 128.0, -1, strtod, DBL_RANGE);
DO_TEST_SUCCESS_FUNC("NAN", isnan, -1, strtod);
DO_TEST_SUCCESS_FUNC("nan", isnan, -1, strtod);
DO_TEST_SUCCESS_FUNC("INF", isinf, -1, strtod);
DO_TEST_SUCCESS_FUNC("INFINITY", isinf, -1, strtod);
DO_TEST("0", 0.0, -1, strtold, LDBL_RANGE);
DO_TEST("0.12", 0.12, -1, strtold, LDBL_RANGE);
DO_TEST("12", 12.0, -1, strtold, LDBL_RANGE);
DO_TEST("12.13", 12.13, -1, strtold, LDBL_RANGE);
DO_TEST("10.0e1", 100.0, -1, strtold, LDBL_RANGE);
DO_TEST("10.0e10", 100000000000.0, -1, strtold, LDBL_RANGE);
DO_TEST("100.0e-1", 10.0, -1, strtold, LDBL_RANGE);
DO_TEST("0x0", 0.0, -1, strtold, LDBL_RANGE);
DO_TEST("0x0.12", 0.0703125, -1, strtold, LDBL_RANGE);
DO_TEST("0x12", 18.0, -1, strtold, LDBL_RANGE);
DO_TEST("0x12.13", 18.07421875, -1, strtold, LDBL_RANGE);
DO_TEST("0x10.0p1", 32.0, -1, strtold, LDBL_RANGE);
DO_TEST("0x10.0p10", 16384.0, -1, strtold, LDBL_RANGE);
DO_TEST("0x100.0p-1", 128.0, -1, strtold, LDBL_RANGE);
DO_TEST_SUCCESS_FUNC("NAN", isnan, -1, strtold);
DO_TEST_SUCCESS_FUNC("nan", isnan, -1, strtold);
DO_TEST_SUCCESS_FUNC("INF", isinf, -1, strtold);
DO_TEST_SUCCESS_FUNC("INFINITY", isinf, -1, strtold);
return 0;
}
+146
View File
@@ -0,0 +1,146 @@
#include <stdlib.h>
#include <assert.h>
#include <limits.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <wchar.h>
#define DO_TEST(str, value, off, func, base) ({ \
char s[] = (str); \
char *pEnd = NULL; \
errno = 0; \
assert(func(s, &pEnd, base) == (value)); \
assert(errno == 0); \
assert(pEnd == (off == -1 ? s + strlen(s) : s + off)); })
#define DO_ERR_TEST(str, value, err, func, base) ({ \
char s[] = (str); \
char *pEnd = NULL; \
errno = 0; \
assert(func(s, &pEnd, base) == (value)); \
assert(errno == err); \
assert(pEnd == (err == ERANGE ? s + strlen(s) : s)); })
#define DO_TESTL(str, value, off, func, base) ({ \
wchar_t s[] = (str); \
wchar_t *pEnd = NULL; \
errno = 0; \
assert(func(s, &pEnd, base) == (value)); \
assert(errno == 0); \
assert(pEnd == (off == -1 ? s + wcslen(s) : s + off)); })
#define DO_ERR_TESTL(str, value, err, func, base) ({ \
wchar_t s[] = (str); \
wchar_t *pEnd = NULL; \
errno = 0; \
assert(func(s, &pEnd, base) == (value)); \
assert(errno == err); \
assert(pEnd == (err == ERANGE ? s + wcslen(s) : s)); })
int main () {
// A few generic checks.
DO_TEST("0", 0, -1, strtol, 0);
DO_TEST("0", 0, -1, strtol, 10);
DO_TEST("2001", 2001, -1, strtol, 10);
DO_TEST("+2001", 2001, -1, strtol, 10);
DO_TEST("60c0c0", 0x60c0c0, -1, strtol, 16);
DO_TEST("-1101110100110100100000", -3624224, -1, strtol, 2);
DO_TEST("0x6fffff", 0x6fffff, -1, strtol, 0);
DO_TEST("0666", 0666, -1, strtol, 0);
#ifndef USE_HOST_LIBC
DO_TEST("1100", 0b1100, -1, strtol, 2);
DO_TEST("0b1100", 0b1100, -1, strtol, 0);
DO_TEST("0B1100", 0b1100, -1, strtol, 0);
DO_TEST("0b1zzz", 1, 3, strtol, 0);
#endif
DO_TEST("0xzzz", 0, 1, strtol, 0);
DO_TEST("0yzzz", 0, 1, strtol, 0);
DO_TEST("00xzz", 0, 2, strtol, 0);
DO_ERR_TEST("", 0, 0, strtol, 10);
DO_ERR_TEST("asd", 0, 0, strtol, 10);
DO_ERR_TEST("999999999999999999999999999", LONG_MAX, ERANGE, strtol, 10);
DO_ERR_TEST("-999999999999999999999999999", LONG_MIN, ERANGE, strtol, 10);
// strtol
#if defined(__i386__) || defined(__m68k__)
DO_TEST("-2147483648", LONG_MIN, -1, strtol, 10);
DO_TEST("2147483647", LONG_MAX, -1, strtol, 10);
DO_ERR_TEST("-2147483649", LONG_MIN, ERANGE, strtol, 10);
DO_ERR_TEST("2147483648", LONG_MAX, ERANGE, strtol, 10);
#else
DO_TEST("-9223372036854775808", LONG_MIN, -1, strtol, 10);
DO_TEST("9223372036854775807", LONG_MAX, -1, strtol, 10);
DO_ERR_TEST("9223372036854775808", LONG_MAX, ERANGE, strtol, 10);
DO_ERR_TEST("-9223372036854775809", LONG_MIN, ERANGE, strtol, 10);
#endif
// wcstol
#if defined(__i386__) || defined(__m68k__)
DO_TESTL(L"-2147483648", LONG_MIN, -1, wcstol, 10);
DO_TESTL(L"2147483647", LONG_MAX, -1, wcstol, 10);
DO_ERR_TESTL(L"2147483648", LONG_MAX, ERANGE, wcstol, 10);
DO_ERR_TESTL(L"-2147483649", LONG_MIN, ERANGE, wcstol, 10);
#else
DO_TESTL(L"-9223372036854775808", LONG_MIN, -1, wcstol, 10);
DO_TESTL(L"9223372036854775807", LONG_MAX, -1, wcstol, 10);
DO_ERR_TESTL(L"9223372036854775808", LONG_MAX, ERANGE, wcstol, 10);
DO_ERR_TESTL(L"-9223372036854775809", LONG_MIN, ERANGE, wcstol, 10);
#endif
// strtoll
DO_TEST("-9223372036854775808", LLONG_MIN, -1, strtoll, 10);
DO_TEST("9223372036854775807", LLONG_MAX, -1, strtoll, 10);
DO_ERR_TEST("9223372036854775808", LLONG_MAX, ERANGE, strtoll, 10);
DO_ERR_TEST("-9223372036854775809", LLONG_MIN, ERANGE, strtoll, 10);
// wcstoll
DO_TESTL(L"-9223372036854775808", LLONG_MIN, -1, wcstoll, 10);
DO_TESTL(L"9223372036854775807", LLONG_MAX, -1, wcstoll, 10);
DO_ERR_TESTL(L"9223372036854775808", LLONG_MAX, ERANGE, wcstoll, 10);
DO_ERR_TESTL(L"-9223372036854775809", LLONG_MIN, ERANGE, wcstoll, 10);
// strtoul
#if defined(__i386__) || defined(__m68k__)
DO_TEST("-1", -(1UL), -1, strtoul, 10);
DO_TEST("2147483647", LONG_MAX, -1, strtoul, 10);
DO_TEST("4294967295", ULONG_MAX, -1, strtoul, 10);
DO_TEST("-4294967295", 1UL, -1, strtoul, 10);
DO_ERR_TEST("4294967296", ULONG_MAX, ERANGE, strtoul, 10);
#else
DO_TEST("-1", -(1UL), -1, strtoul, 10);
DO_TEST("9223372036854775807", LONG_MAX, -1, strtoul, 10);
DO_TEST("18446744073709551615", ULONG_MAX, -1, strtoul, 10);
DO_TEST("-18446744073709551615", 1UL, -1, strtoul, 10);
DO_ERR_TEST("18446744073709551616", ULONG_MAX, ERANGE, strtoul, 10);
#endif
// wcstoul
#if defined(__i386__) || defined(__m68k__)
DO_TESTL(L"-1", -(1UL), -1, wcstoul, 10);
DO_TESTL(L"2147483647", LONG_MAX, -1, wcstoul, 10);
DO_TESTL(L"4294967295", ULONG_MAX, -1, wcstoul, 10);
DO_TESTL(L"-4294967295", 1UL, -1, wcstoul, 10);
DO_ERR_TESTL(L"4294967296", ULONG_MAX, ERANGE, wcstoul, 10);
#else
DO_TESTL(L"-1", -(1UL), -1, wcstoul, 10);
DO_TESTL(L"9223372036854775807", LONG_MAX, -1, wcstoul, 10);
DO_TESTL(L"18446744073709551615", ULONG_MAX, -1, wcstoul, 10);
DO_TESTL(L"-18446744073709551615", 1UL, -1, wcstoul, 10);
DO_ERR_TESTL(L"18446744073709551616", ULONG_MAX, ERANGE, wcstoul, 10);
#endif
// strtoull
DO_TEST("-1", -(1ULL), -1, strtoull, 10);
DO_TEST("9223372036854775807", LLONG_MAX, -1, strtoull, 10);
DO_TEST("18446744073709551615", ULLONG_MAX, -1, strtoull, 10);
DO_TEST("-18446744073709551615", 1ULL, -1, strtoull, 10);
DO_ERR_TEST("18446744073709551616", ULLONG_MAX, ERANGE, strtoull, 10);
// wcstoull
DO_TESTL(L"-1", -(1ULL), -1, wcstoull, 10);
DO_TESTL(L"9223372036854775807", LLONG_MAX, -1, wcstoull, 10);
DO_TESTL(L"18446744073709551615", ULLONG_MAX, -1, wcstoull, 10);
DO_TESTL(L"-18446744073709551615", 1ULL, -1, wcstoull, 10);
DO_ERR_TESTL(L"18446744073709551616", ULLONG_MAX, ERANGE, wcstoull, 10);
return 0;
}
@@ -0,0 +1,18 @@
#include <string.h>
#include <stdlib.h>
#include <assert.h>
int main() {
int res;
res = strverscmp("jan1", "jan10");
assert(res < 0);
res = strverscmp("jan11", "jan10");
assert(res > 0);
res = strverscmp("jan1", "jan1");
assert(res == 0);
return 0;
}
+16
View File
@@ -0,0 +1,16 @@
#include <assert.h>
#include <locale.h>
#include <string.h>
int main() {
setlocale(LC_ALL, "C");
const char *buf = "cbtteststring";
char dest[14];
size_t ret = strxfrm(dest, buf, strlen(buf) + 1);
assert(ret == 13);
int cmp = strncmp(dest, buf, 13);
assert(!cmp);
return 0;
}
+45
View File
@@ -0,0 +1,45 @@
#include <time.h>
#include <stdio.h>
#include <assert.h>
int main() {
struct tm soon = {};
soon.tm_sec = 0;
soon.tm_min = 0;
soon.tm_hour = 0;
soon.tm_mday = 1;
soon.tm_mon = 0;
soon.tm_year = 70;
time_t result;
time_t expected_result = 0;
// This should be epoch.
result = timegm(&soon);
printf("epoch: %ld\n", result);
assert(result == expected_result);
soon.tm_sec = 12;
soon.tm_min = 8;
soon.tm_hour = 16;
soon.tm_mday = 17;
soon.tm_mon = 4;
soon.tm_year = 122;
expected_result = 1652803692;
result = timegm(&soon);
// On my host, this returned 1652803692, verify this.
printf("epoch: %ld\n", result);
assert(result == expected_result);
soon.tm_sec = 45;
soon.tm_min = 42;
soon.tm_hour = 17;
soon.tm_mday = 16;
soon.tm_mon = 8;
soon.tm_year = 69;
expected_result = -9181035;
result = timegm(&soon);
// On my host, this returned -9181035, verify this.
printf("epoch: %ld\n", result);
assert(result == expected_result);
return 0;
}
+27
View File
@@ -0,0 +1,27 @@
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
extern int daylight;
extern long timezone;
extern char *tzname[2];
int main() {
tzset();
printf("%s %s %ld %d\n", tzname[0], tzname[1], timezone, daylight);
time_t sometime_in_summer_in_the_north = 1752019200;
struct tm *local = localtime(&sometime_in_summer_in_the_north);
// Print the current timezone offset from UTC in seconds, considering DST
if (local) {
long offset = local->tm_gmtoff;
int hours = offset / 3600;
int minutes = (offset % 3600) / 60;
printf("UTC offset: %0d:%02d\n", hours, abs(minutes));
} else {
printf("localtime returned NULL\n");
}
return 0;
}
+57
View File
@@ -0,0 +1,57 @@
import subprocess
import sys
import os
from pyexpect import expect
exe_wrapper = os.environ.get("MESON_EXE_WRAPPER")
wrapper = exe_wrapper.split(" ") if exe_wrapper else []
def check_tz(tz, expected):
environ = os.environ.copy()
environ["TZ"] = tz
output = subprocess.check_output(
wrapper + sys.argv[1:],
stderr=subprocess.STDOUT,
env=environ,
)
expect(expected).to_equal(output)
if len(sys.argv) < 2:
print("Usage: python3 tz.py <path to test program>", file=sys.stderr)
sys.exit(1)
check_tz("UTC0", b"UTC UTC 0 0\nUTC offset: 0:00\n")
check_tz("GMT0", b"GMT GMT 0 0\nUTC offset: 0:00\n")
check_tz(":UTC0", b"UTC UTC 0 0\nUTC offset: 0:00\n")
check_tz("EST+5", b"EST EST 18000 0\nUTC offset: -5:00\n")
check_tz("EET-2", b"EET EET -7200 0\nUTC offset: 2:00\n")
check_tz("<+03>-03", b"+03 +03 -10800 0\nUTC offset: 3:00\n")
check_tz("NPT-05:45", b"NPT NPT -20700 0\nUTC offset: 5:45\n")
check_tz("NST+03:30NDT", b"NST NDT 12600 1\nUTC offset: -2:30\n")
check_tz("NZST-12NZDT-13,M9.5.0,M4.1.0/3", b"NZST NZDT -43200 1\nUTC offset: 12:00\n")
check_tz("<PST-8>+8<PDT-7>+7", b"PST-8 PDT-7 28800 1\nUTC offset: -7:00\n")
check_tz("<PST-8>+8<PDT-7>+7,M3.2.0,M11.1.0", b"PST-8 PDT-7 28800 1\nUTC offset: -7:00\n")
# These depend on tzdata, which may or may not exist.
# Useful to check every now and then, but these also present subtle differences
# between the host libc and mlibc, so we can't expect these to always hold up.
# E.g. glibc will set `tzname` from the TZ environment variable even if it
# cannot find the tzinfo file, however mlibc will use the name of the timezone
# as read from the tzinfo file or the timezone that it defaults to (UTC).
# Would be b"Universal 0 0\n" on glibc.
# check_tz("", b"UTC UTC 0 0\n")
# Would be b"UTC 0 0\n" on glibc.
# check_tz("UTC", b"UTC UTC 0 0\n")
# check_tz(":UTC", b"UTC UTC 0 0\n")
# Would be b"Universal 0 0\n" on glibc.
# check_tz("Universal", b"UTC UTC 0 0\n")
# check_tz(":Universal", b"UTC UTC 0 0\n")
# Would be b"ATimeZoneThatShouldHopefullyNeverBeInTzdata 0 0\n" on glibc.
# check_tz("ATimeZoneThatShouldHopefullyNeverBeInTzdata", b"UTC UTC 0 0\n")
# check_tz(":ATimeZoneThatShouldHopefullyNeverBeInTzdata", b"UTC UTC 0 0\n")
+76
View File
@@ -0,0 +1,76 @@
#include <stdio.h>
#include <assert.h>
#ifdef USE_HOST_LIBC
#define TEST_FILE "ungetc-host-libc.tmp"
#else
#define TEST_FILE "ungetc.tmp"
#endif
void test(int buffering) {
FILE *f = fopen(TEST_FILE, "w");
for(int c = '0'; c <= '9'; c++) {
fputc(c, f);
}
fclose(f);
f = fopen(TEST_FILE, "r");
if (!buffering) {
setbuf(f, NULL);
}
assert(ungetc('x', f) == 'x');
assert(fgetc(f) == 'x');
// Test pushing back the same character
for (int c = '0'; c <= '9'; c++) {
assert(fgetc(f) == c);
assert(ungetc(c, f) == c);
assert(fgetc(f) == c);
}
assert(fgetc(f) == EOF);
assert(ungetc(EOF, f) == EOF);
// Even though the spec does not guarantee it, we should be able to
// ungetc more than one character.
assert(ungetc('x', f) == 'x');
assert(ungetc('y', f) == 'y');
assert(fgetc(f) == 'y');
assert(fgetc(f) == 'x');
// Seeking should discard the effects of ungetc.
assert(ungetc('x', f) == 'x');
rewind(f);
// Test pushing back a different character
for (int c = '0'; c <= '9'; c++) {
assert(fgetc(f) == c);
assert(ungetc(c - '0' + 'a', f) == c - '0' + 'a');
assert(fgetc(f) == c - '0' + 'a');
}
#ifndef USE_HOST_LIBC
// Too many ungetcs should fail.
int eof = 0;
for (int i = 0; i < 100; i++) {
if (ungetc('x', f) == EOF) {
eof = 1;
break;
}
}
assert(eof);
#endif
fclose(f);
// TODO: Test with other operations, like fread.
}
int main() {
fprintf(stderr, "with buffering...\n");
test(1);
fprintf(stderr, "without buffering...\n");
test(0);
return 0;
}
+78
View File
@@ -0,0 +1,78 @@
#include <assert.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include <locale.h>
#if UINTPTR_MAX == UINT64_MAX
#define WCHAR_SPEC ""
#else
#define WCHAR_SPEC "l"
#endif
#define EXPECT(func) ({ \
if(res != expected_ret) { \
printf(#func " decoded %d bytes (expected %d bytes), at %s:%d\n", \
res, expected_ret, __FILE__, line); \
fflush(stdout); \
abort(); \
} \
if(wc != expected) { \
printf(#func " output cp %" WCHAR_SPEC "x (expected cp %" WCHAR_SPEC "x), at %s:%d\n", wc, \
expected, __FILE__, line); \
fflush(stdout); \
abort(); \
} \
})
void verify_decode(const char *input, wchar_t expected, int line) {
wchar_t wc;
int bytes = *input ? strlen(input) : 1;
int expected_ret = *input ? strlen(input) : 0;
// Check mbrtowc().
mbstate_t state;
memset(&state, 0, sizeof(state));
assert(mbrtowc(NULL, NULL, -1, &state) == 0);
int res = mbrtowc(&wc, input, bytes, &state);
EXPECT("mbrtowc");
res = mbrtowc(NULL, input, bytes, &state);
EXPECT("mbrtowc (pwc == NULL)");
// Check mbtowc().
assert(mbtowc(NULL, NULL, -1) == 0);
res = mbtowc(&wc, input, bytes);
EXPECT("mbtowc");
res = mbtowc(NULL, input, bytes);
EXPECT("mbtowc (pwc == NULL)");
}
int main() {
setlocale(LC_ALL, "C.UTF-8");
#define verify_decode(in, out) verify_decode(in, out, __LINE__)
verify_decode("\x24", 0x24);
verify_decode("\xC2\xA2", 0xA2);
verify_decode("\xE0\xA4\xB9", 0x939);
verify_decode("\xE2\x82\xAC", 0x20AC);
verify_decode("\xED\x95\x9C", 0xD55C);
verify_decode("\xF0\x90\x8D\x88", 0x10348);
verify_decode("", L'\0');
// Check wcrtomb.
char representation[MB_CUR_MAX];
representation[0] = '\0';
mbstate_t state;
memset(&state, 0, sizeof(state));
assert(wcrtomb(representation, L'1', &state) == 1);
assert(wcrtomb(representation, L'ß', &state) == 2);
assert(!strncmp(representation, "\xC3\x9F", 2));
assert(wcrtomb(representation, L'', &state) == 3);
assert(!strncmp(representation, "\xE0\xA0\x91", 3));
assert(wcrtomb(representation, L'𒂲', &state) == 4);
assert(!strncmp(representation, "\xF0\x92\x82\xB2", 4));
return 0;
}
+13
View File
@@ -0,0 +1,13 @@
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <wchar.h>
int main() {
wchar_t *wide_string = L"test string\n";
wchar_t *dup_string = wcsdup(wide_string);
assert(!memcmp(wide_string, dup_string, (wcslen(wide_string) + 1) * sizeof(wchar_t)));
free(dup_string);
return 0;
}
@@ -0,0 +1,13 @@
#include <assert.h>
#include <wchar.h>
int main() {
assert(!wcsncasecmp(L"foo", L"foo", 3));
assert(!wcsncasecmp(L"foo", L"FOO", 3));
assert(!wcsncasecmp(L"fooa", L"FOOB", 3));
assert(wcsncasecmp(L"foo", L"bar", 3));
assert(!wcsncasecmp(L"fooa", L"FOOA", 4));
assert(!wcsncasecmp(L"123abc", L"123AbC", 6));
return 0;
}
+12
View File
@@ -0,0 +1,12 @@
#include <stdlib.h>
#include <wchar.h>
#include <assert.h>
#include <string.h>
int main() {
const wchar_t str[] = L"wcsrtombs";
const wchar_t *p = str;
int ret = wcsrtombs(NULL, &p, 343245234, NULL);
assert(ret == 9);
return 0;
}
+19
View File
@@ -0,0 +1,19 @@
#include <assert.h>
#include <wchar.h>
#include <stdlib.h>
int main(void){
wchar_t *ws1 = calloc(10, sizeof(wchar_t));
wchar_t *ws2 = calloc(10, sizeof(wchar_t));
mbstowcs(ws1, "Test 1", 10);
mbstowcs(ws2, "Tester 2", 10);
assert(wmemcmp(ws1, ws2, 10) < 0);
assert(wmemcmp(ws2, ws1, 10) > 0);
assert(wmemcmp(ws2, ws2, 10) == 0);
free(ws1);
free(ws2);
return 0;
}
+10
View File
@@ -0,0 +1,10 @@
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
int main(void) {
double samples[3];
assert(getloadavg(samples, 3) != 0);
printf("%f %f %f\n", samples[0], samples[1], samples[2]);
return 0;
}
+21
View File
@@ -0,0 +1,21 @@
#include <assert.h>
#include <arpa/nameser.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
int main() {
uint8_t *buf = malloc(256);
uint16_t original16 = 4891;
uint32_t original32 = 4861984;
memset(buf, 0x0, sizeof(*buf));
ns_put16(original16, buf);
uint16_t result16 = ns_get16(buf);
assert(result16 == original16);
memset(buf, 0x0, sizeof(*buf));
ns_put32(original32, buf);
uint32_t result32 = ns_get32(buf);
assert(result32 == original32);
free(buf);
return 0;
}
@@ -0,0 +1,7 @@
#include <stdlib.h>
int main() {
void *ret = reallocarray(NULL, 69, 0xCB7);
free(ret);
return !ret;
}
+11
View File
@@ -0,0 +1,11 @@
#include <assert.h>
#include <stdio.h>
#include <unistd.h>
int main() {
void *ret = sbrk(0);
assert(ret != (void *) -1);
assert(ret);
return 0;
}
+56
View File
@@ -0,0 +1,56 @@
#include <assert.h>
#include <string.h>
int main() {
char buf[256];
/* Test copy to 0-sized buffer . */
memset(buf, 0, sizeof(buf));
assert(strlcpy(buf, "xyz", 0) == 3);
assert(strcmp(buf, "") == 0);
/* Test normal copy. */
memset(buf, 0, sizeof(buf));
assert(strlcpy(buf, "xyz", sizeof(buf)) == 3);
assert(strcmp(buf, "xyz") == 0);
/* Test truncated copy. */
memset(buf, 0, sizeof(buf));
assert(strlcpy(buf, "abcdefabcdef", 10) == 12);
assert(strcmp(buf, "abcdefabc") == 0);
/* Test concat to 0-sized buffer. */
memset(buf, 0, sizeof(buf));
assert(strlcat(buf, "abc", 0) == 3);
assert(strcmp(buf, "") == 0);
/* Test concat to full buffer. */
memset(buf, 0, sizeof(buf));
assert(strlcat(buf, "abcde", 6) == 5);
assert(strcmp(buf, "abcde") == 0);
assert(strlcat(buf, "xyz", 5) == 8);
assert(strcmp(buf, "abcde") == 0);
/* Test normal concat. */
memset(buf, 0, sizeof(buf));
assert(strlcat(buf, "abc", sizeof(buf)) == 3);
assert(strcmp(buf, "abc") == 0);
assert(strlcat(buf, "xyz", sizeof(buf)) == 6);
assert(strcmp(buf, "abcxyz") == 0);
/* Test truncated concat. */
memset(buf, 0, sizeof(buf));
assert(strlcat(buf, "abcabc", 10) == 6);
assert(strcmp(buf, "abcabc") == 0);
assert(strlcat(buf, "xyzxyz", 10) == 12);
assert(strcmp(buf, "abcabcxyz") == 0);
/* Test truncated concat w/ truncated dst. */
memset(buf, 0, sizeof(buf));
assert(strlcat(buf, "abcabc", 10) == 6);
assert(strcmp(buf, "abcabc") == 0);
assert(strlcat(buf, "xyz", 4) == 7);
assert(strcmp(buf, "abcabc") == 0);
return 0;
}
+8
View File
@@ -0,0 +1,8 @@
#include <errno.h>
#include <error.h>
int main() {
error(0, EINVAL, "test: %s", "error");
return 0;
}
+11
View File
@@ -0,0 +1,11 @@
import subprocess
import sys
import os
from pyexpect import expect
wrapper = os.getenv("MESON_EXE_WRAPPER")
wrapper = [x for x in (wrapper,) if x]
output = subprocess.check_output(wrapper + [sys.argv[1]], stderr=subprocess.STDOUT)
expect(bytes(sys.argv[1], 'utf-8') + b': test: error: Invalid argument (EINVAL)\n').to_equal(output)
@@ -0,0 +1,8 @@
#include <errno.h>
#include <error.h>
int main() {
error_at_line(0, EINVAL, "error_at_line", 5, "test: %s", "error");
return 0;
}
@@ -0,0 +1,11 @@
import subprocess
import sys
import os
from pyexpect import expect
wrapper = os.getenv("MESON_EXE_WRAPPER")
wrapper = [x for x in (wrapper,) if x]
output = subprocess.check_output(wrapper + [sys.argv[1]], stderr=subprocess.STDOUT)
expect(bytes(sys.argv[1], 'utf-8') + b':error_at_line:5: test: error: Invalid argument (EINVAL)\n').to_equal(output)
@@ -0,0 +1,8 @@
#include <errno.h>
#include <error.h>
int main() {
error(1, EINVAL, "test error #1");
return 0;
}
@@ -0,0 +1,13 @@
#include <assert.h>
#include <errno.h>
#include <error.h>
int main() {
assert(error_message_count == 0);
error(0, EINVAL, "test error #1");
assert(error_message_count == 1);
error_at_line(0, EINVAL, __FILE__, __LINE__, "test error #2");
assert(error_message_count == 2);
return 0;
}
@@ -0,0 +1,15 @@
#include <assert.h>
#include <errno.h>
#include <error.h>
int main() {
assert(error_one_per_line == 0);
assert(error_message_count == 0);
error_one_per_line = 1;
error_at_line(0, EINVAL, __FILE__, 0, "test error #1");
assert(error_message_count == 1);
error_at_line(0, EINVAL, __FILE__, 0, "test error #2");
assert(error_message_count == 1);
return 0;
}
@@ -0,0 +1,21 @@
#include <assert.h>
#include <stdbool.h>
#include <stdio.h>
#include <errno.h>
#include <error.h>
bool ran = false;
void test_progname(void) {
ran = true;
fprintf(stderr, "progname test");
}
int main() {
assert(error_print_progname == NULL);
error_print_progname = &test_progname;
error(0, EINVAL, "test error #1");
assert(ran == true);
return 0;
}
@@ -0,0 +1,36 @@
#include <assert.h>
#include <stdint.h>
#include <string.h>
#include <limits.h>
int main(void){
// ffsl
assert(ffsl(0x8000) == 16);
assert(ffsl(0) == 0);
#if UINTPTR_MAX == UINT64_MAX
assert(ffsl(LLONG_MAX - 1) == 2);
assert(ffsl(LLONG_MAX) == 1);
#endif
assert(ffsl(LONG_MIN) == (long)(sizeof(long) * CHAR_BIT));
assert(ffsl(LONG_MIN + 1) == 1);
for (int i = 1; i < 0x1000; i++) {
assert(ffsl(i) - 1 == __builtin_ctz(i));
}
// ffsll
assert(ffsll(0x8000) == 16);
assert(ffsll(0) == 0);
#if UINTPTR_MAX == UINT64_MAX
assert(ffsll(LLONG_MAX - 1) == 2);
assert(ffsll(LLONG_MAX) == 1);
#endif
assert(ffsll(LLONG_MIN) == (long long)(sizeof(long long) * CHAR_BIT));
assert(ffsll(LLONG_MIN + 1) == 1);
for (int i = 1; i < 0x1000; i++) {
assert(ffsll(i) - 1 == __builtin_ctz(i));
}
return 0;
}
@@ -0,0 +1,55 @@
#include <assert.h>
#include <errno.h>
#include <grp.h>
#include <pwd.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main() {
int ngroups = 100;
struct passwd *pw;
struct group *gr;
gid_t *groups;
bool gid_checked = false;
int e = 0;
groups = malloc(sizeof(*groups) * ngroups);
if(groups == NULL) {
perror("malloc");
exit(EXIT_FAILURE);
}
/* Fetch passwd structure */
pw = getpwuid(geteuid());
if(pw == NULL) {
perror("getpwnam");
exit(EXIT_FAILURE);
}
/* Retrieve group list */
e = getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups);
assert(e > 0);
if(e == -1) {
fprintf(stderr, "getgrouplist() returned -1 (%s); ngroups = %d\n", strerror(errno), ngroups);
exit(EXIT_FAILURE);
}
/* Display list of retrieved groups, along with group names */
fprintf(stderr, "ngroups = %d\n", ngroups);
for(int j = 0; j < ngroups; j++) {
if(groups[j] == pw->pw_gid)
gid_checked = true;
printf("%d", groups[j]);
gr = getgrgid(groups[j]);
if(gr != NULL)
printf(" (%s)", gr->gr_name);
printf("\n");
}
assert(gid_checked);
exit(EXIT_SUCCESS);
}
+884
View File
@@ -0,0 +1,884 @@
#include <assert.h>
#include <getopt.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define COUNT_OF(x) ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x])))))
#define dump(x) fprintf(stderr, "getopt c '%c' (%d), optind %d ('%s'), optarg '%s', optopt '%c' (%d)\n", \
(x), (x), optind, (size_t)optind >= COUNT_OF(test_argv) ? "out of range" : test_argv[optind], optarg, optopt, optopt);
#define dumpargv(argv) do { \
fprintf(stderr, "args(%zu) {\n", COUNT_OF(argv)); \
for (size_t i = 0; i < COUNT_OF(argv); i++) { \
fprintf(stderr, "\targv[%zu] = '%s'\n", i, argv[i]); \
} \
fprintf(stderr, "}\n"); \
} while (0)
void test1() {
const char *shortopts = "b:cdef";
const struct option longopts[] = {
{"foo", required_argument, NULL, 'f'},
{NULL, no_argument, NULL, 0}
};
int test_argc = 7;
char *test_argv[] = {
"dummy",
"--foo",
"abc",
"-b",
"abc",
"abc",
"abc"
};
optind = 0;
int c = getopt_long(test_argc, test_argv, shortopts, longopts, NULL);
dump(c)
assert(c == 'f');
c = getopt_long(test_argc, test_argv, shortopts, longopts, NULL);
dump(c)
assert(optarg && !strcmp(optarg, "abc"));
assert(c == 'b');
c = getopt_long(test_argc, test_argv, shortopts, longopts, NULL);
dump(c);
assert(c == -1);
assert(optarg == NULL);
// we have 2 non-option arguments
assert((optind + 2) == test_argc);
}
void test2() {
const struct option longopts[] = {
{"foo", required_argument, NULL, 'f'},
{NULL, no_argument, NULL, 0}
};
char *test_argv[] = {
"dummy",
"-c",
};
fputs("Situation: we pass a non-existant short option in argv\n", stderr);
optind = 0;
opterr = 0;
int c = getopt_long(COUNT_OF(test_argv), test_argv, "ab:", longopts, NULL);
// Expected result: return '?', optopt is set to the offender
assert(c == '?');
assert(optopt == 'c');
fputs("Situation: we pass a non-existant short option in argv, while passing a leading colon in optstring\n", stderr);
optind = 0;
c = getopt_long(COUNT_OF(test_argv), test_argv, ":ab:", longopts, NULL);
// Expected result: return '?', optopt is set to the offender
assert(c == '?');
assert(optopt == 'c');
fputs("Situation: we omit the required arg to a short option\n", stderr);
optind = 0;
c = getopt_long(COUNT_OF(test_argv), test_argv, "ab:c:", longopts, NULL);
// Expected result: return '?', optopt is set to the offender
assert(c == '?');
assert(optopt == 'c');
fputs("Situation: we omit the required arg to a short option, while passing a leading colon in optstring\n", stderr);
optind = 0;
c = getopt_long(COUNT_OF(test_argv), test_argv, ":ab:c:", longopts, NULL);
// Expected result: return ':', optopt is set to the offender
assert(c == ':');
assert(optopt == 'c');
}
void test3() {
const struct option longopts[] = {
{"foo", required_argument, NULL, 'f'},
{NULL, no_argument, NULL, 0}
};
char *test_argv[] = {
"dummy",
"-cmanagarm",
};
fputs("Situation: we pass a concatenated argument to a short option\n", stderr);
optind = 0;
int c = getopt_long(COUNT_OF(test_argv), test_argv, "ab:c:", longopts, NULL);
dump(c);
// Expected result:
assert(c == 'c');
assert(!strcmp(optarg, "managarm"));
}
void test4() {
const struct option longopts[] = {
{"foo", required_argument, NULL, 'f'},
{NULL, no_argument, NULL, 0}
};
char *test_argv[] = {
"dummy",
"-acmanagarm",
};
fputs("Situation: we pass concatenated short options to getopt\n", stderr);
optind = 0;
int c = getopt_long(COUNT_OF(test_argv), test_argv, "ab:c:", longopts, NULL);
assert(c == 'a');
c = getopt_long(COUNT_OF(test_argv), test_argv, "ab:c:", longopts, NULL);
// Expected result:
assert(c == 'c');
assert(!strcmp(optarg, "managarm"));
}
void test5() {
const struct option longopts[] = {
{"foo", required_argument, NULL, 'f'},
{NULL, no_argument, NULL, 0}
};
char *test_argv[] = {
"su",
"-",
"managarm",
0
};
int test_argc = 3;
fputs("Situation: testing `su - managarm`\n", stderr);
optind = 0;
int c = getopt_long(test_argc, test_argv, "ab:", longopts, NULL);
dump(c);
assert(c == -1);
if (optind < test_argc && !strcmp(test_argv[optind], "-")) {
++optind;
}
assert(optind < test_argc);
assert(!strcmp(test_argv[optind++], "managarm"));
assert(optind == test_argc);
}
void test6() {
char *test_argv[] = {
"telescope",
"gemini://electrode.codes",
"-S",
0
};
int test_argc = 3;
optind = 0;
const struct option longopts[] = {
{"colors", no_argument, NULL, 'C'},
{"colours", no_argument, NULL, 'C'},
{"help", no_argument, NULL, 'h'},
{"safe", no_argument, NULL, 'S'},
{"version", no_argument, NULL, 'v'},
{NULL, 0, NULL, 0},
};
int c = getopt_long(test_argc, test_argv, "Cc:hnST:v", longopts, NULL);
dump(c);
dumpargv(test_argv);
assert(c == 'S');
c = getopt_long(test_argc, test_argv, "Cc:hnST:v", longopts, NULL);
dump(c);
dumpargv(test_argv);
assert(optind == 2);
assert(!optarg);
}
void test7() {
int c;
static const struct option options[] = {
{ "debug", no_argument, NULL, 'd' },
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, 'V' },
{}
};
const char *command;
char *test_argv[] = {
"udevadm",
"hwdb",
"--update",
0
};
int test_argc = 3;
setenv("POSIXLY_CORRECT", "1", 1);
optind = 0;
while ((c = getopt_long(test_argc, test_argv, "+dhV", options, NULL)) >= 0) {
switch (c) {
case 'd':
break;
case 'h':
break;
case 'V':
break;
default:
break;
}
}
dump(c);
command = test_argv[optind];
assert(command);
assert(!strcmp(command, "hwdb"));
unsetenv("POSIXLY_CORRECT");
}
void test8() {
const char *shortopts = "b:cde";
int foo = false;
int bar = false;
const struct option longopts[] = {
{"foo", required_argument, &foo, 'x'},
{"bar", required_argument, &bar, 'y'},
{NULL, no_argument, NULL, 0}
};
int test_argc = 6;
char *test_argv[] = {
"dummy",
"-foo",
"abc",
"-bar=def",
"ghi",
"jkl"
};
#ifdef __GLIBC__
optind = 0;
#else
optreset = 1;
#endif
optopt = 0;
int c = getopt_long_only(test_argc, test_argv, shortopts, longopts, NULL);
dump(c);
assert(foo && !c);
assert(optind == 3);
c = getopt_long_only(test_argc, test_argv, shortopts, longopts, NULL);
dump(c);
assert(bar && !c);
assert(optind == 4);
}
void test9() {
char *test_argv[] = {
"foo",
};
struct option opts[] = { {0} };
optind = 0;
int c = getopt_long(1, test_argv, "abc", opts, NULL);
dump(c);
assert(c == -1);
}
void test10() {
char *test_argv[] = {
"foo",
"nonoption",
"-a",
"nonoption2",
"nonoption3",
"-b",
"-c",
};
struct option opts[] = { {0} };
optind = 2;
dump(0);
int c = getopt_long(COUNT_OF(test_argv), test_argv, "abc", opts, NULL);
dump(c);
dumpargv(test_argv);
assert(c == 'a');
c = getopt_long(COUNT_OF(test_argv), test_argv, "abc", opts, NULL);
dump(c);
dumpargv(test_argv);
assert(c == 'b');
c = getopt_long(COUNT_OF(test_argv), test_argv, "abc", opts, NULL);
dump(c);
dumpargv(test_argv);
assert(c == 'c');
c = getopt_long(COUNT_OF(test_argv), test_argv, "abc", opts, NULL);
dump(c);
dumpargv(test_argv);
assert(c == -1);
assert(!strcmp(test_argv[0], "foo"));
assert(!strcmp(test_argv[1], "nonoption"));
assert(!strcmp(test_argv[2], "-a"));
assert(!strcmp(test_argv[3], "-b"));
assert(!strcmp(test_argv[4], "-c"));
assert(!strcmp(test_argv[5], "nonoption2"));
assert(!strcmp(test_argv[6], "nonoption3"));
}
void test11() {
const struct option longopts[] = {
{"op", optional_argument, NULL, 'o'},
{NULL, 0, NULL, 0}
};
char *test_argv[] = {
"dummy",
"--op",
"--op=arg",
"non-option",
"--op"
};
fputs("Situation: optional argument to long option\n", stderr);
optind = 0;
int c = getopt_long(COUNT_OF(test_argv), test_argv, "", longopts, NULL);
assert(c == 'o');
assert(optarg == NULL);
c = getopt_long(COUNT_OF(test_argv), test_argv, "", longopts, NULL);
assert(c == 'o');
assert(!strcmp(optarg, "arg"));
c = getopt_long(COUNT_OF(test_argv), test_argv, "", longopts, NULL);
assert(c == 'o');
assert(optarg == NULL);
}
void test12() {
char *test_argv[] = {
"dummy",
"-a",
"-b",
"arg",
"-carg",
"arg",
};
fputs("Situation: optional argument to short option\n", stderr);
optind = 0;
int c = getopt_long(COUNT_OF(test_argv), test_argv, "ab::c::", NULL, NULL);
assert(c == 'a');
assert(optarg == NULL);
c = getopt_long(COUNT_OF(test_argv), test_argv, "ab::c::", NULL, NULL);
assert(c == 'b');
assert(!optarg);
c = getopt_long(COUNT_OF(test_argv), test_argv, "ab::c::", NULL, NULL);
assert(c == 'c');
assert(!strcmp(optarg, "arg"));
c = getopt_long(COUNT_OF(test_argv), test_argv, "ab::c::", NULL, NULL);
assert(c == -1);
assert(optind == 4);
assert(!strcmp(test_argv[optind], "arg"));
}
void test13() {
const struct option longopts[] = {
{"ambiguous-opt", no_argument, NULL, 0},
{"ambiguous-option", no_argument, NULL, 1},
{NULL, 0, NULL, 0}
};
char *test_argv[] = {
"dummy",
"--ambiguous-o"
};
fputs("Situation: ambiguous long option\n", stderr);
optind = 0;
opterr = 0;
int c = getopt_long(COUNT_OF(test_argv), test_argv, "", longopts, NULL);
assert(c == '?');
}
void test14() {
const struct option longopts[] = {
{"foo", required_argument, NULL, 'f'},
{NULL, 0, NULL, 0}
};
char *test_argv[] = {
"dummy",
"-Wfoo=bar",
};
fputs("Situation: -W for long options\n", stderr);
optind = 0;
int c = getopt_long(COUNT_OF(test_argv), test_argv, "W;", longopts, NULL);
assert(c == 'f');
assert(!strcmp(optarg, "bar"));
}
void test15() {
char *test_argv[] = {
"dummy",
"-c",
"-a",
"--",
"-b"
};
fputs("Situation: -- to stop option processing\n", stderr);
optind = 0;
int c = getopt(COUNT_OF(test_argv), test_argv, "+ab");
assert(c == '?');
assert(optind == 2);
c = getopt(COUNT_OF(test_argv), test_argv, "+ab");
assert(c == 'a');
assert(optind == 3);
c = getopt(COUNT_OF(test_argv), test_argv, "+ab");
assert(c == -1);
assert(optind == 4);
assert(!strcmp(test_argv[optind], "-b"));
}
void test16() {
const struct option longopts[] = {
{"add", required_argument, NULL, 'a'},
{"append", no_argument, NULL, 'p'},
{NULL, 0, NULL, 0}
};
char *test_argv[] = {
"dummy",
"--ad=foo",
"--appe"
};
fputs("Situation: non-ambiguous long option prefix\n", stderr);
optind = 0;
int c = getopt_long(COUNT_OF(test_argv), test_argv, "", longopts, NULL);
assert(c == 'a');
assert(!strcmp(optarg, "foo"));
c = getopt_long(COUNT_OF(test_argv), test_argv, "", longopts, NULL);
assert(c == 'p');
assert(optarg == NULL);
}
void test17() {
const struct option longopts[] = {
{"foo", no_argument, NULL, 'l'},
{NULL, 0, NULL, 0}
};
char *test_argv[] = {
"dummy",
"-foo"
};
fputs("Situation: getopt_long_only with what could be short opts or a long opt\n", stderr);
// Case 1: long option "foo" exists, so "-foo" should be treated as "--foo"
optind = 0;
int c = getopt_long_only(COUNT_OF(test_argv), test_argv, "f:o", longopts, NULL);
assert(c == 'l');
// Case 2: long option "foo" does not exist.
const struct option longopts2[] = {
{"bar", no_argument, NULL, 'b'},
{NULL, 0, NULL, 0}
};
optind = 0;
c = getopt_long_only(COUNT_OF(test_argv), test_argv, "f:o", longopts2, NULL);
assert(c == 'f');
assert(!strcmp(optarg, "oo"));
}
void test18() {
const struct option longopts[] = {
{"op", optional_argument, NULL, 'o'},
{NULL, 0, NULL, 0}
};
char *test_argv[] = {
"dummy",
"-Wop=val",
};
fputs("Situation: -W with a long option with an optional argument (with value)\n", stderr);
optind = 0;
int c = getopt_long(COUNT_OF(test_argv), test_argv, "W;", longopts, NULL);
assert(c == 'o');
assert(!strcmp(optarg, "val"));
char *test_argv2[] = {
"dummy",
"-Wop",
};
fputs("Situation: -W with a long option with an optional argument (no value)\n", stderr);
optind = 0;
c = getopt_long(COUNT_OF(test_argv2), test_argv2, "W;", longopts, NULL);
assert(c == 'o');
assert(optarg == NULL);
}
void test19() {
char *test_argv[] = {
"dummy",
"-a",
"non-option",
"-b",
};
fputs("Situation: POSIXLY_CORRECT behavior with '+'\n", stderr);
optind = 0;
int c = getopt(COUNT_OF(test_argv), test_argv, "+ab");
assert(c == 'a');
c = getopt(COUNT_OF(test_argv), test_argv, "+ab");
assert(c == -1);
assert(optind == 2);
assert(!strcmp(test_argv[optind], "non-option"));
}
void test20() {
const struct option longopts[] = {
{"option", required_argument, NULL, 'o'},
{NULL, 0, NULL, 0}
};
char *test_argv[] = {
"dummy",
"--option",
"-x",
};
fputs("Situation: long option with argument that looks like an option\n", stderr);
optind = 0;
int c = getopt_long(COUNT_OF(test_argv), test_argv, "x", longopts, NULL);
assert(c == 'o');
assert(!strcmp(optarg, "-x"));
assert(optind == 3);
}
void test21() {
const struct option longopts[] = {
{"ambig-one", no_argument, NULL, '1'},
{"ambig-two", no_argument, NULL, '2'},
{NULL, 0, NULL, 0}
};
char *test_argv[] = {
"dummy",
"-ambig",
};
fputs("Situation: ambiguous long option with getopt_long_only\n", stderr);
optind = 0;
opterr = 0;
int c = getopt_long_only(COUNT_OF(test_argv), test_argv, "", longopts, NULL);
assert(c == '?');
}
void test22() {
const struct option longopts[] = {
{"foo", no_argument, NULL, 'f'},
{NULL, 0, NULL, 0}
};
char *test_argv[] = {
"dummy",
"-Wbar",
};
fputs("Situation: -W with non-existent long option\n", stderr);
optind = 0;
opterr = 0;
int c = getopt_long(COUNT_OF(test_argv), test_argv, "W;", longopts, NULL);
assert(c == '?');
assert(optind == 2);
}
void test23() {
const struct option longopts[] = {
{"foo", required_argument, NULL, 'f'},
{NULL, 0, NULL, 0}
};
char *test_argv[] = {
"dummy",
"-foo",
"val1",
"-foo=val2",
};
fputs("Situation: getopt_long_only with required argument\n", stderr);
optind = 0;
int c = getopt_long_only(COUNT_OF(test_argv), test_argv, "", longopts, NULL);
assert(c == 'f');
assert(!strcmp(optarg, "val1"));
assert(optind == 3);
c = getopt_long_only(COUNT_OF(test_argv), test_argv, "", longopts, NULL);
assert(c == 'f');
assert(!strcmp(optarg, "val2"));
assert(optind == 4);
}
void test24() {
char *test_argv[] = {
"dummy",
"-W",
};
fputs("Situation: -W as a short option, not for passing long options\n", stderr);
optind = 0;
int c = getopt(COUNT_OF(test_argv), test_argv, "W");
assert(c == 'W');
assert(optind == 2);
}
void test25() {
const struct option longopts[] = {
{"foo", required_argument, NULL, 'f'},
{NULL, 0, NULL, 0}
};
char *test_argv[] = {
"dummy",
"-Wfoo",
};
fputs("Situation: -W with missing argument for a long option, with ':' in optstring\n", stderr);
optind = 0;
opterr = 0;
int c = getopt_long(COUNT_OF(test_argv), test_argv, ":W;", longopts, NULL);
assert(c == ':');
assert(optopt == 'f');
assert(optind == 2);
}
void test26() {
const struct option longopts[] = {
{"foo", no_argument, NULL, 0},
{"ambig-one", no_argument, NULL, 1},
{"ambig-two", no_argument, NULL, 2},
{NULL, 0, NULL, 0}
};
char *test_argv[] = {
"dummy",
"-W",
};
fputs("Situation: -W without an argument\n", stderr);
optind = 0;
opterr = 1;
int c = getopt_long(COUNT_OF(test_argv), test_argv, ":W;", longopts, NULL);
assert(c == ':');
assert(optopt == 'W');
assert(optind == 2);
}
void test27() {
char *test_argv[] = {
"dummy",
"-Wambig",
};
const struct option longopts[] = {
{"foo", no_argument, NULL, 0},
{"ambig-one", no_argument, NULL, 1},
{"ambig-two", no_argument, NULL, 2},
{NULL, 0, NULL, 0}
};
fputs("Situation: -W with an ambiguous long option\n", stderr);
optind = 0;
opterr = 0;
int c = getopt_long(COUNT_OF(test_argv), test_argv, "W;", longopts, NULL);
assert(c == '?');
assert(optind == 2);
}
void test28() {
char *test_argv[] = {
"dummy",
"-Wfoo=bar",
"-Wfoo=",
};
const struct option longopts[] = {
{"foo", no_argument, NULL, 0},
{"ambig-one", no_argument, NULL, 1},
{"ambig-two", no_argument, NULL, 2},
{NULL, 0, NULL, 0}
};
fputs("Situation: -W with an argument to a long option that does not take one\n", stderr);
optind = 0;
opterr = 0;
int c = getopt_long(COUNT_OF(test_argv), test_argv, "W;", longopts, NULL);
assert(c == '?');
assert(optind == 2);
c = getopt_long(COUNT_OF(test_argv), test_argv, "W;", longopts, NULL);
assert(c == '?');
assert(optind == 3);
c = getopt_long(COUNT_OF(test_argv), test_argv, "W;", longopts, NULL);
assert(c == -1);
}
void test29() {
char *test_argv[] = {
"dummy",
"--a",
};
const struct option longopts[] = {
{"load-credentials", no_argument, NULL, 0x103},
{NULL, 0, NULL, 0},
};
optind = 0;
opterr = 1;
int c = getopt_long(COUNT_OF(test_argv), test_argv, "el:sSRp:m:t:Vh", longopts, NULL);
dump(c);
assert(c == '?');
assert(optind == 2);
}
void test30() {
const struct option longopts[] = {
{"long-opt", required_argument, NULL, 'l'},
{NULL, 0, NULL, 0}
};
char *test_argv[] = {
"getopt_test",
"non-arg1",
"--long-opt",
"val",
"non-arg2"
};
fputs("Situation: non-arguments before valid long arguments\n", stderr);
optind = 0;
int c = getopt_long(COUNT_OF(test_argv), test_argv, "+", longopts, NULL);
assert(c == -1);
assert(optind == 1);
assert(!strcmp(test_argv[0], "getopt_test"));
assert(!strcmp(test_argv[1], "non-arg1"));
assert(!strcmp(test_argv[2], "--long-opt"));
assert(!strcmp(test_argv[3], "val"));
assert(!strcmp(test_argv[4], "non-arg2"));
optind = 2;
while ((c = getopt_long(COUNT_OF(test_argv), test_argv, "+", longopts, NULL)) != -1) {
switch (c) {
case 'l':
assert(!strcmp(optarg, "val"));
break;
default:
break;
}
}
assert(c == -1);
assert(optind == 4);
optind = 0;
while ((c = getopt_long(COUNT_OF(test_argv), test_argv, "", longopts, NULL)) != -1) {
switch (c) {
case 'l':
assert(!strcmp(optarg, "val"));
break;
default:
break;
}
}
assert(optind == 3);
assert(!strcmp(test_argv[0], "getopt_test"));
assert(!strcmp(test_argv[1], "--long-opt"));
assert(!strcmp(test_argv[2], "val"));
assert(!strcmp(test_argv[3], "non-arg1"));
assert(!strcmp(test_argv[4], "non-arg2"));
}
int main() {
test1();
test2();
test3();
test4();
test5();
test6();
test7();
test8();
test9();
test10();
test11();
test12();
test13();
test14();
test15();
test16();
test17();
test18();
test19();
test20();
test21();
test22();
test23();
test24();
test25();
test26();
test27();
test28();
test29();
test30();
return 0;
}
@@ -0,0 +1,13 @@
#define _GNU_SOURCE
#include <assert.h>
#include <string.h>
#define test_string(x, expectval) assert(strcmp(basename(x), expectval) == 0)
int main() {
test_string("/usr/lib", "lib");
test_string("/usr/", "");
test_string("/", "");
test_string(".", ".");
test_string("..", "..");
}
@@ -0,0 +1,14 @@
#include <sys/syscall.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
int main() {
char *data = "hello mlibc\n";
long ret = syscall(SYS_write, 1, data, strlen(data));
assert(ret == (long)strlen(data));
syscall(SYS_exit, 0);
abort();
}
+17
View File
@@ -0,0 +1,17 @@
#include <assert.h>
#include <locale.h>
#include <stdlib.h>
int main() {
assert(rpmatch("y") == 1);
assert(rpmatch("Y") == 1);
assert(rpmatch("n") == 0);
assert(rpmatch("N") == 0);
assert(rpmatch("yno") == 1);
assert(rpmatch("no") == 0);
assert(rpmatch("NO") == 0);
assert(rpmatch("YES") == 1);
assert(rpmatch("mlibc") == -1);
return 0;
}
+27
View File
@@ -0,0 +1,27 @@
#include <assert.h>
#include <stdlib.h>
#include <sched.h>
#define SET_SIZE 15
int main() {
cpu_set_t *set = CPU_ALLOC(SET_SIZE);
size_t setsize = CPU_ALLOC_SIZE(SET_SIZE);
CPU_ZERO_S(setsize, set);
assert(!CPU_ISSET_S(11, setsize, set));
CPU_SET_S(11, setsize, set);
assert(CPU_ISSET_S(11, setsize, set));
assert(CPU_COUNT_S(setsize, set) == 1);
assert(!CPU_ISSET_S(CPU_SETSIZE - 1, setsize, set));
CPU_CLR_S(11, setsize, set);
assert(!CPU_ISSET_S(11, setsize, set));
CPU_FREE(set);
return 0;
}
@@ -0,0 +1,65 @@
#include <arpa/inet.h>
#include <assert.h>
#include <ifaddrs.h>
#include <linux/if_link.h>
#include <net/if.h>
#include <netdb.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
(void) argc;
(void) argv;
struct ifaddrs *ifaddr = 0;
char host[NI_MAXHOST];
bool loopback_found = false;
if(getifaddrs(&ifaddr)) {
perror("getifaddrs");
exit(EXIT_FAILURE);
}
for(struct ifaddrs *ifa = ifaddr; ifa; ifa = ifa->ifa_next) {
if(ifa->ifa_addr == NULL)
continue;
int family = ifa->ifa_addr->sa_family;
if(family == AF_INET && !strcmp("lo", ifa->ifa_name)) {
loopback_found = true;
printf("%-10s %s (%d)\n", ifa->ifa_name,
(family == AF_INET) ? "AF_INET" : (family == AF_INET6) ? "AF_INET6" : "???",
family
);
int s = getnameinfo(ifa->ifa_addr,
(family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6),
host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
assert(!s);
printf("\t\taddress: <%s>\n", host);
if(ifa->ifa_netmask)
printf("\t\tnetmask: <%s>\n", inet_ntoa(((struct sockaddr_in *) ifa->ifa_netmask)->sin_addr));
if(ifa->ifa_flags & IFF_BROADCAST) {
assert(ifa->ifa_broadaddr);
printf("\t\tbroadcast: <%s>\n", inet_ntoa(((struct sockaddr_in *) ifa->ifa_broadaddr)->sin_addr));
}
if(ifa->ifa_flags & IFF_POINTOPOINT) {
assert(ifa->ifa_dstaddr);
printf("\t\tdest addr: <%s>\n", inet_ntoa(((struct sockaddr_in *) ifa->ifa_dstaddr)->sin_addr));
}
}
}
freeifaddrs(ifaddr);
exit(loopback_found ? EXIT_SUCCESS : EXIT_FAILURE);
}
@@ -0,0 +1,13 @@
#include <assert.h>
#include <malloc.h>
#include <stdio.h>
#include <stdlib.h>
int main() {
void *p1 = malloc(1023);
fprintf(stderr, "size: %zu\n", malloc_usable_size(p1));
assert(malloc_usable_size(p1) >= 1023);
free(p1);
return 0;
}
+74
View File
@@ -0,0 +1,74 @@
#include <assert.h>
#include <errno.h>
#include <poll.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/pidfd.h>
#include <sys/wait.h>
#include <unistd.h>
int main() {
int child = fork();
if(!child) {
sleep(1);
exit(42);
}
int pidfd = pidfd_open(child, 0);
assert(pidfd > 0);
int ret = lseek(pidfd, 0, SEEK_SET);
assert(ret == -1);
assert(errno == ESPIPE);
pid_t outpid = pidfd_getpid(pidfd);
assert(outpid == child);
struct pollfd pollfd;
pollfd.fd = pidfd;
pollfd.events = POLLIN;
int ready = poll(&pollfd, 1, 0);
assert(ready == 0);
ready = poll(&pollfd, 1, 2000);
if(ready == -1) {
perror("poll");
exit(EXIT_FAILURE);
}
assert(ready == 1);
assert(pollfd.revents == POLLIN);
siginfo_t info = {};
ret = waitid(P_PIDFD, pidfd, &info, WEXITED | WNOHANG);
assert(ret == 0);
assert(info.si_code == CLD_EXITED);
assert(info.si_pid == child);
assert(info.si_status == 42);
close(pidfd);
child = fork();
if(!child) {
sleep(10);
}
pidfd = pidfd_open(child, 0);
assert(pidfd > 0);
ret = pidfd_send_signal(pidfd, SIGKILL, NULL, 0);
assert(ret == 0);
memset(&info, 0, sizeof(info));
ret = waitid(P_PIDFD, pidfd, &info, WEXITED);
assert(ret == 0);
assert(info.si_code == CLD_KILLED);
assert(info.si_pid == child);
assert(info.si_status == SIGKILL);
return 0;
}
+96
View File
@@ -0,0 +1,96 @@
#include <assert.h>
#include <errno.h>
#include <poll.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>
static void sig_handler(int sig) {
(void)sig;
}
int main() {
int fds[2];
int ret = pipe(fds);
assert(ret == 0);
struct pollfd poll_fds[1];
poll_fds[0].fd = fds[0];
poll_fds[0].events = POLLIN;
struct timespec timeout;
timeout.tv_sec = 0;
timeout.tv_nsec = 1000000; // 1 ms
// Test that ppoll times out correctly.
ret = ppoll(poll_fds, 1, &timeout, NULL);
assert(ret == 0);
// Test that ppoll returns 1 if there is an event.
char buf[1];
ret = write(fds[1], "a", 1);
assert(ret == 1);
ret = ppoll(poll_fds, 1, &timeout, NULL);
assert(ret == 1);
assert(poll_fds[0].revents & POLLIN);
// Test that ppoll returns 0 if there are no events and timeout is 0.
ret = read(fds[0], buf, 1);
assert(ret == 1);
timeout.tv_nsec = 0;
ret = ppoll(poll_fds, 1, &timeout, NULL);
assert(ret == 0);
// Test that ppoll returns immediately if there is an event and timeout is 0.
ret = write(fds[1], "a", 1);
assert(ret == 1);
ret = ppoll(poll_fds, 1, &timeout, NULL);
assert(ret == 1);
assert(poll_fds[0].revents & POLLIN);
char recvbuf[2];
ret = read(fds[0], &recvbuf, 2);
assert(ret == 1);
// Test that ppoll is interrupted by a signal.
struct sigaction sa;
sa.sa_handler = sig_handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
ret = sigaction(SIGUSR1, &sa, NULL);
assert(ret == 0);
pid_t pid = fork();
assert(pid >= 0);
if (pid == 0) {
// Child process.
usleep(100000); // 100 ms
ret = kill(getppid(), SIGUSR1);
assert(ret == 0);
exit(0);
} else {
// Parent process.
timeout.tv_sec = 1;
timeout.tv_nsec = 0;
ret = ppoll(poll_fds, 1, &timeout, NULL);
assert(ret == -1);
assert(errno == EINTR);
int status;
ret = waitpid(pid, &status, 0);
assert(ret == pid);
assert(WIFEXITED(status) && WEXITSTATUS(status) == 0);
}
close(fds[0]);
close(fds[1]);
return 0;
}
@@ -0,0 +1,35 @@
#include <assert.h>
#include <stdio.h>
#include <sys/uio.h>
#include <unistd.h>
// Test variable to read and write
static int test = 42;
int main() {
// Read the variable using process_vm_readv
int temp;
struct iovec local_iov = {
.iov_base = &temp,
.iov_len = sizeof(temp),
};
struct iovec remote_iov = {
.iov_base = &test,
.iov_len = sizeof(test),
};
ssize_t bytes_read = process_vm_readv(getpid(), &local_iov, 1, &remote_iov, 1, 0);
assert(bytes_read == sizeof(test));
assert(temp == 42);
// Write a new value to the variable using process_vm_writev
int new_value = 1337;
struct iovec new_local_iov = {
.iov_base = &new_value,
.iov_len = sizeof(new_value),
};
ssize_t bytes_written = process_vm_writev(getpid(), &new_local_iov, 1, &remote_iov, 1, 0);
assert(bytes_written == sizeof(new_value));
assert(test == 1337);
return 0;
}
@@ -0,0 +1,90 @@
#include <assert.h>
#include <pthread.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
static void test_affinity() {
pthread_attr_t attr;
cpu_set_t set = {0};
assert(!pthread_attr_init(&attr));
assert(!pthread_attr_setaffinity_np(&attr, 1, &set));
cpu_set_t other_set = {0};
assert(!pthread_attr_getaffinity_np(&attr, 1, &set));
assert(!memcmp(&set, &other_set, sizeof(cpu_set_t)));
pthread_attr_destroy(&attr);
}
#if !defined(USE_HOST_LIBC) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 32)
static void test_sigmask() {
pthread_attr_t attr;
sigset_t set;
sigemptyset(&set);
sigaddset(&set, SIGUSR1);
#ifndef USE_HOST_LIBC
sigaddset(&set, SIGCANCEL);
#endif
assert(!pthread_attr_init(&attr));
assert(!pthread_attr_setsigmask_np(&attr, &set));
sigset_t other_set;
sigemptyset(&other_set);
assert(!pthread_attr_getsigmask_np(&attr, &other_set));
assert(sigismember(&other_set, SIGUSR1));
#ifndef USE_HOST_LIBC
// Test whether internal signals get filtered properly.
assert(!sigismember(&other_set, SIGCANCEL));
#endif
pthread_attr_destroy(&attr);
}
static void *getattr_worker(void *arg) {
(void)arg;
return NULL;
}
static void test_getattrnp() {
pthread_attr_t attr;
size_t stacksize = PTHREAD_STACK_MIN;
assert(!pthread_attr_init(&attr));
assert(!pthread_attr_setstacksize(&attr, stacksize));
pthread_t thread;
assert(!pthread_create(&thread, &attr, getattr_worker, NULL));
assert(!pthread_getattr_np(thread, &attr));
size_t other_stacksize;
assert(!pthread_attr_getstacksize(&attr, &other_stacksize));
assert(other_stacksize == stacksize);
assert(!pthread_join(thread, NULL));
pthread_t own_thread = pthread_self();
void *stack;
assert(!pthread_getattr_np(own_thread, &attr));
assert(!pthread_attr_getstack(&attr, &stack, &other_stacksize));
assert(stack);
assert(other_stacksize);
// Check that we can read from the highest byte returned.
// pthread_getattr_np() should return the lowest byte
// of the stack.
printf("highest byte: %hhu\n", *(char *)(stack + other_stacksize - 1));
pthread_attr_destroy(&attr);
}
#endif // !defined(USE_HOST_LIBC) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 32)
int main() {
test_affinity();
#if !defined(USE_HOST_LIBC) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 32)
test_sigmask();
test_getattrnp();
#endif
return 0;
}
@@ -0,0 +1,33 @@
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <assert.h>
#include <errno.h>
#include <string.h>
#include <pthread.h>
int main() {
int ret = pthread_setname_np(pthread_self(), "mlibc-test-123");
assert(!ret);
char buf[16];
ret = pthread_getname_np(pthread_self(), buf, 16);
assert(!ret);
assert(!strcmp("mlibc-test-123", buf));
ret = pthread_setname_np(pthread_self(), "mlibc-test-123-too-long");
assert(ret == ERANGE);
ret = pthread_getname_np(pthread_self(), buf, 1);
assert(ret == ERANGE);
ret = pthread_getname_np(pthread_self(), buf, 15);
assert(ret == ERANGE);
ret = pthread_getname_np(pthread_self(), buf, 16);
assert(!ret);
assert(!strcmp("mlibc-test-123", buf));
return 0;
}
+64
View File
@@ -0,0 +1,64 @@
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <stdint.h>
#include <sys/time.h>
#include <sys/timerfd.h>
#include <unistd.h>
int main() {
int t = timerfd_create(CLOCK_MONOTONIC, 0);
assert(t > 0);
struct itimerspec its;
int ret = timerfd_gettime(t, &its);
assert(ret == 0);
assert(!its.it_value.tv_sec);
assert(!its.it_value.tv_nsec);
assert(!its.it_interval.tv_sec);
assert(!its.it_interval.tv_nsec);
struct itimerspec new_its = {
.it_interval = {0, 0},
.it_value = {0, 100000000},
};
ret = timerfd_settime(t, 0, &new_its, &its);
assert(ret == 0);
assert(!its.it_value.tv_sec);
assert(!its.it_value.tv_nsec);
assert(!its.it_interval.tv_sec);
assert(!its.it_interval.tv_nsec);
ret = timerfd_gettime(t, &its);
assert(ret == 0);
assert(!its.it_value.tv_sec);
assert(its.it_value.tv_nsec);
assert(!its.it_interval.tv_sec);
assert(!its.it_interval.tv_nsec);
struct timeval before;
gettimeofday(&before, NULL);
assert(ret == 0);
uint64_t ev = 0;
ret = read(t, &ev, sizeof(ev));
struct timeval after;
gettimeofday(&after, NULL);
assert(ret == sizeof(ev));
assert(ev == 1);
struct timeval diff = {};
timersub(&after, &before, &diff);
assert(diff.tv_sec || diff.tv_usec);
fcntl(t, F_SETFL, fcntl(t, F_GETFL, 0) | O_NONBLOCK);
ret = timerfd_settime(t, 0, &new_its, &its);
assert(ret == 0);
ret = read(t, &ev, sizeof(ev));
assert(ret == -1);
assert(errno == EAGAIN);
return 0;
}
+132
View File
@@ -0,0 +1,132 @@
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <utmp.h>
int main() {
char path[] = "/tmp/mlibc-utmp-test-XXXXXX";
int fd = mkstemp(path);
assert(fd != -1);
close(fd);
int ret = utmpname(path);
assert(!ret);
// Test writing to the utmp file.
struct utmp entry1;
memset(&entry1, 0, sizeof(struct utmp));
entry1.ut_type = USER_PROCESS;
entry1.ut_pid = 1234;
strcpy(entry1.ut_line, "pts/1");
strcpy(entry1.ut_id, "id1");
strcpy(entry1.ut_user, "user1");
strcpy(entry1.ut_host, "host1");
entry1.ut_tv.tv_sec = 1;
entry1.ut_tv.tv_usec = 1;
setutent();
struct utmp *res = pututline(&entry1);
assert(res);
endutent();
// Test reading from the utmp file.
setutent();
struct utmp *read_entry = getutent();
assert(read_entry);
assert(read_entry->ut_type == USER_PROCESS);
assert(read_entry->ut_pid == 1234);
assert(strcmp(read_entry->ut_line, "pts/1") == 0);
assert(strcmp(read_entry->ut_id, "id1") == 0);
assert(strcmp(read_entry->ut_user, "user1") == 0);
assert(strcmp(read_entry->ut_host, "host1") == 0);
assert(read_entry->ut_tv.tv_sec == 1);
assert(read_entry->ut_tv.tv_usec == 1);
read_entry = getutent();
assert(!read_entry);
assert(errno == ESRCH);
endutent();
// Test getutid
struct utmp id_entry;
memset(&id_entry, 0, sizeof(struct utmp));
id_entry.ut_type = USER_PROCESS;
strcpy(id_entry.ut_id, "id1");
setutent();
struct utmp *id_read_entry = getutid(&id_entry);
assert(id_read_entry);
assert(id_read_entry->ut_pid == 1234);
read_entry = getutent();
assert(!read_entry);
assert(errno == ESRCH);
endutent();
// Test getutline
struct utmp line_entry;
memset(&line_entry, 0, sizeof(struct utmp));
line_entry.ut_type = USER_PROCESS;
strcpy(line_entry.ut_line, "pts/1");
setutent();
struct utmp *line_read_entry = getutline(&line_entry);
assert(line_read_entry);
assert(line_read_entry->ut_pid == 1234);
endutent();
// Test getutent_r
struct utmp buf;
struct utmp *res_r;
setutent();
int ret_r = getutent_r(&buf, &res_r);
assert(!ret_r);
assert(res_r == &buf);
assert(buf.ut_pid == 1234);
endutent();
// Test updwtmp.
char wtmp_path[] = "/tmp/mlibc-wtmp-test-XXXXXX";
int wtmp_fd = mkstemp(wtmp_path);
assert(wtmp_fd != -1);
close(wtmp_fd);
struct utmp entry2;
memset(&entry2, 0, sizeof(struct utmp));
entry2.ut_type = USER_PROCESS;
entry2.ut_pid = 5678;
strcpy(entry2.ut_line, "pts/2");
strcpy(entry2.ut_id, "id2");
strcpy(entry2.ut_user, "user2");
strcpy(entry2.ut_host, "host2");
entry2.ut_tv.tv_sec = 2;
entry2.ut_tv.tv_usec = 2;
updwtmp(wtmp_path, &entry2);
// Verify the wtmp file.
FILE *f = fopen(wtmp_path, "r");
assert(f);
struct utmp wtmp_entry;
ret = fread(&wtmp_entry, sizeof(struct utmp), 1, f);
assert(ret == 1);
fclose(f);
assert(wtmp_entry.ut_type == USER_PROCESS);
assert(wtmp_entry.ut_pid == 5678);
assert(strcmp(wtmp_entry.ut_line, "pts/2") == 0);
assert(strcmp(wtmp_entry.ut_id, "id2") == 0);
assert(strcmp(wtmp_entry.ut_user, "user2") == 0);
assert(strcmp(wtmp_entry.ut_host, "host2") == 0);
assert(wtmp_entry.ut_tv.tv_sec == 2);
assert(wtmp_entry.ut_tv.tv_usec == 2);
unlink(wtmp_path);
unlink(path);
return EXIT_SUCCESS;
}
+117
View File
@@ -0,0 +1,117 @@
#include <assert.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <utmpx.h>
int main() {
char path[] = "/tmp/mlibc-utmpx-test-XXXXXX";
int fd = mkstemp(path);
assert(fd != -1);
close(fd);
int ret = utmpxname(path);
assert(!ret);
struct utmpx entry;
memset(&entry, 0, sizeof(struct utmpx));
// Test an empty file.
setutxent();
struct utmpx *read_entry = getutxent();
assert(!read_entry);
endutxent();
// Test writing a new entry.
entry.ut_type = USER_PROCESS;
entry.ut_pid = getpid();
strncpy(entry.ut_line, "tty1", sizeof(entry.ut_line));
strncpy(entry.ut_id, "t1", sizeof(entry.ut_id));
strncpy(entry.ut_user, "root", sizeof(entry.ut_user));
strncpy(entry.ut_host, "localhost", sizeof(entry.ut_host));
entry.ut_tv.tv_sec = 1234567890;
entry.ut_tv.tv_usec = 0;
setutxent();
assert(pututxline(&entry));
endutxent();
// Test reading the entry back.
setutxent();
read_entry = getutxent();
assert(read_entry);
assert(read_entry->ut_type == USER_PROCESS);
assert(read_entry->ut_pid == getpid());
assert(!strcmp(read_entry->ut_line, "tty1"));
assert(!strcmp(read_entry->ut_id, "t1"));
assert(!strcmp(read_entry->ut_user, "root"));
assert(!strcmp(read_entry->ut_host, "localhost"));
assert(read_entry->ut_tv.tv_sec == 1234567890);
read_entry = getutxent();
assert(!read_entry);
endutxent();
// Test getutxid().
struct utmpx id_entry;
memset(&id_entry, 0, sizeof(struct utmpx));
id_entry.ut_type = USER_PROCESS;
strncpy(id_entry.ut_id, "t1", sizeof(id_entry.ut_id));
setutxent();
struct utmpx *id_read_entry = getutxid(&id_entry);
assert(id_read_entry);
assert(id_read_entry->ut_pid == getpid());
endutxent();
// Test getutxline().
struct utmpx line_entry;
memset(&line_entry, 0, sizeof(struct utmpx));
line_entry.ut_type = USER_PROCESS;
strncpy(line_entry.ut_line, "tty1", sizeof(line_entry.ut_line));
setutxent();
struct utmpx *line_read_entry = getutxline(&line_entry);
assert(line_read_entry);
assert(line_read_entry->ut_pid == getpid());
endutxent();
// Test updwtmpx.
char wtmpx_path[] = "/tmp/mlibc-wtmpx-test-XXXXXX";
int wtmpx_fd = mkstemp(wtmpx_path);
assert(wtmpx_fd != -1);
close(wtmpx_fd);
struct utmpx entry2;
memset(&entry2, 0, sizeof(struct utmpx));
entry2.ut_type = USER_PROCESS;
entry2.ut_pid = 5678;
strcpy(entry2.ut_line, "pts/2");
strcpy(entry2.ut_id, "id2");
strcpy(entry2.ut_user, "user2");
strcpy(entry2.ut_host, "host2");
entry2.ut_tv.tv_sec = 2;
entry2.ut_tv.tv_usec = 2;
updwtmpx(wtmpx_path, &entry2);
// Verify the wtmpx file.
FILE *f = fopen(wtmpx_path, "r");
assert(f);
struct utmpx wtmpx_entry;
ret = fread(&wtmpx_entry, sizeof(struct utmpx), 1, f);
assert(ret == 1);
fclose(f);
assert(wtmpx_entry.ut_type == USER_PROCESS);
assert(wtmpx_entry.ut_pid == 5678);
assert(strcmp(wtmpx_entry.ut_line, "pts/2") == 0);
assert(strcmp(wtmpx_entry.ut_id, "id2") == 0);
assert(strcmp(wtmpx_entry.ut_user, "user2") == 0);
assert(strcmp(wtmpx_entry.ut_host, "host2") == 0);
assert(wtmpx_entry.ut_tv.tv_sec == 2);
assert(wtmpx_entry.ut_tv.tv_usec == 2);
unlink(wtmpx_path);
unlink(path);
return EXIT_SUCCESS;
}
+82
View File
@@ -0,0 +1,82 @@
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/xattr.h>
#define assert_perror(x) \
({ \
int res = (x); \
if (res < 0) { \
perror(#x); \
return 1; \
} \
res; \
})
#define soft_assert(x, m) \
({ \
if (!(x)) { \
fprintf(stderr, "cond \"%s\" failed: %s\n", #x, m); \
return 1; \
} \
})
void remove_tmp(const char (*fname)[]) {
unlink(&(*fname)[0]);
}
#define _cleanup_file_ __attribute__((cleanup(remove_tmp)))
int main(void) {
int ret;
char buf[32] = { 0 };
_cleanup_file_ char filename[] = "xattr_test.XXXXXX";
_cleanup_file_ char filename2[] = "xattr_test.XXXXXX.2";
int tmpfile = assert_perror(mkstemp(filename));
memcpy(filename2, filename, sizeof(filename) - 1);
assert_perror(symlink(filename, filename2));
assert_perror(setxattr(filename, "user.T1", "ABC", 3, XATTR_CREATE));
assert_perror(fsetxattr(tmpfile, "user.T2", "DEF", 3, XATTR_CREATE));
// for testing remove
assert_perror(fsetxattr(tmpfile, "user.T3", "DEF", 3, XATTR_CREATE));
if ((ret = getxattr(filename, "user.T1", buf, 3)) != 3) {
if (ret < 0) {
perror("getxattr");
return 1;
}
soft_assert(memcmp(buf, "ABC", 3) == 0, "xattr read wrong");
}
ret = lgetxattr(filename2, "user.T1", buf, 3);
soft_assert(ret < 0 && errno == ENODATA, "lgetxattr deref'd");
if ((ret = fgetxattr(tmpfile, "user.T3", buf, 3)) != 3) {
if (ret < 0) {
perror("fgetxattr");
return 1;
}
soft_assert(memcmp(buf, "DEF", 3) == 0, "xattr read wrong");
}
assert_perror(removexattr(filename, "user.T2"));
assert_perror(fremovexattr(tmpfile, "user.T3"));
ret = assert_perror(listxattr(filename, buf, sizeof(buf) - 1));
soft_assert(memmem(buf, ret, "user.T1", 7), "user.T1 not found");
soft_assert(!memmem(buf, ret, "user.T2", 7), "user.T2 found");
soft_assert(!memmem(buf, ret, "user.T3", 7), "user.T3 found");
ret = assert_perror(flistxattr(tmpfile, buf, sizeof(buf) - 1));
soft_assert(memmem(buf, ret, "user.T1", 7), "user.T1 not found");
soft_assert(!memmem(buf, ret, "user.T2", 7), "user.T2 found");
soft_assert(!memmem(buf, ret, "user.T3", 7), "user.T3 found");
return 0;
}
+342
View File
@@ -0,0 +1,342 @@
timeout_sec = 10
all_test_cases = [
'ansi/alloc',
'ansi/sscanf',
'ansi/sprintf',
'ansi/snprintf',
'ansi/utf8',
'ansi/strtol',
'ansi/strtof',
'ansi/abs',
'ansi/longjmp',
'ansi/mbrtoc32',
'ansi/strverscmp',
'ansi/strftime',
'ansi/strchr',
'ansi/strrchr',
'ansi/wcsrtombs',
'ansi/wmemcmp',
'ansi/timegm',
'ansi/tz',
'ansi/ungetc',
'ansi/wcsdup',
'ansi/wcsncasecmp',
'ansi/fopen',
'ansi/memmem',
'ansi/creal-cimag',
'ansi/fenv',
'ansi/qsort',
'ansi/freopen',
'ansi/strxfrm',
'ansi/calloc',
'ansi/fgetpos',
'ansi/fputs',
'ansi/ftell',
'bsd/ns_get_put',
'bsd/reallocarray',
'bsd/strl',
'bsd/sbrk',
'bsd/getloadavg',
'posix/inet_ntop',
'posix/inet_pton',
'posix/access',
'posix/pthread_barrier',
'posix/pthread_rwlock',
'posix/pthread_cond',
'posix/pthread_create',
'posix/pthread_cancel',
'posix/pthread_atfork',
'posix/pthread_cleanup',
'posix/pthread_kill',
'posix/pthread_mutex',
'posix/pthread_key',
'posix/pthread_thread_local',
'posix/pthread_attr',
'posix/pthread_schedparam',
'posix/pwd',
'posix/fdopen',
'posix/fopencookie',
'posix/fmemopen',
'posix/getaddrinfo',
'posix/getdelim',
'posix/getnameinfo',
'posix/getparam',
'posix/getservbyname',
'posix/getservbyport',
'posix/grp',
'posix/dprintf',
'posix/posix_memalign',
'posix/posix_spawn',
'posix/index',
'posix/rindex',
'posix/search',
'posix/semaphore',
'posix/open_memstream',
'posix/popen',
'posix/system', # This test should be in the ANSI tests, but it depends on sys/wait.h
'posix/sigsuspend',
'posix/sigaltstack',
'posix/time',
'posix/realpath',
'posix/ffs',
'posix/getcwd',
'posix/memrchr',
'posix/wordexp',
'posix/rlimits',
'posix/accept4',
'posix/setpriority',
'posix/nice',
'posix/alarm',
'posix/abort', # This test should be in the ANSI tests, but it depends on sigaction
'posix/timer',
'posix/vfork',
'posix/wcwidth',
'posix/pause',
'posix/flockfile',
'posix/basename',
'posix/regex',
'posix/sigtimedwait',
'posix/if_indextoname',
'posix/readv-writev',
'posix/posix-timer',
'posix/strdupa',
'posix/mkstemp',
'posix/waitid',
'posix/usershell',
'posix/shm',
'posix/swab',
'glibc/getopt',
'glibc/ffsl-ffsll',
'glibc/error_message_count',
'glibc/error_one_per_line',
'glibc/error_print_progname',
'glibc/error_expect_fail',
'glibc/error',
'glibc/error_at_line',
'glibc/getgrouplist',
'glibc/rpmatch',
'linux/xattr',
'linux/pthread_setname_np',
'linux/pthread_attr',
'linux/cpuset',
'linux/malloc-usable-size',
'linux/getifaddrs',
'linux/pidfd',
'linux/timerfd',
'linux/ppoll',
'linux/utmp',
'linux/utmpx',
]
if host_machine.system() == 'linux'
all_test_cases += 'glibc/linux-syscall'
endif
# We only add some tests if the target is the same as the build machine.
if build_machine.cpu_family() == target_machine.cpu_family()
# process_vm_readv_writev can only run natively beacuse qemu-user doesn't support these syscalls.
all_test_cases += 'linux/process_vm_readv_writev'
endif
fail_test_cases = [
'posix/abort',
'glibc/error_expect_fail',
]
wrapped_test_cases = [
'ansi/tz',
'glibc/error',
'glibc/error_at_line',
]
host_libc_excluded_test_cases = [
'bsd/strl', # These functions do not exist on Linux.
'glibc/error', # These tests depend on mlibc error messages.
'glibc/error_at_line', # These tests depend on mlibc error messages.
'rtld/search-order', # See rtld/search-order/meson.build.
]
host_libc_noasan_test_cases = [
'posix/pthread_cancel',
'posix/pthread_attr', # does some stack overflowing to check stack size
'posix/posix_memalign',
'posix/search', # requires tdelete (#351)
'ansi/calloc', # does some overflowing
'linux/pthread_attr', # encounters memory leaks
]
extra_cflags_test_cases = {
'ansi/calloc': ['-Wno-alloc-size-larger-than'],
}
test_sources = []
test_objects = []
test_link_args = []
test_c_args = ['-D_GNU_SOURCE', '-U__MLIBC_DEBUG', '-U__MLIBC_BUILDING_MLIBC', '-fhosted', '-fno-builtin']
use_pie = false
host_test_c_args = ['-fno-builtin']
c_compiler = meson.get_compiler('c')
if c_compiler.get_id() == 'gcc'
test_c_args += []
host_test_c_args += []
elif c_compiler.get_id() == 'clang'
test_c_args += ['-Wno-unknown-warning-option']
host_test_c_args += ['-Wno-unknown-warning-option']
endif
# Our ubsan implementation can't be used by the tests themselves,
# since it is internal to libc.so and ld.so.
test_override_options = ['b_sanitize=none']
if library_type == 'static'
c_compiler = meson.get_compiler('c')
searchdirs = run_command(c_compiler.cmd_array(), '-print-search-dirs',
check: true).stdout()
searchdirs_arr = searchdirs.split('\n')
searchline = 'libraries: ='
searchpaths = ''
foreach line : searchdirs_arr
if line.startswith(searchline)
searchpaths = line.strip(searchline)
break
endif
endforeach
if searchpaths == ''
error('could not find compiler-specific library directory')
endif
searchpaths_arr = searchpaths.split(':')
crtpath = ''
fs = import('fs')
foreach path : searchpaths_arr
if fs.exists(path / 'crtbegin.o')
crtpath = path
break
endif
endforeach
if crtpath == ''
error('could not find crtbegin.o/crtend.o')
endif
test_objects += [crtpath / 'crtbegin.o', crtpath / 'crtend.o']
libc_dep = declare_dependency(
include_directories: libc_include_dirs,
link_with: libc_static,
dependencies: [libc_deps, rtlib_deps]
)
use_pie = false
test_c_args += '-no-pie'
test_link_args += ['-no-pie', '-static']
test_sources += crt
else
libc_dep = declare_dependency(
include_directories: libc_include_dirs,
link_with: libc_shared,
dependencies: [libc_deps, rtlib_deps]
)
test_link_args += ['-Wl,--dynamic-linker=' + meson.global_build_root() + '/ld.so']
if host_machine.system() in ['linux']
use_pie = true
test_sources += crt_pie
else
use_pie = false
test_sources += crt
# Meson doesn't set these for us (issue #4651).
test_c_args += '-no-pie'
test_link_args += '-no-pie'
endif
# Add the rtld tests.
if posix_option
subdir('rtld')
endif
endif
py = import('python').find_installation('python3')
foreach test_name : all_test_cases
test_subdir = test_name.split('/')[0]
test_short_name = test_name.split('/')[1]
test_exec_name = test_name.replace('/', '-')
if test_subdir == 'bsd' and not bsd_option
continue
elif test_subdir == 'glibc' and not glibc_option
continue
elif test_subdir == 'posix' and not posix_option
continue
elif test_subdir == 'linux' and not linux_option
continue
endif
should_fail = fail_test_cases.contains(test_name)
exec = executable(test_exec_name, [test_name + '.c', test_sources],
dependencies: libc_dep,
objects: test_objects,
build_rpath: meson.global_build_root(),
override_options: test_override_options,
c_args: test_c_args,
link_args: test_link_args,
pie: use_pie,
)
if wrapped_test_cases.contains(test_name)
test(test_short_name,
py,
suite: test_subdir,
should_fail: should_fail,
args: [
meson.global_source_root() + '/tests/' + test_name + '.py',
exec
],
timeout: timeout_sec,
)
else
test(test_short_name, exec, suite: test_subdir, should_fail: should_fail, timeout: timeout_sec)
endif
if build_tests_host_libc and not host_libc_excluded_test_cases.contains(test_name)
if test_name in host_libc_noasan_test_cases
host_libc_sanitize_options = 'b_sanitize=undefined'
else
host_libc_sanitize_options = 'b_sanitize=address,undefined'
endif
if test_name in extra_cflags_test_cases
extra_cflags = extra_cflags_test_cases[test_name]
else
extra_cflags = []
endif
exec = executable('host-libc-' + test_exec_name, test_name + '.c',
build_rpath: meson.global_build_root(),
override_options: host_libc_sanitize_options,
c_args: [host_test_c_args + '-D_GNU_SOURCE', '-DUSE_HOST_LIBC', '-pthread', extra_cflags],
link_args: ['-lresolv', '-ldl', '-pthread', '-lm', '-lrt'],
native: true,
)
if wrapped_test_cases.contains(test_name)
test(test_short_name,
py,
suite: ['host-libc', test_subdir],
should_fail: should_fail,
args: [
meson.source_root() + '/tests/' + test_name + '.py',
exec
],
timeout: timeout_sec,
)
else
test(test_short_name, exec, suite: ['host-libc', test_subdir], should_fail: should_fail, timeout: timeout_sec)
endif
endif
endforeach
+21
View File
@@ -0,0 +1,21 @@
#include <signal.h>
#include <assert.h>
#include <stdlib.h>
void handler(int sig, siginfo_t *info, void *ctx) {
(void)sig;
(void)info;
(void)ctx;
}
int main() {
struct sigaction sa;
sa.sa_sigaction = handler;
sa.sa_flags = SA_SIGINFO;
sigemptyset(&sa.sa_mask);
int ret = sigaction(SIGABRT, &sa, NULL);
assert(!ret);
abort();
}
+125
View File
@@ -0,0 +1,125 @@
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <errno.h>
#ifdef USE_HOST_LIBC
#define TEST_PORT 31337
#else
#define TEST_PORT 42069
#endif
static struct sockaddr_in connect_addr, accept_addr;
static int listen_fd;
int permutations[] = {
0,
SOCK_CLOEXEC,
SOCK_NONBLOCK,
SOCK_CLOEXEC | SOCK_NONBLOCK,
};
static bool run_test(int flags)
{
int connect_fd;
int fd_flags, access;
socklen_t addrlen;
connect_fd = socket(AF_INET, SOCK_STREAM, 0);
connect(connect_fd, (struct sockaddr *)&connect_addr, sizeof(connect_addr));
addrlen = sizeof(accept_addr);
int accept_fd = accept4(listen_fd, (struct sockaddr *)&accept_addr, &addrlen, flags);
if(accept_fd == -1) {
fprintf(stderr, "accept4 failed: %s\n", strerror(errno));
goto cleanup;
}
fd_flags = fcntl(accept_fd, F_GETFD);
if(!(!!(fd_flags & FD_CLOEXEC) == !!(flags & SOCK_CLOEXEC))) {
fprintf(stderr, "CLOEXEC mismatch, got %d instead of %d\n", !!(fd_flags & FD_CLOEXEC), !!(flags & SOCK_CLOEXEC));
goto cleanup;
}
access = fcntl(accept_fd, F_GETFL);
if(!(!!(access & O_NONBLOCK) == !!(flags & SOCK_NONBLOCK))) {
fprintf(stderr, "NONBLOCK flag mismatch, %d vs %d\n", !!(access & O_NONBLOCK), !!(flags & SOCK_NONBLOCK));
goto cleanup;
}
close(accept_fd);
close(connect_fd);
fprintf(stderr, "tested CLOEXEC %d, NONBLOCK %d\n", !!(flags & SOCK_CLOEXEC), !!(flags & SOCK_NONBLOCK));
return true;
cleanup:
close(accept_fd);
close(connect_fd);
return false;
}
static int socket_setup(void)
{
struct sockaddr_in addr;
int reuseaddr;
memset(&addr, 0, sizeof(struct sockaddr_in));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(TEST_PORT);
int socket_fd = socket(AF_INET, SOCK_STREAM, 0);
if(socket_fd == -1) {
fprintf(stderr, "socket failed: %s\n", strerror(errno));
exit(1);
}
reuseaddr = 1;
int ret = setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof(reuseaddr));
if(ret == -1) {
fprintf(stderr, "setsockopt failed: %s\n", strerror(errno));
exit(1);
}
ret = bind(socket_fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in));
if(ret == -1) {
fprintf(stderr, "bind failed: %s\n", strerror(errno));
exit(1);
}
ret = listen(socket_fd, 5);
if(ret == -1) {
fprintf(stderr, "listen failed: %s\n", strerror(errno));
exit(1);
}
return socket_fd;
}
int main() {
memset(&connect_addr, 0, sizeof(connect_addr));
connect_addr.sin_family = AF_INET;
connect_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
connect_addr.sin_port = htons(TEST_PORT);
for(size_t i = 0; i < 4; i++) {
listen_fd = socket_setup();
if(!run_test(permutations[i])) {
exit(1);
}
close(listen_fd);
}
return 0;
}
+32
View File
@@ -0,0 +1,32 @@
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <fcntl.h>
#ifdef USE_HOST_LIBC
#define TEST_FILE "access-host-libc.tmp"
#else
#define TEST_FILE "access.tmp"
#endif
int main() {
// Make sure that it wasn't created by a previous test run
unlink(TEST_FILE);
assert(access(TEST_FILE, F_OK) == -1);
assert(access(TEST_FILE, W_OK) == -1);
assert(access(TEST_FILE, R_OK) == -1);
assert(access(TEST_FILE, X_OK) == -1);
close(open(TEST_FILE, O_CREAT | O_RDWR, 0666));
assert(access(TEST_FILE, F_OK) == 0);
assert(access(TEST_FILE, W_OK) == 0);
assert(access(TEST_FILE, R_OK) == 0);
assert(access(TEST_FILE, X_OK) == -1);
unlink(TEST_FILE);
return 0;
}
+36
View File
@@ -0,0 +1,36 @@
#include <signal.h>
#include <assert.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
static volatile int alarms_fired = 0;
static void sigalrm_handler(int signal) {
if(signal == SIGALRM)
alarms_fired++;
}
int main() {
signal(SIGALRM, sigalrm_handler);
alarms_fired = 0;
unsigned int ret = alarm(10);
assert(!ret);
sleep(1);
ret = alarm(1);
assert(ret == 9);
sleep(2);
if(alarms_fired != 1) {
fprintf(stderr, "alarm handler fired %u times instead of 1\n", alarms_fired);
exit(1);
}
return 0;
}
+19
View File
@@ -0,0 +1,19 @@
#include <assert.h>
#include <libgen.h>
#include <string.h>
int main() {
/* intentionally a macro: basename modifies its argument */
#define test_string(x, expectval) do { \
char str[] = x; \
assert(strcmp(basename(str), expectval) == 0); \
} while (0)
test_string("/usr/lib", "lib");
test_string("/usr/", "usr");
test_string("/", "/");
test_string(".", ".");
test_string("..", "..");
return 0;
}
+39
View File
@@ -0,0 +1,39 @@
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <assert.h>
#include <errno.h>
#ifdef USE_HOST_LIBC
#define TEST_FILE "dprintf-host-libc.tmp"
#else
#define TEST_FILE "dprintf.tmp"
#endif
int main() {
int fd = open(TEST_FILE, O_RDWR | O_CREAT, 0666);
assert(fd > -1);
int ret = dprintf(fd, "aaa");
assert(ret == 3);
// Check if we can read back the same things.
// Also checks to see if the fd is still open,
// which is issue #199.
off_t seek = lseek(fd, 0, SEEK_SET);
assert(seek == 0);
char buf[3];
ssize_t num_read = read(fd, buf, 3);
assert(num_read == 3);
assert(buf[0] == 'a'
&& buf[1] == 'a'
&& buf[2] == 'a');
// All the tests pass, now we can unlink the file.
ret = unlink(TEST_FILE);
assert(ret == 0);
return 0;
}
+39
View File
@@ -0,0 +1,39 @@
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#define TEST_FILE "fdopen.tmp"
int main() {
int fd = open(TEST_FILE, O_CREAT | O_RDWR, 0666);
assert(fd >= 0);
char *str = "mlibc fdopen test";
assert(write(fd, str, strlen(str)));
// Seek to the beginning, then reopen with fdopen in append mode.
lseek(fd, 0, SEEK_SET);
FILE *file = fdopen(fd, "a");
assert(file);
// Append and close.
str = " appended";
fwrite(str, strlen(str), 1, file);
fflush(file);
fclose(file);
// Open it again and check that the append succeeded.
fd = open(TEST_FILE, O_RDONLY);
assert(fd >= 0);
file = fdopen(fd, "r");
assert(file);
str = "mlibc fdopen test appended";
char buf[100] = {0};
assert(fread(buf, 1, strlen(str), file));
assert(!strcmp(buf, str));
fclose(file);
return 0;
}
+18
View File
@@ -0,0 +1,18 @@
#include <assert.h>
#include <strings.h>
#include <limits.h>
int main(void){
assert(ffs(0x8000) == 16);
assert(ffs(0) == 0);
assert(ffs(INT_MAX - 1) == 2);
assert(ffs(INT_MAX) == 1);
assert(ffs(INT_MIN) == (int)(sizeof(int) * CHAR_BIT));
assert(ffs(INT_MIN + 1) == 1);
for (int i = 1; i < 0x1000; i++) {
assert(ffs(i) - 1 == __builtin_ctz(i));
}
return 0;
}
@@ -0,0 +1,35 @@
#include <assert.h>
#include <time.h>
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
static void *worker(void *arg) {
(void)arg;
flockfile(stdout);
fputs_unlocked("hello from worker", stdout);
funlockfile(stdout);
return NULL;
}
int main() {
// Check that recursive locking works.
assert(!ftrylockfile(stdout));
flockfile(stdout);
flockfile(stdout);
funlockfile(stdout);
funlockfile(stdout);
funlockfile(stdout);
assert(!ftrylockfile(stdout));
pthread_t thread;
int ret = pthread_create(&thread, NULL, &worker, NULL);
assert(!ret);
sleep(1);
funlockfile(stdout);
assert(!pthread_join(thread, NULL));
return 0;
}
+150
View File
@@ -0,0 +1,150 @@
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUFFER0_SIZE 0x1000
#define BUFFER1 "Hello world"
#define BUFFER1_SIZE (sizeof(BUFFER1))
int main() {
// test seek with mode "r"
FILE *f = fmemopen(NULL, BUFFER0_SIZE, "r");
assert(f);
int ret = fseek(f, 0, SEEK_END);
assert(!ret);
long pos = ftell(f);
fprintf(stderr, "pos = %ld\n", pos);
// Despite the fact that this is correct behavior (see below),
// this sometimes fails on glibc; newlib seems to get this wrong, too.
// to quote what posix says about it:
// > The stream shall also maintain the size of the current buffer contents;
// > use of fseek() or fseeko() on the stream with SEEK_END shall seek relative to this size.
// > For modes r and r+ the size shall be set to the value given by the size argument.
#if !defined(__GLIBC__)
assert(pos == BUFFER0_SIZE);
#endif
fclose(f);
// test seek with mode "w"
f = fmemopen(NULL, BUFFER0_SIZE, "w");
assert(f);
ret = fseek(f, 0, SEEK_END);
assert(!ret);
pos = ftell(f);
assert(pos == 0);
fclose(f);
// test seek with mode "a" and a NULL buffer
f = fmemopen(NULL, BUFFER0_SIZE, "a");
assert(f);
ret = fseek(f, 0, SEEK_END);
assert(!ret);
pos = ftell(f);
assert(pos == 0);
fclose(f);
// test seek with mode "a" and a buffer containing a '\0'
f = fmemopen(BUFFER1, BUFFER1_SIZE + 2, "a");
assert(f);
pos = ftell(f);
assert(pos == (long) (BUFFER1_SIZE - 1));
ret = fseek(f, 0, SEEK_SET);
assert(!ret);
pos = ftell(f);
assert(!pos);
ret = fseek(f, 0, SEEK_END);
assert(!ret);
pos = ftell(f);
assert(pos == (long) (BUFFER1_SIZE - 1));
fclose(f);
// test seek with mode "a" and a buffer not containing a '\0'
f = fmemopen(BUFFER1, BUFFER1_SIZE - 2, "a");
assert(f);
ret = fseek(f, 0, SEEK_END);
assert(!ret);
pos = ftell(f);
assert(pos == (long) (BUFFER1_SIZE - 2));
fclose(f);
f = fmemopen(BUFFER1, BUFFER1_SIZE, "r");
assert(f);
ret = fseek(f, 0, SEEK_SET);
assert(!ret);
char buf[BUFFER1_SIZE];
int read = fread(buf, 1, BUFFER1_SIZE - 2, f);
assert(read == BUFFER1_SIZE - 2);
assert(!strncmp(BUFFER1, buf, BUFFER1_SIZE - 2));
fseek(f, 0, SEEK_END);
read = fread(buf, 1, 2, f);
assert(read == 0);
assert(feof(f));
fclose(f);
// Open a buffer for read+write
char *buf1 = strdup(BUFFER1);
f = fmemopen(buf1, BUFFER1_SIZE, "w+");
assert(f);
assert(strlen(BUFFER1) == BUFFER1_SIZE - 1);
// seek to somewhere in the middle of the buffer
fseek(f, BUFFER1_SIZE - 5, SEEK_SET);
// write as much data to it as possible
read = fwrite(BUFFER1, 1, 9, f);
rewind(f);
// seek the the same position in the middle of the buffer
ret = fseek(f, BUFFER1_SIZE - 5, SEEK_SET);
assert(!ret);
memset(buf, 0, BUFFER1_SIZE);
// read what we just wrote
read = fread(buf, 1, 5, f);
// check that the write got correctly truncated
fprintf(stderr, "buf '%s' (%zu)\n", buf, strlen(buf));
assert(!strncmp(BUFFER1, buf, 4) && strlen(buf) == 4);
fclose(f);
free(buf1);
char *buf2 = strdup(BUFFER1);
f = fmemopen(buf2, 0, "r");
assert(f || errno == EINVAL);
if(f) {
memset(buf, 0, BUFFER1_SIZE);
read = fread(buf, 10, 1, f);
assert(!read);
rewind(f);
read = fwrite(BUFFER1, 1, 12, f);
assert(read == 0);
fclose(f);
}
free(buf2);
return 0;
}
@@ -0,0 +1,71 @@
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <assert.h>
#include <stdbool.h>
#include <stdio.h>
struct testcookie {
bool read;
bool write;
bool seek;
bool close;
};
ssize_t cookie_read(void *c, char *buf, size_t size) {
(void) buf;
struct testcookie *cookie = c;
cookie->read = true;
return size;
}
ssize_t cookie_write(void *c, const char *buf, size_t size) {
(void) buf;
struct testcookie *cookie = c;
cookie->write = true;
return size;
}
int cookie_seek(void *c, off64_t *offset, int whence) {
(void) offset;
(void) whence;
struct testcookie *cookie = c;
cookie->seek = true;
return 0;
}
int cookie_close(void *c) {
struct testcookie *cookie = c;
cookie->close = true;
return 0;
}
int main() {
struct testcookie cookie = { false, false, false, false };
cookie_io_functions_t funcs = {
.read = cookie_read,
.write = cookie_write,
.seek = cookie_seek,
.close = cookie_close,
};
FILE *stream = fopencookie(&cookie, "w+", funcs);
assert(stream);
unsigned char buf[1];
int ret = fread(buf, 1, 1, stream);
assert(ret == 1);
ret = fwrite(buf, 1, 1, stream);
assert(ret == 1);
ret = fseek(stream, 0, SEEK_SET);
assert(!ret);
ret = fclose(stream);
assert(!ret);
assert(cookie.read && cookie.write && cookie.seek && cookie.close);
return 0;
}
@@ -0,0 +1,235 @@
#if !defined(USE_HOST_LIBC)
#include <mlibc-config.h>
#endif
#include <netdb.h>
#include <assert.h>
#include <stdbool.h>
#include <stddef.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <net/if.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#if __MLIBC_LINUX_OPTION || defined(USE_HOST_LIBC)
#include <ifaddrs.h>
static bool has_ipv4_addr(void) {
struct ifaddrs *addrs;
if (getifaddrs(&addrs)) {
return false;
}
int found = 0;
for (struct ifaddrs *cur = addrs; cur; cur = cur->ifa_next) {
if (cur->ifa_addr && (cur->ifa_flags & IFF_UP) && cur->ifa_addr->sa_family == AF_INET && strncmp(cur->ifa_name, "lo", IF_NAMESIZE)) {
found = 1;
break;
}
}
freeifaddrs(addrs);
return found;
}
static bool has_ipv6_addr(void) {
struct ifaddrs *addrs;
if (getifaddrs(&addrs)) {
return false;
}
int found = 0;
for (struct ifaddrs *cur = addrs; cur; cur = cur->ifa_next) {
if (cur->ifa_addr && (cur->ifa_flags & IFF_UP) && cur->ifa_addr->sa_family == AF_INET6 && strncmp(cur->ifa_name, "lo", IF_NAMESIZE)) {
found = 1;
break;
}
}
freeifaddrs(addrs);
return found;
}
#endif // __MLIBC_LINUX_OPTION || defined(USE_HOST_LIBC)
int main() {
struct addrinfo *res = NULL;
struct addrinfo hints = {0};
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
int ret = getaddrinfo(NULL, "443", &hints, &res);
assert(ret == 0);
struct sockaddr_in *addr = (struct sockaddr_in*)(res[0].ai_addr);
assert(addr->sin_port == htons(443));
assert(res[0].ai_socktype == SOCK_STREAM);
assert(res[0].ai_protocol == IPPROTO_TCP);
freeaddrinfo(res);
res = NULL;
/* check we can resolve any domain */
ret = getaddrinfo("example.net", NULL, &hints, &res);
assert(ret == 0);
freeaddrinfo(res);
res = NULL;
hints.ai_flags = AI_NUMERICHOST;
ret = getaddrinfo("10.10.10.10", NULL, &hints, &res);
assert(ret == 0);
addr = (struct sockaddr_in*)res[0].ai_addr;
assert((addr->sin_addr.s_addr & 0xFF) == 10);
assert(((addr->sin_addr.s_addr >> 8) & 0xFF) == 10);
assert(((addr->sin_addr.s_addr >> 16) & 0xFF) == 10);
assert(((addr->sin_addr.s_addr >> 24) & 0xFF) == 10);
freeaddrinfo(res);
res = NULL;
ret = getaddrinfo("example.net", NULL, &hints, &res);
assert(ret == EAI_NONAME);
freeaddrinfo(res);
res = NULL;
hints.ai_family = AF_INET6;
hints.ai_flags = AI_NUMERICHOST;
ret = getaddrinfo("::1", "1234", &hints, &res);
assert(ret == 0);
assert(res[0].ai_family == AF_INET6);
struct sockaddr_in6 *addr6 = (struct sockaddr_in6*) res[0].ai_addr;
assert(addr6->sin6_port == htons(1234));
assert(addr6->sin6_addr.s6_addr[15] == 1);
for (int i = 0; i < 15; i++) {
assert(addr6->sin6_addr.s6_addr[i] == 0);
}
freeaddrinfo(res);
res = NULL;
hints.ai_family = AF_INET6;
hints.ai_flags = 0;
ret = getaddrinfo("example.net", "443", &hints, &res);
assert(ret == 0);
assert(res[0].ai_family == AF_INET6);
addr6 = (struct sockaddr_in6*)res[0].ai_addr;
assert(addr6->sin6_port == htons(443));
freeaddrinfo(res);
res = NULL;
#if __MLIBC_LINUX_OPTION || defined(USE_HOST_LIBC)
// Test with AF_INET
hints.ai_family = AF_INET;
ret = getaddrinfo("localhost", NULL, &hints, &res);
if (has_ipv4_addr()) {
assert(ret == 0);
for(struct addrinfo *p = res; p != NULL; p = p->ai_next) {
assert(p->ai_family == AF_INET);
}
} else {
assert(ret != 0);
}
freeaddrinfo(res);
res = NULL;
// Test with AF_INET6
hints.ai_family = AF_INET6;
ret = getaddrinfo("localhost", NULL, &hints, &res);
assert(ret == 0);
for(struct addrinfo *p = res; p != NULL; p = p->ai_next) {
assert(p->ai_family == AF_INET6);
}
freeaddrinfo(res);
res = NULL;
// Test AI_ADDRCONFIG
hints = (struct addrinfo){0};
hints.ai_flags = AI_ADDRCONFIG;
hints.ai_family = AF_UNSPEC;
ret = getaddrinfo("localhost", NULL, &hints, &res);
if (ret == 0) {
int found_ipv4 = 0;
int found_ipv6 = 0;
for(struct addrinfo *p = res; p != NULL; p = p->ai_next) {
if (p->ai_family == AF_INET)
found_ipv4 = 1;
else if (p->ai_family == AF_INET6)
found_ipv6 = 1;
}
if (has_ipv4_addr())
assert(found_ipv4);
else
assert(!found_ipv4);
if (has_ipv6_addr())
assert(found_ipv6);
else
assert(!found_ipv6);
} else {
// If getaddrinfo fails, it should be because no addresses are configured.
assert(!has_ipv4_addr() && !has_ipv6_addr());
}
freeaddrinfo(res);
res = NULL;
#endif // __MLIBC_LINUX_OPTION || defined(USE_HOST_LIBC)
// Test AI_NUMERICSERV.
hints = (struct addrinfo){0};
hints.ai_flags = AI_NUMERICSERV;
hints.ai_family = AF_INET;
ret = getaddrinfo(NULL, "8080", &hints, &res);
assert(ret == 0);
assert(res->ai_family == AF_INET);
struct sockaddr_in *addr_in = (struct sockaddr_in *)res->ai_addr;
assert(addr_in->sin_port == htons(8080));
freeaddrinfo(res);
res = NULL;
ret = getaddrinfo(NULL, "http", &hints, &res);
assert(ret == EAI_NONAME);
assert(res == NULL);
hints.ai_family = AF_INET6;
ret = getaddrinfo(NULL, "9090", &hints, &res);
assert(ret == 0);
assert(res->ai_family == AF_INET6);
struct sockaddr_in6 *addr_in6 = (struct sockaddr_in6 *)res->ai_addr;
assert(addr_in6->sin6_port == htons(9090));
freeaddrinfo(res);
res = NULL;
ret = getaddrinfo(NULL, "https", &hints, &res);
assert(ret == EAI_NONAME);
assert(res == NULL);
// Test for NXDOMAIN
hints = (struct addrinfo){0};
ret = getaddrinfo("this-domain-should-not-exist.nxdomain", NULL, &hints, &res);
assert(ret == EAI_NONAME);
assert(res == NULL);
// Test AI_CANONNAME.
hints = (struct addrinfo){0};
hints.ai_flags = AI_CANONNAME;
ret = getaddrinfo("localhost.localdomain", NULL, &hints, &res);
assert(ret == 0);
assert(res->ai_canonname);
freeaddrinfo(res);
res = NULL;
return 0;
}
+22
View File
@@ -0,0 +1,22 @@
#include <assert.h>
#include <limits.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
int main() {
char buf[PATH_MAX];
char *ret = getcwd(buf, PATH_MAX);
assert(ret);
assert((strlen(ret) == strlen(buf)) && strlen(ret));
assert(!strcmp(ret, buf));
char *ret2 = getcwd(NULL, 0);
assert(ret2);
assert(strlen(ret2));
assert(!strcmp(ret, ret2));
free(ret2);
return 0;
}
+92
View File
@@ -0,0 +1,92 @@
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <unistd.h>
#include <string.h>
#ifdef USE_HOST_LIBC
#define TEST_FILE "getdelim-host-libc.tmp"
#else
#define TEST_FILE "getdelim.tmp"
#endif
int main(void) {
FILE *fp;
char *line = NULL;
size_t len = 0;
ssize_t read;
// We have to open the file for writing and then reading separately,
// as mlibc doesn't allow us to do both at the same time (yet).
fp = fopen(TEST_FILE, "w");
assert(fp);
fputs("foo\nbar\nbaz\nquux\n", fp);
fclose(fp);
fp = fopen(TEST_FILE, "r");
assert(fp);
while ((read = getline(&line, &len, fp)) != -1) {
printf("read line of length %zd, capacity %zu\n", read, len);
}
assert(!ferror(fp));
free(line);
fclose(fp);
size_t nchars = 10000;
fp = fopen(TEST_FILE, "w");
assert(fp);
for (size_t i = 0; i < nchars; i++)
fputc('a', fp);
fputc('b', fp);
fclose(fp);
line = NULL;
len = 0;
fp = fopen(TEST_FILE, "r");
assert(fp);
while ((read = getdelim(&line, &len, 'b', fp)) != -1) {
printf("read line of length %zd, capacity %zu\n", read, len);
assert((size_t)read == nchars + 1);
}
assert(len > nchars + 1);
assert(!ferror(fp));
assert(feof(fp));
assert(getdelim(&line, &len, 'b', fp) == -1);
assert(feof(fp));
free(line);
fclose(fp);
fp = fopen(TEST_FILE, "w");
assert(fp);
assert(fwrite("1234ef\0f", 1, 8, fp) == 8);
fclose(fp);
fp = fopen(TEST_FILE, "r");
assert(fp);
/* test with line = NULL and large len */
line = NULL;
len = (size_t) ~0;
assert(getdelim(&line, &len, 'e', fp) == 5);
assert(!memcmp(line, "1234e", 6));
assert(5 < len);
/* test handling of internal nulls */
assert(getdelim(&line, &len, 'e', fp) == 3);
assert(!memcmp(line, "f\0f", 4));
assert(3 < len);
/* test handling of EOF */
assert(getdelim(&line, &len, 'e', fp) == -1);
free(line);
fclose(fp);
// Delete the file
unlink(TEST_FILE);
return 0;
}
@@ -0,0 +1,22 @@
#include <netdb.h>
#include <assert.h>
#include <arpa/inet.h>
#include <stddef.h>
#include <string.h>
int main() {
struct sockaddr_in addr;
addr.sin_family = AF_INET;
assert(inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr));
char host[64];
assert(!getnameinfo((struct sockaddr*)&addr, sizeof(addr), host,
sizeof(host), NULL, 0, 0));
assert(inet_pton(AF_INET, "8.8.8.8", &addr.sin_addr));
assert(!getnameinfo((struct sockaddr*)&addr, sizeof(addr), host,
sizeof(host), NULL, 0, 0));
assert(!strcmp(host, "dns.google"));
return 0;
}
+23
View File
@@ -0,0 +1,23 @@
#include <assert.h>
#include <errno.h>
#include <sched.h>
#include <unistd.h>
int main() {
struct sched_param param = {
.sched_priority = 100,
};
int ret = sched_getparam(getpid(), &param);
assert(!ret);
ret = sched_setparam(getpid(), &param);
assert(ret == 0);
param.sched_priority = 0xD00DFEED;
ret = sched_setparam(getpid(), &param);
assert(ret == -1 && errno == EINVAL);
return 0;
}
@@ -0,0 +1,27 @@
#include <assert.h>
#include <netdb.h>
#include <string.h>
#include <arpa/inet.h>
int main() {
struct servent *ret = getservbyname("http", "tcp");
assert(ret);
assert(!strcmp("http", ret->s_name));
assert(ret->s_port == htons(80));
assert(!strcmp("tcp", ret->s_proto));
ret = getservbyname("http", NULL);
assert(ret);
assert(!strcmp("http", ret->s_name));
assert(ret->s_port == htons(80));
assert(!strcmp("tcp", ret->s_proto));
ret = getservbyname("babel", "udp");
assert(ret);
ret = getservbyname("babel", "tcp");
assert(!ret);
ret = getservbyname("", NULL);
assert(!ret);
return 0;
}
@@ -0,0 +1,28 @@
#include <netdb.h>
#include <arpa/inet.h>
#include <string.h>
#include <assert.h>
#include <stdio.h>
int main() {
struct servent *ret = getservbyport(htons(80), "tcp");
assert(ret);
assert(!strcmp("http", ret->s_name));
assert(ret->s_port == htons(80));
assert(!strcmp("tcp", ret->s_proto));
ret = getservbyport(htons(80), NULL);
assert(ret);
assert(!strcmp("http", ret->s_name));
assert(ret->s_port == htons(80));
assert(!strcmp("tcp", ret->s_proto));
ret = getservbyport(htons(6696), "udp");
assert(ret);
ret = getservbyport(htons(6696), "tcp");
assert(!ret);
ret = getservbyport(htons(0), NULL);
assert(!ret);
return 0;
}
+155
View File
@@ -0,0 +1,155 @@
#include <stdlib.h>
#include <stdio.h>
#include <grp.h>
#include <unistd.h>
#include <assert.h>
#include <string.h>
#include <errno.h>
#include <stdbool.h>
void check_root_group(struct group *grp) {
assert(grp);
printf("group name: %s\n", grp->gr_name);
fflush(stdout);
assert(grp->gr_gid == 0);
assert(!strcmp(grp->gr_name, "root"));
// Depending on your system, the root group may or may not contain the root user.
if (grp->gr_mem[0] != NULL) {
bool found = false;
for (size_t i = 0; grp->gr_mem[i] != NULL; i++) {
printf("group member: %s\n", grp->gr_mem[i]);
fflush(stdout);
if (!strcmp(grp->gr_mem[i], "root")) {
found = true;
break;
}
}
assert(found);
}
}
int main()
{
struct group grp, *result = NULL;
char *buf;
size_t bufsize;
int s;
bool password = false;
char *members[3];
char filename[] = "grpXXXXXX";
int tmpfd;
FILE *tmp;
char *expected = "managarm:passwordhash:12345:managarm,mlibc\n";
size_t readsize;
bufsize = sysconf(_SC_GETGR_R_SIZE_MAX);
assert(bufsize > 0 && bufsize < 0x100000);
buf = malloc(bufsize);
assert(buf);
s = getgrnam_r("root", &grp, buf, bufsize, &result);
assert(!s);
check_root_group(result);
s = getgrgid_r(0, &grp, buf, bufsize, &result);
assert(!s);
check_root_group(result);
result = getgrnam("root");
check_root_group(result);
result = getgrgid(0);
check_root_group(result);
result = getgrnam("this_group_doesnt_exist");
assert(!result);
#ifndef USE_HOST_LIBC
// This is not guaranteed.
assert(errno == ESRCH);
#endif
s = getgrnam_r("this_group_doesnt_exist", &grp, buf, bufsize, &result);
assert(!result);
#ifndef USE_HOST_LIBC
// This is not guaranteed.
assert(s == ESRCH);
#endif
errno = 0;
setgrent();
assert(errno == 0);
result = getgrent();
assert(result);
grp.gr_name = strdup(result->gr_name);
if(result->gr_passwd) {
password = true;
}
grp.gr_passwd = strdup(result->gr_passwd);
grp.gr_gid = result->gr_gid;
assert(grp.gr_name);
if(password)
assert(grp.gr_passwd);
assert(grp.gr_name);
if(password)
assert(grp.gr_passwd);
endgrent();
result = getgrent();
assert(result);
assert(strcmp(result->gr_name, grp.gr_name) == 0);
if(password)
assert(strcmp(result->gr_passwd, grp.gr_passwd) == 0);
assert(result->gr_gid == grp.gr_gid);
free(grp.gr_name);
if(password)
free(grp.gr_passwd);
grp.gr_name = "managarm";
grp.gr_passwd = "passwordhash";
grp.gr_gid = 12345;
members[0] = "managarm";
members[1] = "mli:bc";
members[2] = NULL;
grp.gr_mem = members;
// tmpfile() cannot be used because its unimplemented in mlibc.
tmpfd = mkstemp(filename);
assert(tmpfd);
tmp = fdopen(tmpfd, "w+");
assert(tmp);
assert(putgrent(NULL, tmp) < 0);
assert(putgrent(&grp, tmp) < 0);
members[1] = "mlibc";
grp.gr_name = "mana:garm";
assert(putgrent(&grp, tmp) < 0);
grp.gr_name = "managarm";
grp.gr_passwd = "passwordhash\n";
assert(putgrent(&grp, tmp) < 0);
grp.gr_passwd = "passwordhash";
assert(putgrent(&grp, tmp) == 0);
rewind(tmp);
readsize = fread(buf, 1, bufsize, tmp);
assert(readsize == strlen(expected));
assert(strncmp(expected, buf, strlen(expected)) == 0);
fclose(tmp);
unlink(filename);
free(buf);
return 0;
}
@@ -0,0 +1,13 @@
#include <assert.h>
#include <net/if.h>
#include <stdio.h>
int main() {
char name[IF_NAMESIZE];
assert(name == if_indextoname(1, name));
printf("test: name '%s'\n", name);
assert(1 == if_nametoindex(name));
return 0;
}
+20
View File
@@ -0,0 +1,20 @@
#include <assert.h>
#include <strings.h>
#include <stddef.h>
int main() {
char str[] = "This is a sample string";
char *pch;
// The character 's' is at position 4, 7, 11 and 18
pch = index(str, 's');
assert(pch - str + 1 == 4);
pch = index(pch + 1, 's');
assert(pch - str + 1 == 7);
pch = index(pch + 1, 's');
assert(pch - str + 1 == 11);
pch = index(pch + 1, 's');
assert(pch - str + 1 == 18);
pch = index(pch + 1, 's');
assert(pch == NULL);
return 0;
}
@@ -0,0 +1,30 @@
#include <arpa/inet.h>
#include <stdio.h>
#include <assert.h>
#include <string.h>
int main() {
struct in_addr addr;
addr.s_addr = (1 << 24) |
(1 << 16) | (1 << 8) | 1;
char buf[INET_ADDRSTRLEN];
assert(inet_ntop(AF_INET, &addr, buf, INET_ADDRSTRLEN) != NULL);
assert(strncmp("1.1.1.1", buf, INET_ADDRSTRLEN) == 0);
struct in6_addr addr2 = { .s6_addr = {0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0, 0, 0x1, 0, 0, 0, 0, 0, 0x1} };
char buf2[INET6_ADDRSTRLEN];
assert(inet_ntop(AF_INET6, &addr2, buf2, INET6_ADDRSTRLEN) != NULL);
assert(strncmp("2001:db8::1:0:0:1", buf2, INET6_ADDRSTRLEN) == 0);
struct in6_addr addr3 = { .s6_addr = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1} };
char buf3[INET6_ADDRSTRLEN];
assert(inet_ntop(AF_INET6, &addr3, buf3, INET6_ADDRSTRLEN) != NULL);
assert(strncmp("::1", buf3, INET6_ADDRSTRLEN) == 0);
struct in6_addr addr4 = { .s6_addr = {0x20, 0x1, 0xd, 0xb8, 00, 00, 00, 0x1, 00, 0x1, 00, 0x1, 00, 0x1, 00, 0x1} };
char buf4[INET6_ADDRSTRLEN];
assert(inet_ntop(AF_INET6, &addr4, buf4, INET6_ADDRSTRLEN) != NULL);
assert(strncmp("2001:db8:0:1:1:1:1:1", buf4, INET6_ADDRSTRLEN) == 0);
return 0;
}
+136
View File
@@ -0,0 +1,136 @@
#include <arpa/inet.h>
#include <assert.h>
#include <string.h>
int main() {
struct in_addr addr;
assert(inet_pton(AF_INET, "1.1.1.1", &addr));
assert((addr.s_addr & 0xFF) == 1);
assert(((addr.s_addr >> 8) & 0xFF) == 1);
assert(((addr.s_addr >> 16) & 0xFF) == 1);
assert(((addr.s_addr >> 24) & 0xFF) == 1);
assert(!inet_pton(AF_INET, "256.999.1234.555", &addr));
assert(!inet_pton(AF_INET, "a.b.c.d", &addr));
struct in6_addr test6;
{
struct in6_addr addr6 = {
.s6_addr = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01
},
};
int ret = inet_pton(AF_INET6, "::1", &test6);
assert(ret == 1);
assert(!memcmp(&addr6, &test6, sizeof(addr6)));
}
memset(&test6, 0, sizeof(test6));
{
struct in6_addr addr6 = {
.s6_addr16 = {
htons(0x2606), htons(0x4700), htons(0x4700), htons(0x00), htons(0x00), htons(0x00), htons(0x00), htons(0x1111)
},
};
int ret = inet_pton(AF_INET6, "2606:4700:4700::1111", &test6);
assert(ret == 1);
assert(!memcmp(&addr6, &test6, sizeof(addr6)));
}
memset(&test6, 0, sizeof(test6));
{
struct in6_addr addr6 = {
.s6_addr16 = {
htons(0x2606), htons(0x4700), htons(0x4700), htons(0x00), htons(0x00), htons(0x00), htons(0x00), htons(0x1111)
},
};
int ret = inet_pton(AF_INET6, "2606:4700:4700:0000:0000:0000:0000:1111", &test6);
assert(ret == 1);
assert(!memcmp(&addr6, &test6, sizeof(addr6)));
}
memset(&test6, 0, sizeof(test6));
{
struct in6_addr addr6 = {
.s6_addr16 = {
0, 0, 0, 0, 0, 0, 0, 0
},
};
int ret = inet_pton(AF_INET6, "::", &test6);
assert(ret == 1);
assert(!memcmp(&addr6, &test6, sizeof(addr6)));
}
memset(&test6, 0, sizeof(test6));
{
int ret = inet_pton(AF_INET6, "mlibc::", &test6);
assert(!ret);
}
memset(&test6, 0, sizeof(test6));
{
struct in6_addr addr6 = {
.s6_addr = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0xFF, 0xFF, 204, 152, 189, 116,
},
};
int ret = inet_pton(AF_INET6, "::FFFF:204.152.189.116", &test6);
assert(ret == 1);
assert(!memcmp(&addr6, &test6, sizeof(addr6)));
}
memset(&test6, 0, sizeof(test6));
{
int ret = inet_pton(AF_INET6, "::FFFF:204.152.189.", &test6);
assert(!ret);
}
memset(&test6, 0, sizeof(test6));
{
int ret = inet_pton(AF_INET6, "::FFFF:204.152.189.420", &test6);
assert(!ret);
}
memset(&test6, 0, sizeof(test6));
{
int ret = inet_pton(AF_INET6, "::FFFF:204.152.420.69", &test6);
assert(!ret);
}
memset(&test6, 0, sizeof(test6));
{
int ret = inet_pton(AF_INET6, "1100::FFFF:204.152.189.116", &test6);
(void) ret;
#if !defined(USE_HOST_LIBC)
assert(!ret);
#endif
}
memset(&test6, 0, sizeof(test6));
{
struct in6_addr addr6 = {
.s6_addr = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0xFF, 0xFF, 204, 152, 189, 116,
},
};
int ret = inet_pton(AF_INET6, "0000:0000:0000:0000:0000:FFFF:204.152.189.116", &test6);
assert(ret == 1);
assert(!memcmp(&addr6, &test6, sizeof(addr6)));
}
return 0;
}
+25
View File
@@ -0,0 +1,25 @@
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <stdio.h>
#include <string.h>
#include <assert.h>
int main () {
char str[] = "The Last Supper by Leonardo da Vinci";
char *str_temp;
// Test strstr
str_temp = strstr(str, "Supper"); /* Find a substring in the string */
assert(!strcmp(str_temp, "Supper by Leonardo da Vinci"));
/* Following calls use memory APIs for the above tasks */
// Test memchr
str_temp = (char *)memchr((void *)str, 'L', strlen(str));
assert(!strcmp(str_temp, "Last Supper by Leonardo da Vinci"));
// Test memrchr
str_temp = (char *)memrchr((void *)str, 'L', strlen(str));
assert(!strcmp(str_temp, "Leonardo da Vinci"));
return 0;
}
+72
View File
@@ -0,0 +1,72 @@
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
void validate_pattern(char *p) {
assert(memcmp(p, "XXXXXX", 6));
assert(memchr(p, 0, 6) == NULL);
for (int i = 0; i < 6; i++) {
assert(isalnum(p[i]));
}
}
int main() {
int ret;
// Make sure the patterns themselves cannot be chosen. This
// *could* happen on glibc, or if we widen the character set
// used for generating random names. Odds are 1 in 60 billion,
// but I'd rather not worry about this.
ret = open("prefixXXXXXX", O_RDWR | O_CREAT | O_EXCL, 0600);
assert(ret >= 0 || (ret == -1 && errno == EEXIST));
ret = open("longprefixXXXXXXlongsuffix", O_RDWR | O_CREAT | O_EXCL, 0600);
assert(ret >= 0 || (ret == -1 && errno == EEXIST));
ret = mkstemp("short");
assert(ret == -1);
assert(errno == EINVAL);
ret = mkstemp("lessthan6XXX");
assert(ret == -1);
assert(errno == EINVAL);
ret = mkstemps("lessthan6XXXswithsuffix", 11);
assert(ret == -1);
assert(errno == EINVAL);
char *p = strdup("prefixXXXXXX");
ret = mkstemp(p);
// We can't really protect against EEXIST...
assert(ret >= 0 || (ret == -1 && errno == EEXIST));
assert(!memcmp(p, "prefix", 6));
assert(p[12] == 0);
validate_pattern(p + 6);
if (ret >= 0) {
ret = close(ret);
assert(!ret);
}
free(p);
p = strdup("longprefixXXXXXXlongsuffix");
ret = mkstemps(p, 10);
// We can't really protect against EEXIST...
assert(ret >= 0 || (ret == -1 && errno == EEXIST));
assert(!memcmp(p, "longprefix", 10));
assert(!memcmp(p + 16, "longsuffix", 10));
assert(p[26] == 0);
validate_pattern(p + 10);
if (ret >= 0) {
ret = close(ret);
assert(!ret);
}
free(p);
return 0;
}
+37
View File
@@ -0,0 +1,37 @@
#include <assert.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/resource.h>
#include <unistd.h>
#include <limits.h>
int main() {
errno = 0;
int original_priority = nice(0);
assert(original_priority != -1 || !errno);
errno = 0;
int ret = nice(1);
if(ret == -1 && errno) {
fprintf(stderr, "%s", strerror(errno));
exit(1);
}
errno = 0;
int new_priority = nice(0);
assert(new_priority != -1 || !errno);
assert(new_priority == original_priority + 1);
errno = 0;
new_priority = nice(INT_MAX - new_priority);
assert(new_priority != -1 || !errno);
assert(new_priority != INT_MAX);
return 0;
}
@@ -0,0 +1,65 @@
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#define WRITE_NO 1024
int main() {
size_t size;
char *buf;
FILE *fp = open_memstream(&buf, &size);
assert(fp);
char c = 'A';
for (size_t i = 0; i < WRITE_NO; i++)
assert(fwrite(&c, sizeof(char), 1, fp) == 1);
// Flush the file to update the pointers.
assert(!fflush(fp));
assert(size == WRITE_NO);
for (size_t i = 0; i < size; i++)
assert(buf[i] == c);
// Check if the stream maintains a null-bye at the end.
assert(buf[size] == '\0');
// Stream should be expanded, size should be == 2*WRITE_NO.
assert(!fseek(fp, WRITE_NO, SEEK_END));
assert(!fflush(fp));
assert(size == 2*WRITE_NO);
assert(buf[size] == '\0');
// Check if it's filled with zero's.
for (size_t i = WRITE_NO; i < size; i++)
assert(buf[i] == '\0');
// Go back and overwrite the 0's with 'B'.
assert(!fseek(fp, -WRITE_NO, SEEK_CUR));
c = 'B';
for (size_t i = 0; i < WRITE_NO; i++)
assert(fwrite(&c, sizeof(char), 1, fp) == 1);
// Check if that happened.
assert(size == 2*WRITE_NO);
for (size_t i = WRITE_NO; i < size; i++)
assert(buf[i] == c);
assert(buf[size] == '\0');
// Go to the front and write 'B'.
assert(!fseek(fp, 0, SEEK_SET));
for (size_t i = 0; i < WRITE_NO; i++)
assert(fwrite(&c, sizeof(char), 1, fp) == 1);
// Check if that happened.
assert(size == 2*WRITE_NO);
for (size_t i = 0; i < size; i++)
assert(buf[i] == c);
assert(buf[size] == '\0');
// Close the file, we have tested everything.
assert(!fclose(fp));
free(buf);
return 0;
}
+49
View File
@@ -0,0 +1,49 @@
#include <assert.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <sys/wait.h>
static void noop(int x) {
(void)x;
}
int main() {
signal(SIGUSR1, &noop);
int pid;
switch(pid = fork()) {
case -1:
perror("fork");
abort();
case 0:
pause();
assert(errno == EINTR);
return 0;
default:
while (1) {
usleep(100);
kill(pid, SIGUSR1);
usleep(100);
int status;
errno = 0;
if (waitpid(-1, &status, WNOHANG) <= 0) {
if (errno && errno != EAGAIN) {
perror("wait");
kill(pid, SIGKILL);
}
continue;
}
if (!WIFEXITED(status)) {
printf("wait returned %x\n", status);
abort();
}
return WEXITSTATUS(status);
}
}
}
+42
View File
@@ -0,0 +1,42 @@
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <unistd.h>
#ifdef USE_HOST_LIBC
#define TEST_FILE "popen-host-libc.tmp"
#else
#define TEST_FILE "popen.tmp"
#endif
#define TEST_STRING1 "the quick brown fox jumps over the lazy dog"
#define TEST_STRING1_LEN 43
#define TEST_STRING2 "Lorem ipsum dolor sit amet, consectetur adipiscing elit"
#define TEST_STRING2_LEN 55
int main() {
// Test reading
FILE *f1 = popen("echo -n '" TEST_STRING1 "'", "r");
assert(f1);
char buf1[TEST_STRING1_LEN];
assert(fread(buf1, 1, TEST_STRING1_LEN, f1) == TEST_STRING1_LEN);
assert(memcmp(buf1, TEST_STRING1, TEST_STRING1_LEN) == 0);
pclose(f1);
// Test writing
FILE *f2 = popen("cat - > " TEST_FILE, "w");
assert(f2);
assert(fwrite(TEST_STRING2, 1, TEST_STRING2_LEN, f2) == TEST_STRING2_LEN);
pclose(f2);
// Read test file back
FILE *test_file = fopen(TEST_FILE, "r");
assert(test_file);
char buf2[TEST_STRING2_LEN];
assert(fread(buf2, 1, TEST_STRING2_LEN, test_file) == TEST_STRING2_LEN);
assert(memcmp(buf2, TEST_STRING2, TEST_STRING2_LEN) == 0);
fclose(test_file);
assert(unlink(TEST_FILE) == 0);
return 0;
}
@@ -0,0 +1,119 @@
#include <assert.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <time.h>
#if defined(__linux__)
#include <pthread.h>
size_t COUNTER_EXPIRATIONS = 3;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
size_t count = 0;
void timer_handler(union sigval val) {
(void) val;
pthread_mutex_lock(&mutex);
count++;
fprintf(stderr, "new count %zu\n", count);
if(count >= COUNTER_EXPIRATIONS) {
pthread_cond_signal(&cond);
}
pthread_mutex_unlock(&mutex);
}
static void test_thread_notify() {
timer_t timer;
struct sigevent sev = {
.sigev_value = {
.sival_ptr = &timer,
},
.sigev_notify = SIGEV_THREAD,
};
sev.sigev_notify_function = timer_handler;
sev.sigev_notify_attributes = NULL;
int ret = timer_create(CLOCK_MONOTONIC, &sev, &timer);
assert(ret == 0);
struct itimerspec its = {
.it_interval = {
.tv_sec = 1,
.tv_nsec = 0,
},
.it_value = {
.tv_sec = 1,
.tv_nsec = 0,
},
};
ret = timer_settime(timer, 0, &its, NULL);
assert(ret == 0);
pthread_mutex_lock(&mutex);
while(count < COUNTER_EXPIRATIONS)
pthread_cond_wait(&cond, &mutex);
pthread_mutex_unlock(&mutex);
ret = timer_delete(timer);
assert(ret == 0);
}
#endif
int main() {
struct sigevent evp;
memset(&evp, 0, sizeof(evp));
sigset_t set;
sigemptyset(&set);
sigaddset(&set, SIGUSR1);
sigprocmask(SIG_BLOCK, &set, 0);
evp.sigev_notify = SIGEV_SIGNAL;
evp.sigev_signo = SIGUSR1;
struct timeval start;
gettimeofday(&start, NULL);
timer_t timer;
if (timer_create(CLOCK_MONOTONIC, &evp, &timer)) {
perror("timer_create");
exit(1);
}
struct itimerspec spec;
memset(&spec, 0, sizeof(spec));
spec.it_value.tv_sec = 1;
spec.it_value.tv_nsec = 0;
int sig;
timer_settime(timer, 0, &spec, NULL);
struct itimerspec its = {};
int ret = timer_gettime(timer, &its);
assert(ret == 0);
assert(its.it_value.tv_sec || its.it_value.tv_nsec);
sigwait(&set, &sig);
struct timeval end;
gettimeofday(&end, NULL);
double diff = end.tv_sec - start.tv_sec;
diff += (end.tv_usec - start.tv_usec) / 1000000.0;
assert(diff >= 1.0);
#if defined(__linux__)
test_thread_notify();
#endif
timer_delete(timer);
return 0;
}
@@ -0,0 +1,23 @@
#include <stdlib.h>
#include <assert.h>
#include <stdint.h>
#include <errno.h>
int main() {
void *p = NULL;
// align must be a power of two
assert(posix_memalign(&p, 3, 1) == EINVAL && p == NULL);
// align must be a multiple of sizeof(void *)
assert(posix_memalign(&p, sizeof(void *) / 2, 8) == EINVAL && p == NULL);
assert(posix_memalign(&p, sizeof(void *), sizeof(void *)) == 0 && p != NULL && (uintptr_t)p % sizeof(void *) == 0);
free(p);
assert(posix_memalign(&p, 256, 1) == 0 && p != NULL && (uintptr_t)p % 256 == 0);
free(p);
assert(posix_memalign(&p, 256, 256) == 0 && p != NULL && (uintptr_t)p % 256 == 0);
free(p);
return 0;
}
@@ -0,0 +1,38 @@
#include <stdlib.h>
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <spawn.h>
#include <sys/wait.h>
extern char **environ;
void run_cmd(char *cmd)
{
pid_t pid;
char *argv[] = {"sh", "-c", cmd, NULL};
int status;
printf("Run command: %s\n", cmd);
status = posix_spawn(&pid, "/bin/sh", NULL, NULL, argv, environ);
if(status == 0) {
printf("Child pid: %i\n", pid);
if(waitpid(pid, &status, 0) != -1) {
printf("Child exited with status %i\n", status);
printf("Child exit status: %i\n", WEXITSTATUS(status));
assert(WEXITSTATUS(status) == 0);
} else {
perror("waitpid");
assert(0 == 1);
}
} else {
printf("posix_spawn: %s\n", strerror(status));
assert(0 == 1);
}
}
int main() {
run_cmd(":");
return 0;
}
@@ -0,0 +1,54 @@
#include <assert.h>
#include <pthread.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/wait.h>
_Atomic int prepare_order = 0;
_Atomic int parent_order = 0;
_Atomic int child_order = 0;
static void prepare1() { prepare_order = 1; }
static void prepare2() { prepare_order = 2; }
static void parent1() { parent_order = 1; }
static void parent2() { parent_order = 2; }
static void child1() { child_order = 1; }
static void child2() { child_order = 2; }
int main() {
assert(!pthread_atfork(prepare1, parent1, child1));
assert(!pthread_atfork(prepare2, parent2, child2));
pid_t pid = fork();
assert(pid >= 0);
if (!pid) {
assert(child_order == 2);
exit(0);
} else {
assert(prepare_order == 1);
assert(parent_order == 2);
while (1) {
int status = 0;
int ret = waitpid(pid, &status, 0);
if (ret == -1 && errno == EINTR)
continue;
assert(ret > 0);
if (WIFSIGNALED(status) && WTERMSIG(status) == SIGABRT)
return 1;
return WEXITSTATUS(status);
}
}
return 0;
}
@@ -0,0 +1,166 @@
#include <pthread.h>
#include <assert.h>
#include <errno.h>
#include <alloca.h>
#include <string.h>
#include <sys/mman.h>
#include <signal.h>
static void test_detachstate() {
pthread_attr_t attr;
assert(!pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED));
int detachstate;
assert(!pthread_attr_getdetachstate(&attr, &detachstate));
assert(detachstate == PTHREAD_CREATE_DETACHED);
assert(pthread_attr_setdetachstate(&attr, 2* (PTHREAD_CREATE_DETACHED +
PTHREAD_CREATE_JOINABLE)) == EINVAL);
}
static void *stacksize_worker(void *arg) {
size_t default_stacksize = (*(size_t*)arg);
size_t alloc_size = default_stacksize + default_stacksize/2;
void *area = alloca(alloc_size);
// If the allocated stack was not enough this will crash.
// Trample both the start and end of the area so it works on both upwards-
// and downwards-growing stacks.
*(volatile char*)area = 1;
*(volatile char*)(area + alloc_size - 1) = 1;
return NULL;
}
static void test_stacksize() {
pthread_attr_t attr;
assert(!pthread_attr_init(&attr));
size_t stacksize;
assert(!pthread_attr_getstacksize(&attr, &stacksize));
assert(!pthread_attr_setstacksize(&attr, stacksize * 2));
pthread_t thread;
assert(!pthread_create(&thread, &attr, stacksize_worker, &stacksize));
assert(!pthread_join(thread, NULL));
}
static void test_guardsize() {
pthread_attr_t attr;
assert(!pthread_attr_init(&attr));
assert(!pthread_attr_setguardsize(&attr, 0));
size_t guardsize;
assert(!pthread_attr_getguardsize(&attr, &guardsize));
assert(!guardsize);
}
static void test_scope() {
pthread_attr_t attr;
assert(!pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM));
int scope;
assert(!pthread_attr_getscope(&attr, &scope));
assert(scope == PTHREAD_SCOPE_SYSTEM);
assert(pthread_attr_setscope(&attr, 2* (PTHREAD_SCOPE_SYSTEM +
PTHREAD_SCOPE_PROCESS)) == EINVAL);
}
static void test_inheritsched() {
pthread_attr_t attr;
assert(!pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED));
int inheritsched;
assert(!pthread_attr_getinheritsched(&attr, &inheritsched));
assert(inheritsched == PTHREAD_INHERIT_SCHED);
assert(pthread_attr_setinheritsched(&attr, 2* (PTHREAD_INHERIT_SCHED +
PTHREAD_EXPLICIT_SCHED)) == EINVAL);
}
static void test_schedparam() {
pthread_attr_t attr;
struct sched_param init_param = {0};
assert(!pthread_attr_setschedparam(&attr, &init_param));
struct sched_param param = {1};
assert(!pthread_attr_getschedparam(&attr, &param));
assert(param.sched_priority == init_param.sched_priority);
}
static void test_schedpolicy() {
pthread_attr_t attr;
assert(!pthread_attr_setschedpolicy(&attr, SCHED_FIFO));
int policy;
assert(!pthread_attr_getschedpolicy(&attr, &policy));
assert(policy == SCHED_FIFO);
assert(pthread_attr_setinheritsched(&attr, 2* (SCHED_FIFO + SCHED_RR +
SCHED_OTHER)) == EINVAL);
}
static void *stackaddr_worker(void *arg) {
void *addr = *(void**)arg;
void *sp;
#if defined(__x86_64__)
asm volatile ("mov %%rsp, %0" : "=r"(sp));
#elif defined(__i386__)
asm volatile ("mov %%esp, %0" : "=r"(sp));
#elif defined(__aarch64__)
asm volatile ("mov %0, sp" : "=r"(sp));
#elif defined (__riscv)
asm volatile ("mv %0, sp" : "=r"(sp));
#elif defined(__m68k__)
asm volatile ("move.l %%sp, %0" : "=r"(sp));
#elif defined (__loongarch64)
asm volatile ("move %0, $sp" : "=r"(sp));
#else
# error Unknown architecture
#endif
// Check if our stack pointer is in a sane range.
assert(sp > addr);
return NULL;
}
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
static void test_stackaddr() {
pthread_attr_t attr;
assert(!pthread_attr_init(&attr));
size_t size;
assert(!pthread_attr_getstacksize(&attr, &size));
void *addr = mmap(NULL, size, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
assert(!pthread_attr_setstack(&attr, addr, size));
assert(!pthread_attr_setguardsize(&attr, 0));
void *new_addr;
size_t new_size;
assert(!pthread_attr_getstack(&attr, &new_addr, &new_size));
assert(new_addr == addr);
assert(new_size == size);
pthread_t thread;
assert(!pthread_create(&thread, &attr, stackaddr_worker, &addr));
assert(!pthread_join(thread, NULL));
}
#pragma GCC diagnostic pop
#if !defined(USE_HOST_LIBC) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 32)
static void test_stack() {
pthread_attr_t attr;
void *stackaddr = (void*)1;
size_t stacksize = PTHREAD_STACK_MIN;
assert(!pthread_attr_setstack(&attr, stackaddr, stacksize));
void *new_addr;
size_t new_size;
assert(!pthread_attr_getstack(&attr, &new_addr, &new_size));
assert(new_addr == stackaddr);
assert(new_size == stacksize);
}
#endif
int main() {
test_detachstate();
test_stacksize();
test_guardsize();
test_scope();
test_inheritsched();
test_schedparam();
test_schedpolicy();
test_stackaddr();
#if !defined(USE_HOST_LIBC) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 32)
test_stack();
#endif
return 0;
}

Some files were not shown because too many files have changed in this diff Show More