mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-06-27 23:08:31 +00:00
Make more fixes and improvements
- Remove PAGESIZE constant - Fix realloc() documentation - Fix ttyname_r() error reporting - Make forking more reliable on Windows - Make execvp() a few microseconds faster - Make system() a few microseconds faster - Tighten up the socket-related magic numbers - Loosen restrictions on mmap() offset alignment - Improve GetProgramExecutableName() with getenv("_") - Use mkstemp() as basis for mktemp(), tmpfile(), tmpfd() - Fix flakes in pthread_cancel_test, unix_test, fork_test - Fix recently introduced futex stack overflow regression - Let sockets be passed as stdio to subprocesses on Windows - Improve security of bind() on Windows w/ SO_EXCLUSIVEADDRUSE
This commit is contained in:
parent
140a8a52e5
commit
18bb5888e1
311 changed files with 1239 additions and 2622 deletions
|
@ -17,6 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/rusage.h"
|
||||
#include "libc/calls/syscall_support-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
|
@ -24,7 +25,9 @@
|
|||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/temp.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/testlib/ezbench.h"
|
||||
#include "libc/testlib/subprocess.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
|
||||
|
@ -93,4 +96,59 @@ TEST(execve, ziposAPE) {
|
|||
EXITS(42);
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
#define TINY_ELF_PROGRAM "\
|
||||
\177\105\114\106\002\001\001\000\000\000\000\000\000\000\000\000\
|
||||
\002\000\076\000\001\000\000\000\170\000\100\000\000\000\000\000\
|
||||
\100\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\
|
||||
\000\000\000\000\100\000\070\000\001\000\000\000\000\000\000\000\
|
||||
\001\000\000\000\005\000\000\000\000\000\000\000\000\000\000\000\
|
||||
\000\000\100\000\000\000\000\000\000\000\100\000\000\000\000\000\
|
||||
\200\000\000\000\000\000\000\000\200\000\000\000\000\000\000\000\
|
||||
\000\020\000\000\000\000\000\000\152\052\137\152\074\130\017\005"
|
||||
// clang-format on
|
||||
|
||||
void ExecvTinyElf(const char *path) {
|
||||
int ws;
|
||||
if (!vfork()) {
|
||||
execv(path, (char *[]){path, 0});
|
||||
abort();
|
||||
}
|
||||
ASSERT_NE(-1, wait(&ws));
|
||||
ASSERT_EQ(42, WEXITSTATUS(ws));
|
||||
}
|
||||
|
||||
void ExecvpTinyElf(const char *path) {
|
||||
int ws;
|
||||
if (!vfork()) {
|
||||
execvp(path, (char *[]){path, 0});
|
||||
abort();
|
||||
}
|
||||
ASSERT_NE(-1, wait(&ws));
|
||||
ASSERT_EQ(42, WEXITSTATUS(ws));
|
||||
}
|
||||
|
||||
void ExecveTinyElf(const char *path) {
|
||||
int ws;
|
||||
if (!vfork()) {
|
||||
execve(path, (char *[]){path, 0}, (char *[]){0});
|
||||
abort();
|
||||
}
|
||||
ASSERT_NE(-1, wait(&ws));
|
||||
ASSERT_EQ(42, WEXITSTATUS(ws));
|
||||
}
|
||||
|
||||
BENCH(execve, bench) {
|
||||
if (!IsLinux()) return;
|
||||
char path[128] = "/tmp/tinyelf.XXXXXX";
|
||||
int fd = mkstemp(path);
|
||||
fchmod(fd, 0700);
|
||||
write(fd, TINY_ELF_PROGRAM, sizeof(TINY_ELF_PROGRAM));
|
||||
close(fd);
|
||||
EZBENCH2("execv", donothing, ExecvTinyElf(path));
|
||||
EZBENCH2("execvp", donothing, ExecvpTinyElf(path));
|
||||
EZBENCH2("execve", donothing, ExecveTinyElf(path));
|
||||
unlink(path);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -348,7 +348,6 @@ TEST(pledge, inet_forbidsOtherSockets) {
|
|||
ASSERT_SYS(EPERM, -1, socket(AF_BLUETOOTH, SOCK_DGRAM, IPPROTO_UDP));
|
||||
ASSERT_SYS(EPERM, -1, socket(AF_INET, SOCK_RAW, IPPROTO_UDP));
|
||||
ASSERT_SYS(EPERM, -1, socket(AF_INET, SOCK_DGRAM, IPPROTO_RAW));
|
||||
ASSERT_SYS(EPERM, -1, setsockopt(3, SOL_SOCKET, SO_TIMESTAMP, &yes, 4));
|
||||
struct sockaddr_in sin = {AF_INET, 0, {htonl(0x7f000001)}};
|
||||
ASSERT_SYS(0, 0, bind(4, (struct sockaddr *)&sin, sizeof(sin)));
|
||||
struct sockaddr_in6 sin6 = {.sin6_family = AF_INET6,
|
||||
|
@ -372,7 +371,6 @@ TEST(pledge, anet_forbidsUdpSocketsAndConnect) {
|
|||
ASSERT_SYS(0, 0, pledge("stdio anet", 0));
|
||||
ASSERT_SYS(0, 3, socket(AF_INET, SOCK_STREAM, IPPROTO_TCP));
|
||||
ASSERT_SYS(EPERM, -1, socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP));
|
||||
ASSERT_SYS(EPERM, -1, setsockopt(3, SOL_SOCKET, SO_TIMESTAMP, &yes, 4));
|
||||
struct sockaddr_in sin = {AF_INET, 0, {htonl(0x7f000001)}};
|
||||
ASSERT_SYS(EPERM, -1, connect(4, (struct sockaddr *)&sin, sizeof(sin)));
|
||||
_Exit(0);
|
||||
|
|
|
@ -17,49 +17,46 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/atomic.h"
|
||||
#include "libc/cosmo.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/atomic.h"
|
||||
#include "libc/mem/gc.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
#include "libc/thread/spawn.h"
|
||||
#include "libc/thread/thread.h"
|
||||
|
||||
#define N 32
|
||||
|
||||
int i, n;
|
||||
struct spawn *t;
|
||||
atomic_int x, y;
|
||||
pthread_barrier_t b;
|
||||
static pthread_once_t once = PTHREAD_ONCE_INIT;
|
||||
static _Atomic(uint32_t) once;
|
||||
|
||||
void InitFactory(void) {
|
||||
ASSERT_EQ(0, atomic_load(&x));
|
||||
atomic_fetch_add(&y, 1);
|
||||
}
|
||||
|
||||
int Worker(void *arg, int tid) {
|
||||
void *Worker(void *arg) {
|
||||
pthread_barrier_wait(&b);
|
||||
ASSERT_EQ(0, pthread_once(&once, InitFactory));
|
||||
ASSERT_EQ(0, cosmo_once(&once, InitFactory));
|
||||
ASSERT_EQ(1, atomic_load(&y));
|
||||
atomic_fetch_add(&x, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
TEST(pthread_once, test) {
|
||||
n = 32;
|
||||
TEST(cosmo_once, test) {
|
||||
pthread_t th[N];
|
||||
x = y = 0;
|
||||
ASSERT_EQ(0, pthread_barrier_init(&b, 0, n));
|
||||
t = gc(malloc(sizeof(struct spawn) * n));
|
||||
for (i = 0; i < n; ++i) ASSERT_SYS(0, 0, _spawn(Worker, 0, t + i));
|
||||
for (i = 0; i < n; ++i) EXPECT_SYS(0, 0, _join(t + i));
|
||||
ASSERT_EQ(n, atomic_load(&x));
|
||||
ASSERT_EQ(0, pthread_barrier_init(&b, 0, N));
|
||||
for (i = 0; i < N; ++i) {
|
||||
ASSERT_EQ(0, pthread_create(th + i, 0, Worker, 0));
|
||||
}
|
||||
for (i = 0; i < N; ++i) {
|
||||
ASSERT_EQ(0, pthread_join(th[i], 0));
|
||||
}
|
||||
ASSERT_EQ(N, atomic_load(&x));
|
||||
ASSERT_EQ(1, atomic_load(&y));
|
||||
ASSERT_EQ(0, pthread_barrier_destroy(&b));
|
||||
}
|
||||
|
||||
__attribute__((__constructor__)) static void init(void) {
|
||||
// try to test both the nsync and non-nsync versions with regular builds
|
||||
if (!IsTiny()) {
|
||||
pthread_cond_t c = {0};
|
||||
pthread_cond_broadcast(&c);
|
||||
}
|
||||
}
|
|
@ -1,65 +0,0 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/intrin/morton.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/nexgen32e/kcpuids.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/testlib/ezbench.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
|
||||
void SetUpOnce(void) {
|
||||
ASSERT_SYS(0, 0, pledge("stdio rpath", 0));
|
||||
}
|
||||
|
||||
TEST(morton, test) {
|
||||
EXPECT_EQ(0, morton(0, 0));
|
||||
EXPECT_EQ(1, morton(0, 1));
|
||||
EXPECT_EQ(2, morton(1, 0));
|
||||
EXPECT_EQ(3, morton(1, 1));
|
||||
EXPECT_EQ(4, morton(0, 2));
|
||||
EXPECT_EQ(~0ul, morton(~0ul, ~0ul));
|
||||
EXPECT_EQ(0x7ffffffffffffffdul, morton(0x7ffffffeul, 0xfffffffful));
|
||||
EXPECT_EQ(0b1010101000010101010, morton(0b0000001111, 0b1111000000));
|
||||
}
|
||||
|
||||
TEST(unmorton, test) {
|
||||
EXPECT_EQ(0, unmorton(0).ax);
|
||||
EXPECT_EQ(0, unmorton(0).dx);
|
||||
EXPECT_EQ(0, unmorton(1).ax);
|
||||
EXPECT_EQ(1, unmorton(1).dx);
|
||||
EXPECT_EQ(1, unmorton(2).ax);
|
||||
EXPECT_EQ(0, unmorton(2).dx);
|
||||
EXPECT_EQ(1, unmorton(3).ax);
|
||||
EXPECT_EQ(1, unmorton(3).dx);
|
||||
EXPECT_EQ(0, unmorton(4).ax);
|
||||
EXPECT_EQ(2, unmorton(4).dx);
|
||||
EXPECT_EQ(0xffffffffu, unmorton(~0ul).ax);
|
||||
EXPECT_EQ(0xffffffffu, unmorton(~0ul).dx);
|
||||
EXPECT_EQ(0x7ffffffeul, unmorton(0x7ffffffffffffffdul).ax);
|
||||
EXPECT_EQ(0xfffffffful, unmorton(0x7ffffffffffffffdul).dx);
|
||||
EXPECT_EQ(0b0000001111000000, unmorton(0b010101010000001010101).ax);
|
||||
EXPECT_EQ(0b0000000000001111, unmorton(0b010101010000001010101).dx);
|
||||
}
|
||||
|
||||
BENCH(morton, bench) {
|
||||
EZBENCH2("morton", donothing,
|
||||
__expropriate(morton(__conceal("r", 123), __conceal("r", 123))));
|
||||
EZBENCH2("unmorton", donothing, __expropriate(unmorton(__conceal("r", 123))));
|
||||
}
|
|
@ -99,7 +99,6 @@ void *Worker(void *arg) {
|
|||
}
|
||||
|
||||
TEST(pthread_atfork, torture) {
|
||||
if (IsWindows()) return; // TODO(jart): why do we get EBADF? it worked before
|
||||
pthread_mutex_init(&mu, 0);
|
||||
pthread_atfork(mu_lock, mu_unlock, mu_funlock);
|
||||
int i, n = 4;
|
||||
|
|
|
@ -1,39 +0,0 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/intrin/bits.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
|
||||
void SetUpOnce(void) {
|
||||
ASSERT_SYS(0, 0, pledge("stdio", 0));
|
||||
}
|
||||
|
||||
TEST(_rounddown2pow, test) {
|
||||
EXPECT_EQ(0, _rounddown2pow(0));
|
||||
EXPECT_EQ(1, _rounddown2pow(1));
|
||||
EXPECT_EQ(2, _rounddown2pow(2));
|
||||
EXPECT_EQ(2, _rounddown2pow(3));
|
||||
EXPECT_EQ(4, _rounddown2pow(4));
|
||||
EXPECT_EQ(PAGESIZE / 2, _rounddown2pow(PAGESIZE - 1));
|
||||
EXPECT_EQ(PAGESIZE, _rounddown2pow(PAGESIZE));
|
||||
EXPECT_EQ(PAGESIZE, _rounddown2pow(PAGESIZE + 1));
|
||||
EXPECT_EQ(PAGESIZE / 2, _rounddown2pow(PAGESIZE - 1));
|
||||
EXPECT_EQ(PAGESIZE, _rounddown2pow(PAGESIZE));
|
||||
EXPECT_EQ(PAGESIZE, _rounddown2pow(PAGESIZE + 1));
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/intrin/bits.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
|
||||
void SetUpOnce(void) {
|
||||
ASSERT_SYS(0, 0, pledge("stdio", 0));
|
||||
}
|
||||
|
||||
TEST(_roundup2log, test) {
|
||||
EXPECT_EQ(0, _roundup2log(0));
|
||||
EXPECT_EQ(1, _roundup2log(1));
|
||||
EXPECT_EQ(1, _roundup2log(2));
|
||||
EXPECT_EQ(2, _roundup2log(3));
|
||||
EXPECT_EQ(2, _roundup2log(4));
|
||||
EXPECT_EQ(12, _roundup2log(PAGESIZE - 1));
|
||||
EXPECT_EQ(12, _roundup2log(PAGESIZE));
|
||||
EXPECT_EQ(13, _roundup2log(PAGESIZE + 1));
|
||||
EXPECT_EQ(12, _roundup2log(PAGESIZE - 1));
|
||||
EXPECT_EQ(12, _roundup2log(PAGESIZE));
|
||||
EXPECT_EQ(13, _roundup2log(PAGESIZE + 1));
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/intrin/bits.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
|
||||
void SetUpOnce(void) {
|
||||
ASSERT_SYS(0, 0, pledge("stdio", 0));
|
||||
}
|
||||
|
||||
TEST(_roundup2pow, test) {
|
||||
EXPECT_EQ(0, _roundup2pow(0));
|
||||
EXPECT_EQ(1, _roundup2pow(1));
|
||||
EXPECT_EQ(2, _roundup2pow(2));
|
||||
EXPECT_EQ(4, _roundup2pow(3));
|
||||
EXPECT_EQ(4, _roundup2pow(4));
|
||||
EXPECT_EQ(PAGESIZE, _roundup2pow(PAGESIZE - 1));
|
||||
EXPECT_EQ(PAGESIZE, _roundup2pow(PAGESIZE));
|
||||
EXPECT_EQ(PAGESIZE * 2, _roundup2pow(PAGESIZE + 1));
|
||||
EXPECT_EQ(PAGESIZE, _roundup2pow(PAGESIZE - 1));
|
||||
EXPECT_EQ(PAGESIZE, _roundup2pow(PAGESIZE));
|
||||
EXPECT_EQ(PAGESIZE * 2, _roundup2pow(PAGESIZE + 1));
|
||||
}
|
|
@ -325,30 +325,30 @@ TEST(wcscasecmp, testItWorksCase) {
|
|||
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||
|
||||
TEST(strncmp, testEqualManyNs) {
|
||||
char *s1 = malloc(PAGESIZE);
|
||||
char *s2 = malloc(PAGESIZE);
|
||||
memset(s1, 7, PAGESIZE);
|
||||
memset(s2, 7, PAGESIZE);
|
||||
s1[PAGESIZE - 1] = '\0';
|
||||
s2[PAGESIZE - 1] = '\0';
|
||||
char *s1 = malloc(4096);
|
||||
char *s2 = malloc(4096);
|
||||
memset(s1, 7, 4096);
|
||||
memset(s2, 7, 4096);
|
||||
s1[4096 - 1] = '\0';
|
||||
s2[4096 - 1] = '\0';
|
||||
for (unsigned i = 1; i <= 128; ++i) {
|
||||
ASSERT_EQ(0, strncmp(s1 + PAGESIZE - i, s2 + PAGESIZE - i, i + 0));
|
||||
ASSERT_EQ(0, strncmp(s1 + PAGESIZE - i, s2 + PAGESIZE - i, i + 1));
|
||||
ASSERT_EQ(0, strncmp(s1 + 4096 - i, s2 + 4096 - i, i + 0));
|
||||
ASSERT_EQ(0, strncmp(s1 + 4096 - i, s2 + 4096 - i, i + 1));
|
||||
}
|
||||
free(s2);
|
||||
free(s1);
|
||||
}
|
||||
|
||||
TEST(strncmp, testNotEqualManyNs) {
|
||||
char *s1 = malloc(PAGESIZE);
|
||||
char *s2 = malloc(PAGESIZE);
|
||||
char *s1 = malloc(4096);
|
||||
char *s2 = malloc(4096);
|
||||
for (unsigned i = 1; i <= 128; ++i) {
|
||||
memset(s1, 7, PAGESIZE);
|
||||
memset(s2, 7, PAGESIZE);
|
||||
s1[PAGESIZE - 1] = (unsigned char)0;
|
||||
s2[PAGESIZE - 1] = (unsigned char)255;
|
||||
ASSERT_EQ(-255, strncmp(s1 + PAGESIZE - i, s2 + PAGESIZE - i, i + 0));
|
||||
ASSERT_EQ(-255, strncmp(s1 + PAGESIZE - i, s2 + PAGESIZE - i, i + 1));
|
||||
memset(s1, 7, 4096);
|
||||
memset(s2, 7, 4096);
|
||||
s1[4096 - 1] = (unsigned char)0;
|
||||
s2[4096 - 1] = (unsigned char)255;
|
||||
ASSERT_EQ(-255, strncmp(s1 + 4096 - i, s2 + 4096 - i, i + 0));
|
||||
ASSERT_EQ(-255, strncmp(s1 + 4096 - i, s2 + 4096 - i, i + 1));
|
||||
}
|
||||
free(s2);
|
||||
free(s1);
|
||||
|
|
|
@ -1,107 +0,0 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2021 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/log/libfatal.internal.h"
|
||||
#include "libc/mem/arena.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/mem/gc.internal.h"
|
||||
#include "libc/stdio/append.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/testlib/ezbench.h"
|
||||
#include "libc/testlib/hyperion.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
|
||||
TEST(arena, test) {
|
||||
EXPECT_STREQ("hello", gc(strdup("hello")));
|
||||
__arena_push();
|
||||
EXPECT_STREQ("hello", strdup("hello"));
|
||||
__arena_push();
|
||||
EXPECT_STREQ("hello", strdup("hello"));
|
||||
for (int i = 0; i < 5000; ++i) {
|
||||
EXPECT_STREQ("hello", strdup("hello"));
|
||||
}
|
||||
free(strdup("hello"));
|
||||
__arena_pop();
|
||||
EXPECT_STREQ("", calloc(1, 16));
|
||||
EXPECT_STREQ("hello", strdup("hello"));
|
||||
__arena_pop();
|
||||
}
|
||||
|
||||
TEST(arena, testRealloc) {
|
||||
char *b = 0;
|
||||
size_t i, n = 0;
|
||||
__arena_push();
|
||||
for (i = 0; i < kHyperionSize; ++i) {
|
||||
b = realloc(b, ++n * sizeof(*b));
|
||||
b[n - 1] = kHyperion[i];
|
||||
}
|
||||
ASSERT_EQ(0, memcmp(b, kHyperion, kHyperionSize));
|
||||
__arena_pop();
|
||||
}
|
||||
|
||||
void *memalign_(size_t, size_t) asm("memalign");
|
||||
void *calloc_(size_t, size_t) asm("calloc");
|
||||
|
||||
void Ca(size_t n) {
|
||||
__arena_push();
|
||||
for (int i = 0; i < n; ++i) {
|
||||
memalign_(1, 1);
|
||||
}
|
||||
__arena_pop();
|
||||
}
|
||||
|
||||
void Cb(size_t n) {
|
||||
void **P;
|
||||
P = malloc(n * sizeof(void *));
|
||||
for (int i = 0; i < n; ++i) {
|
||||
P[i] = calloc_(1, 1);
|
||||
}
|
||||
bulk_free(P, n);
|
||||
free(P);
|
||||
}
|
||||
|
||||
BENCH(arena, benchMalloc) {
|
||||
EZBENCH2("arena calloc(1)", donothing, Ca(100));
|
||||
EZBENCH2("dlmalloc calloc(1)", donothing, Cb(100));
|
||||
}
|
||||
|
||||
void Ra(void) {
|
||||
long *b = 0;
|
||||
size_t i, n = 0;
|
||||
__arena_push();
|
||||
for (i = 0; i < kHyperionSize; ++i) {
|
||||
b = realloc(b, ++n * sizeof(*b));
|
||||
b[n - 1] = kHyperion[i];
|
||||
}
|
||||
__arena_pop();
|
||||
}
|
||||
|
||||
void Rb(void) {
|
||||
long *b = 0;
|
||||
size_t i, n = 0;
|
||||
for (i = 0; i < kHyperionSize; ++i) {
|
||||
b = realloc(b, ++n * sizeof(*b));
|
||||
b[n - 1] = kHyperion[i];
|
||||
}
|
||||
free(b);
|
||||
}
|
||||
|
||||
BENCH(arena, benchRealloc) {
|
||||
EZBENCH2("arena realloc", donothing, Ra());
|
||||
EZBENCH2("dlmalloc realloc", donothing, Rb());
|
||||
}
|
|
@ -1,103 +0,0 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/log/libfatal.internal.h"
|
||||
#include "libc/mem/alg.h"
|
||||
#include "libc/mem/arraylist.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
|
||||
struct string {
|
||||
size_t i, n;
|
||||
char *p;
|
||||
};
|
||||
|
||||
struct string16 {
|
||||
size_t i, n;
|
||||
char16_t *p;
|
||||
};
|
||||
|
||||
struct ArrayListInteger {
|
||||
size_t i, n;
|
||||
int *p;
|
||||
};
|
||||
|
||||
TEST(append, worksGreatForScalars) {
|
||||
char c = 'a';
|
||||
struct string s;
|
||||
memset(&s, 0, sizeof(s));
|
||||
for (size_t i = 0; i < 1024; ++i) {
|
||||
ASSERT_EQ(i, append(&s, &c));
|
||||
}
|
||||
ASSERT_EQ(1024, s.i);
|
||||
for (size_t i = 0; i < s.i; ++i) ASSERT_EQ('a', s.p[i]);
|
||||
free(s.p);
|
||||
s.p = 0;
|
||||
}
|
||||
|
||||
TEST(append, isGenericallyTyped) {
|
||||
int c = 0x31337;
|
||||
struct ArrayListInteger s;
|
||||
memset(&s, 0, sizeof(s));
|
||||
for (size_t i = 0; i < 1024; ++i) {
|
||||
ASSERT_EQ(i, append(&s, &c));
|
||||
}
|
||||
ASSERT_EQ(1024, s.i);
|
||||
ASSERT_GT(malloc_usable_size(s.p), 1024 * sizeof(int));
|
||||
for (size_t i = 0; i < s.i; ++i) {
|
||||
ASSERT_EQ(0x31337, s.p[i]);
|
||||
}
|
||||
free(s.p);
|
||||
s.p = 0;
|
||||
}
|
||||
|
||||
TEST(concat, worksGreatForStrings) {
|
||||
const char *ks = "Und wird die Welt auch in Flammen stehen\n"
|
||||
"Wir werden wieder auferstehen\n";
|
||||
struct string s;
|
||||
memset(&s, 0, sizeof(s));
|
||||
ASSERT_EQ(0, concat(&s, ks, strlen(ks)));
|
||||
ASSERT_EQ(strlen(ks), concat(&s, ks, strlen(ks) + 1));
|
||||
ASSERT_STREQ("Und wird die Welt auch in Flammen stehen\n"
|
||||
"Wir werden wieder auferstehen\n"
|
||||
"Und wird die Welt auch in Flammen stehen\n"
|
||||
"Wir werden wieder auferstehen\n",
|
||||
s.p);
|
||||
ASSERT_EQ(strlen(ks) * 2 + 1, s.i);
|
||||
free(s.p);
|
||||
s.p = 0;
|
||||
}
|
||||
|
||||
TEST(concat, isGenericallyTyped) {
|
||||
const char16_t *ks = u"Drum hoch die Fäuste, hoch zum Licht.\n"
|
||||
u"Unsere schwarzen Seelen bekommt ihr nicht.\n";
|
||||
struct string16 s;
|
||||
memset(&s, 0, sizeof(s));
|
||||
ASSERT_EQ(0, concat(&s, ks, strlen16(ks)));
|
||||
ASSERT_EQ(strlen16(ks), concat(&s, ks, strlen16(ks) + 1));
|
||||
ASSERT_STREQ(u"Drum hoch die Fäuste, hoch zum Licht.\n"
|
||||
u"Unsere schwarzen Seelen bekommt ihr nicht.\n"
|
||||
u"Drum hoch die Fäuste, hoch zum Licht.\n"
|
||||
u"Unsere schwarzen Seelen bekommt ihr nicht.\n",
|
||||
s.p);
|
||||
ASSERT_EQ(strlen16(ks) * 2 + 1, s.i);
|
||||
free(s.p);
|
||||
s.p = 0;
|
||||
}
|
|
@ -1,57 +0,0 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/mem/alg.h"
|
||||
#include "libc/mem/bisectcarleft.internal.h"
|
||||
#include "libc/intrin/bits.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
|
||||
TEST(bisectcarleft, testEmpty) {
|
||||
const int32_t cells[][2] = {};
|
||||
EXPECT_EQ(0, bisectcarleft(cells, ARRAYLEN(cells), 123));
|
||||
}
|
||||
|
||||
TEST(bisectcarleft, testOneEntry) {
|
||||
const int32_t cells[][2] = {{123, 31337}};
|
||||
EXPECT_EQ(0, bisectcarleft(cells, ARRAYLEN(cells), 122));
|
||||
EXPECT_EQ(0, bisectcarleft(cells, ARRAYLEN(cells), 123));
|
||||
EXPECT_EQ(0, bisectcarleft(cells, ARRAYLEN(cells), 124));
|
||||
}
|
||||
|
||||
TEST(bisectcarleft, testNegativity_usesSignedBehavior) {
|
||||
const int32_t cells[][2] = {{-2, 31337}};
|
||||
EXPECT_EQ(0, bisectcarleft(cells, ARRAYLEN(cells), -3));
|
||||
EXPECT_EQ(0, bisectcarleft(cells, ARRAYLEN(cells), -2));
|
||||
EXPECT_EQ(0, bisectcarleft(cells, ARRAYLEN(cells), -1));
|
||||
}
|
||||
|
||||
TEST(bisectcarleft, testMultipleEntries) {
|
||||
const int32_t cells[][2] = {{00, 0}, {11, 0}, {20, 0}, {33, 0}, {40, 0},
|
||||
{50, 0}, {60, 0}, {70, 0}, {80, 0}, {90, 0}};
|
||||
EXPECT_EQ(0, bisectcarleft(cells, ARRAYLEN(cells), 10));
|
||||
EXPECT_EQ(1, bisectcarleft(cells, ARRAYLEN(cells), 11));
|
||||
EXPECT_EQ(1, bisectcarleft(cells, ARRAYLEN(cells), 12));
|
||||
EXPECT_EQ(1, bisectcarleft(cells, ARRAYLEN(cells), 19));
|
||||
EXPECT_EQ(2, bisectcarleft(cells, ARRAYLEN(cells), 20));
|
||||
EXPECT_EQ(2, bisectcarleft(cells, ARRAYLEN(cells), 21));
|
||||
EXPECT_EQ(2, bisectcarleft(cells, ARRAYLEN(cells), 32));
|
||||
EXPECT_EQ(3, bisectcarleft(cells, ARRAYLEN(cells), 33));
|
||||
EXPECT_EQ(3, bisectcarleft(cells, ARRAYLEN(cells), 34));
|
||||
}
|
|
@ -20,6 +20,7 @@
|
|||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/intrin/bits.h"
|
||||
#include "libc/intrin/cxaatexit.internal.h"
|
||||
#include "libc/intrin/safemacros.internal.h"
|
||||
|
@ -51,12 +52,59 @@ void SetUp(void) {
|
|||
if (IsWindows()) exit(0);
|
||||
}
|
||||
|
||||
TEST(malloc, zeroMeansOne) {
|
||||
ASSERT_GE(malloc_usable_size(gc(malloc(0))), 1);
|
||||
TEST(malloc, zero) {
|
||||
char *p;
|
||||
ASSERT_NE(NULL, (p = malloc(0)));
|
||||
if (IsAsan()) ASSERT_FALSE(__asan_is_valid(p, 1));
|
||||
free(p);
|
||||
}
|
||||
|
||||
TEST(calloc, zerosMeansOne) {
|
||||
ASSERT_GE(malloc_usable_size(gc(calloc(0, 0))), 1);
|
||||
TEST(realloc, bothAreZero_createsMinimalAllocation) {
|
||||
char *p;
|
||||
ASSERT_NE(NULL, (p = realloc(0, 0)));
|
||||
if (IsAsan()) ASSERT_FALSE(__asan_is_valid(p, 1));
|
||||
free(p);
|
||||
}
|
||||
|
||||
TEST(realloc, ptrIsZero_createsAllocation) {
|
||||
char *p;
|
||||
ASSERT_NE(NULL, (p = realloc(0, 1)));
|
||||
if (IsAsan()) ASSERT_TRUE(__asan_is_valid(p, 1));
|
||||
if (IsAsan()) ASSERT_FALSE(__asan_is_valid(p + 1, 1));
|
||||
ASSERT_EQ(p, realloc(p, 0));
|
||||
if (IsAsan()) ASSERT_FALSE(__asan_is_valid(p, 1));
|
||||
if (IsAsan()) ASSERT_FALSE(__asan_is_valid(p + 1, 1));
|
||||
free(p);
|
||||
}
|
||||
|
||||
TEST(realloc, sizeIsZero_shrinksAllocation) {
|
||||
char *p;
|
||||
ASSERT_NE(NULL, (p = malloc(1)));
|
||||
if (IsAsan()) ASSERT_TRUE(__asan_is_valid(p, 1));
|
||||
if (IsAsan()) ASSERT_FALSE(__asan_is_valid(p + 1, 1));
|
||||
ASSERT_EQ(p, realloc(p, 0));
|
||||
if (IsAsan()) ASSERT_FALSE(__asan_is_valid(p, 1));
|
||||
if (IsAsan()) ASSERT_FALSE(__asan_is_valid(p + 1, 1));
|
||||
free(p);
|
||||
}
|
||||
|
||||
TEST(realloc_in_place, test) {
|
||||
char *x = malloc(16);
|
||||
EXPECT_EQ(x, realloc_in_place(x, 0));
|
||||
EXPECT_EQ(x, realloc_in_place(x, 1));
|
||||
*x = 2;
|
||||
free(x);
|
||||
}
|
||||
|
||||
BENCH(realloc_in_place, bench) {
|
||||
volatile int i = 1000;
|
||||
volatile char *x = malloc(i);
|
||||
EZBENCH2("malloc", donothing, free(malloc(i)));
|
||||
EZBENCH2("memalign", donothing, free(memalign(16, i)));
|
||||
EZBENCH2("memalign", donothing, free(memalign(32, i)));
|
||||
EZBENCH2("realloc", donothing, x = realloc(x, --i));
|
||||
EZBENCH2("realloc_in_place", donothing, realloc_in_place(x, --i));
|
||||
free(x);
|
||||
}
|
||||
|
||||
void AppendStuff(char **p, size_t *n) {
|
||||
|
|
|
@ -1,42 +0,0 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2021 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/mem/gc.internal.h"
|
||||
#include "libc/testlib/ezbench.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
|
||||
TEST(realloc_in_place, test) {
|
||||
char *x = malloc(16);
|
||||
EXPECT_EQ(x, realloc_in_place(x, 0));
|
||||
EXPECT_EQ(x, realloc_in_place(x, 1));
|
||||
*x = 2;
|
||||
free(x);
|
||||
}
|
||||
|
||||
BENCH(realloc_in_place, bench) {
|
||||
volatile int i = 1000;
|
||||
volatile char *x = malloc(i);
|
||||
EZBENCH2("malloc", donothing, free(malloc(i)));
|
||||
EZBENCH2("malloc", donothing, free(malloc(i)));
|
||||
EZBENCH2("memalign", donothing, free(memalign(16, i)));
|
||||
EZBENCH2("memalign", donothing, free(memalign(32, i)));
|
||||
EZBENCH2("realloc", donothing, x = realloc(x, --i));
|
||||
EZBENCH2("realloc_in_place", donothing, realloc_in_place(x, --i));
|
||||
free(x);
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/mem/reverse.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
|
||||
TEST(reverse, test) {
|
||||
/* this test gets DCE'd :) */
|
||||
int A[3] = {1, 2, 3};
|
||||
reverse(A, ARRAYLEN(A));
|
||||
EXPECT_EQ(3, A[0]);
|
||||
EXPECT_EQ(2, A[1]);
|
||||
EXPECT_EQ(1, A[2]);
|
||||
}
|
||||
|
||||
TEST(reverse, testEmpty) {
|
||||
int A[3] = {1, 2, 3};
|
||||
reverse(A, 0);
|
||||
EXPECT_EQ(1, A[0]);
|
||||
EXPECT_EQ(2, A[1]);
|
||||
EXPECT_EQ(3, A[2]);
|
||||
}
|
|
@ -16,15 +16,19 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/atomic.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/sigaction.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nexgen32e/rdtsc.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/map.h"
|
||||
#include "libc/sysv/consts/msync.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
|
@ -38,6 +42,7 @@ TEST(fork, testPipes) {
|
|||
int a, b;
|
||||
int ws, pid;
|
||||
int pipefds[2];
|
||||
alarm(5);
|
||||
ASSERT_NE(-1, pipe(pipefds));
|
||||
ASSERT_NE(-1, (pid = fork()));
|
||||
if (!pid) {
|
||||
|
@ -52,9 +57,11 @@ TEST(fork, testPipes) {
|
|||
EXPECT_NE(-1, close(pipefds[0]));
|
||||
EXPECT_NE(-1, waitpid(pid, &ws, 0));
|
||||
EXPECT_EQ(31337, b);
|
||||
alarm(0);
|
||||
}
|
||||
|
||||
TEST(fork, testSharedMemory) {
|
||||
alarm(5);
|
||||
int ws, pid;
|
||||
int stackvar;
|
||||
int *sharedvar;
|
||||
|
@ -86,6 +93,7 @@ TEST(fork, testSharedMemory) {
|
|||
EXPECT_EQ(1, *privatevar);
|
||||
EXPECT_NE(-1, munmap(sharedvar, FRAMESIZE));
|
||||
EXPECT_NE(-1, munmap(privatevar, FRAMESIZE));
|
||||
alarm(0);
|
||||
}
|
||||
|
||||
static volatile bool gotsigusr1;
|
||||
|
@ -109,6 +117,7 @@ TEST(fork, childToChild) {
|
|||
signal(SIGUSR1, OnSigusr1);
|
||||
signal(SIGUSR2, OnSigusr2);
|
||||
sigemptyset(&mask);
|
||||
sigaddset(&mask, SIGUSR1);
|
||||
sigaddset(&mask, SIGUSR2);
|
||||
sigprocmask(SIG_BLOCK, &mask, &oldmask);
|
||||
ASSERT_NE(-1, (child1 = fork()));
|
||||
|
@ -117,28 +126,27 @@ TEST(fork, childToChild) {
|
|||
sigsuspend(0);
|
||||
_Exit(!gotsigusr1);
|
||||
}
|
||||
sigdelset(&mask, SIGUSR2);
|
||||
sigsuspend(&mask);
|
||||
sigsuspend(0);
|
||||
ASSERT_NE(-1, (child2 = fork()));
|
||||
if (!child2) {
|
||||
kill(child1, SIGUSR1);
|
||||
_Exit(0);
|
||||
}
|
||||
ASSERT_NE(-1, wait(&ws));
|
||||
EXPECT_TRUE(WIFEXITED(ws));
|
||||
EXPECT_EQ(0, WEXITSTATUS(ws));
|
||||
EXPECT_EQ(0, ws);
|
||||
ASSERT_NE(-1, wait(&ws));
|
||||
EXPECT_TRUE(WIFEXITED(ws));
|
||||
EXPECT_EQ(0, WEXITSTATUS(ws));
|
||||
EXPECT_EQ(0, ws);
|
||||
sigprocmask(SIG_SETMASK, &oldmask, 0);
|
||||
}
|
||||
|
||||
TEST(fork, preservesTlsMemory) {
|
||||
alarm(5);
|
||||
int pid;
|
||||
__get_tls()->tib_errno = 31337;
|
||||
SPAWN(fork);
|
||||
ASSERT_EQ(31337, __get_tls()->tib_errno);
|
||||
EXITS(0);
|
||||
alarm(0);
|
||||
}
|
||||
|
||||
void ForkInSerial(void) {
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/intrin/atomic.h"
|
||||
#include "libc/intrin/bits.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
|
@ -37,6 +38,7 @@
|
|||
#include "libc/stdio/rand.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/auxv.h"
|
||||
#include "libc/sysv/consts/map.h"
|
||||
#include "libc/sysv/consts/msync.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
|
@ -94,7 +96,8 @@ TEST(mmap, noreplaceExistingMap) {
|
|||
|
||||
TEST(mmap, smallerThanPage_mapsRemainder) {
|
||||
long pagesz = sysconf(_SC_PAGESIZE);
|
||||
char *map = mmap(0, 1, PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
|
||||
char *map =
|
||||
mmap(0, 4096, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
ASSERT_NE(MAP_FAILED, map);
|
||||
EXPECT_TRUE(testlib_memoryexists(map));
|
||||
EXPECT_TRUE(testlib_memoryexists(map + (pagesz - 1)));
|
||||
|
@ -103,6 +106,16 @@ TEST(mmap, smallerThanPage_mapsRemainder) {
|
|||
EXPECT_FALSE(testlib_memoryexists(map + (pagesz - 1)));
|
||||
}
|
||||
|
||||
TEST(mmap, smallerThanPage_remainderIsPoisoned) {
|
||||
if (!IsAsan()) return;
|
||||
char *map;
|
||||
ASSERT_NE(MAP_FAILED, (map = mmap(0, 1, PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)));
|
||||
EXPECT_TRUE(__asan_is_valid(map, 1));
|
||||
EXPECT_FALSE(__asan_is_valid(map + 1, 1));
|
||||
EXPECT_SYS(0, 0, munmap(map, 1));
|
||||
}
|
||||
|
||||
TEST(mmap, testMapFile) {
|
||||
int fd;
|
||||
char *p;
|
||||
|
@ -130,7 +143,7 @@ TEST(mmap, testMapFile_fdGetsClosed_makesNoDifference) {
|
|||
EXPECT_NE(-1, close(fd));
|
||||
EXPECT_STREQN("hello", p, 5);
|
||||
p[1] = 'a';
|
||||
EXPECT_NE(-1, msync(p, PAGESIZE, MS_SYNC));
|
||||
EXPECT_NE(-1, msync(p, getauxval(AT_PAGESZ), MS_SYNC));
|
||||
ASSERT_NE(-1, (fd = open(path, O_RDONLY)));
|
||||
EXPECT_EQ(5, read(fd, buf, 5));
|
||||
EXPECT_STREQN("hallo", buf, 5);
|
||||
|
@ -179,15 +192,16 @@ TEST(mmap, customStackMemory_isAuthorized) {
|
|||
TEST(mmap, fileOffset) {
|
||||
int fd;
|
||||
char *map;
|
||||
int offset_align = IsWindows() ? FRAMESIZE : getauxval(AT_PAGESZ);
|
||||
ASSERT_NE(-1, (fd = open("foo", O_CREAT | O_RDWR, 0644)));
|
||||
EXPECT_NE(-1, ftruncate(fd, FRAMESIZE * 2));
|
||||
EXPECT_NE(-1, pwrite(fd, "hello", 5, FRAMESIZE * 0));
|
||||
EXPECT_NE(-1, pwrite(fd, "there", 5, FRAMESIZE * 1));
|
||||
EXPECT_NE(-1, ftruncate(fd, offset_align * 2));
|
||||
EXPECT_NE(-1, pwrite(fd, "hello", 5, offset_align * 0));
|
||||
EXPECT_NE(-1, pwrite(fd, "there", 5, offset_align * 1));
|
||||
EXPECT_NE(-1, fdatasync(fd));
|
||||
ASSERT_NE(MAP_FAILED, (map = mmap(NULL, FRAMESIZE, PROT_READ, MAP_PRIVATE, fd,
|
||||
FRAMESIZE)));
|
||||
ASSERT_NE(MAP_FAILED, (map = mmap(NULL, offset_align, PROT_READ, MAP_PRIVATE,
|
||||
fd, offset_align)));
|
||||
EXPECT_EQ(0, memcmp(map, "there", 5), "%#.*s", 5, map);
|
||||
EXPECT_NE(-1, munmap(map, FRAMESIZE));
|
||||
EXPECT_NE(-1, munmap(map, offset_align));
|
||||
EXPECT_NE(-1, close(fd));
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/runtime/syslib.internal.h"
|
||||
|
@ -106,8 +107,9 @@ TEST(O_NONBLOCK, canBeTunedWithFcntl_toMakeReadNonBlocking) {
|
|||
PARENT();
|
||||
EXPECT_SYS(0, 0, close(3));
|
||||
ASSERT_SYS(0, 3, socket(AF_INET, SOCK_STREAM, IPPROTO_TCP));
|
||||
ASSERT_SYS(0, O_RDWR, fcntl(3, F_GETFL));
|
||||
ASSERT_SYS(0, 0, connect(3, (struct sockaddr *)&addr, sizeof(addr)));
|
||||
ASSERT_SYS(0, 0, fcntl(3, F_SETFL, O_NONBLOCK));
|
||||
ASSERT_SYS(0, 0, fcntl(3, F_SETFL, O_RDWR | O_NONBLOCK));
|
||||
ASSERT_SYS(EAGAIN, -1, read(3, buf, 16));
|
||||
EXPECT_EQ(0, pthread_spin_unlock(phaser + 0));
|
||||
TryAgain:
|
||||
|
|
|
@ -17,6 +17,11 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/fd.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/nt/winsock.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sock/sock.h"
|
||||
#include "libc/sock/struct/sockaddr.h"
|
||||
#include "libc/sock/struct/sockaddr6.h"
|
||||
|
@ -25,6 +30,7 @@
|
|||
#include "libc/sysv/consts/ipproto.h"
|
||||
#include "libc/sysv/consts/limits.h"
|
||||
#include "libc/sysv/consts/sock.h"
|
||||
#include "libc/testlib/subprocess.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
|
||||
TEST(ipv4, test) {
|
||||
|
@ -40,27 +46,20 @@ TEST(ipv4, test) {
|
|||
ASSERT_SYS(0, 0, bind(3, (struct sockaddr *)&addr, sizeof(addr)));
|
||||
ASSERT_SYS(0, 0, getsockname(3, (struct sockaddr *)&addr, &addrsize));
|
||||
ASSERT_SYS(0, 0, listen(3, SOMAXCONN));
|
||||
ASSERT_NE(-1, (pid = fork()));
|
||||
if (!pid) {
|
||||
ASSERT_SYS(0, 4, accept(3, (struct sockaddr *)&addr, &addrsize));
|
||||
ASSERT_SYS(0, 5, send(4, "hello", 5, 0));
|
||||
ASSERT_SYS(0, 0, close(4));
|
||||
ASSERT_SYS(0, 0, close(3));
|
||||
_Exit(0);
|
||||
}
|
||||
SPAWN(fork);
|
||||
ASSERT_SYS(0, 4, accept(3, (struct sockaddr *)&addr, &addrsize));
|
||||
ASSERT_SYS(0, 5, send(4, "hello", 5, 0));
|
||||
PARENT();
|
||||
EXPECT_SYS(0, 0, close(3));
|
||||
EXPECT_SYS(0, 3, socket(AF_INET, SOCK_STREAM, IPPROTO_TCP));
|
||||
EXPECT_SYS(0, 0, connect(3, (struct sockaddr *)&addr, sizeof(addr)));
|
||||
EXPECT_SYS(0, 5, read(3, buf, 16));
|
||||
EXPECT_STREQ("hello", buf);
|
||||
EXPECT_SYS(0, 0, close(3));
|
||||
EXPECT_NE(-1, wait(&ws));
|
||||
ASSERT_TRUE(WIFEXITED(ws));
|
||||
ASSERT_EQ(0, WEXITSTATUS(ws));
|
||||
WAIT(exit, 0);
|
||||
}
|
||||
|
||||
TEST(ipv6, test) {
|
||||
int ws, pid;
|
||||
char buf[16] = {0};
|
||||
int64_t inoffset;
|
||||
uint32_t addrsize = sizeof(struct sockaddr_in6);
|
||||
|
@ -74,23 +73,19 @@ TEST(ipv6, test) {
|
|||
ASSERT_EQ(AF_INET6, addr.sin6_family);
|
||||
ASSERT_NE(0, addr.sin6_port);
|
||||
ASSERT_SYS(0, 0, listen(3, SOMAXCONN));
|
||||
ASSERT_NE(-1, (pid = fork()));
|
||||
if (!pid) {
|
||||
ASSERT_SYS(0, 4, accept(3, (struct sockaddr *)&addr, &addrsize));
|
||||
ASSERT_SYS(0, 5, send(4, "hello", 5, 0));
|
||||
ASSERT_SYS(0, 0, close(4));
|
||||
ASSERT_SYS(0, 0, close(3));
|
||||
_Exit(0);
|
||||
}
|
||||
SPAWN(fork);
|
||||
ASSERT_SYS(0, 4, accept(3, (struct sockaddr *)&addr, &addrsize));
|
||||
ASSERT_SYS(0, 5, send(4, "hello", 5, 0));
|
||||
ASSERT_SYS(0, 0, close(4));
|
||||
ASSERT_SYS(0, 0, close(3));
|
||||
PARENT();
|
||||
EXPECT_SYS(0, 0, close(3));
|
||||
EXPECT_SYS(0, 3, socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP));
|
||||
EXPECT_SYS(0, 0, connect(3, (struct sockaddr *)&addr, sizeof(addr)));
|
||||
EXPECT_SYS(0, 5, read(3, buf, 16));
|
||||
EXPECT_STREQ("hello", buf);
|
||||
EXPECT_SYS(0, 0, close(3));
|
||||
EXPECT_NE(-1, wait(&ws));
|
||||
ASSERT_TRUE(WIFEXITED(ws));
|
||||
ASSERT_EQ(0, WEXITSTATUS(ws));
|
||||
WAIT(exit, 0);
|
||||
}
|
||||
|
||||
TEST(getsockname, defaultsToZero) {
|
||||
|
@ -118,3 +113,76 @@ TEST(getsockname, copiesSafely_givesFullSize) {
|
|||
ASSERT_EQ(0xffff, addr.sin_port);
|
||||
EXPECT_SYS(0, 0, close(3));
|
||||
}
|
||||
|
||||
TEST(socket, canBeInheritedByForkedWorker) {
|
||||
char buf[16] = {0};
|
||||
int64_t inoffset;
|
||||
uint32_t addrsize = sizeof(struct sockaddr_in);
|
||||
struct sockaddr_in addr = {
|
||||
.sin_family = AF_INET,
|
||||
.sin_addr.s_addr = htonl(0x7f000001),
|
||||
};
|
||||
ASSERT_SYS(0, 3, socket(AF_INET, SOCK_STREAM, IPPROTO_TCP));
|
||||
ASSERT_SYS(0, 0, bind(3, (struct sockaddr *)&addr, sizeof(addr)));
|
||||
ASSERT_SYS(0, 0, getsockname(3, (struct sockaddr *)&addr, &addrsize));
|
||||
ASSERT_SYS(0, 0, listen(3, SOMAXCONN));
|
||||
SPAWN(fork);
|
||||
ASSERT_SYS(0, 4, accept(3, (struct sockaddr *)&addr, &addrsize));
|
||||
ASSERT_SYS(0, 0, close(3));
|
||||
SPAWN(fork);
|
||||
ASSERT_SYS(0, 5, write(4, "hello", 5));
|
||||
PARENT();
|
||||
ASSERT_SYS(0, 0, close(4));
|
||||
WAIT(exit, 0);
|
||||
PARENT();
|
||||
EXPECT_SYS(0, 0, close(3));
|
||||
EXPECT_SYS(0, 3, socket(AF_INET, SOCK_STREAM, IPPROTO_TCP));
|
||||
EXPECT_SYS(0, 0, connect(3, (struct sockaddr *)&addr, sizeof(addr)));
|
||||
EXPECT_SYS(0, 5, read(3, buf, 16));
|
||||
EXPECT_STREQ("hello", buf);
|
||||
EXPECT_SYS(0, 0, close(3));
|
||||
WAIT(exit, 0);
|
||||
}
|
||||
|
||||
__attribute__((__constructor__)) static void StdioPro(int argc, char *argv[]) {
|
||||
if (argc >= 2 && !strcmp(argv[1], "StdioProg")) {
|
||||
ASSERT_EQ(NULL, getenv("__STDIO_SOCKETS"));
|
||||
ASSERT_EQ(5, write(1, "hello", 5));
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(socket, canBeUsedAsExecutedStdio) {
|
||||
char buf[16] = {0};
|
||||
int64_t inoffset;
|
||||
const char *prog;
|
||||
uint32_t addrsize = sizeof(struct sockaddr_in);
|
||||
struct sockaddr_in addr = {
|
||||
.sin_family = AF_INET,
|
||||
.sin_addr.s_addr = htonl(0x7f000001),
|
||||
};
|
||||
prog = GetProgramExecutableName();
|
||||
ASSERT_SYS(0, 3, socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, IPPROTO_TCP));
|
||||
ASSERT_SYS(0, 0, bind(3, (struct sockaddr *)&addr, sizeof(addr)));
|
||||
ASSERT_SYS(0, 0, getsockname(3, (struct sockaddr *)&addr, &addrsize));
|
||||
ASSERT_SYS(0, 0, listen(3, SOMAXCONN));
|
||||
SPAWN(fork);
|
||||
ASSERT_SYS(0, 4,
|
||||
accept4(3, (struct sockaddr *)&addr, &addrsize, SOCK_CLOEXEC));
|
||||
ASSERT_SYS(0, 1, dup2(4, 1));
|
||||
SPAWN(vfork);
|
||||
execve(prog, (char *[]){prog, "StdioProg", 0}, (char *[]){0});
|
||||
abort();
|
||||
PARENT();
|
||||
ASSERT_SYS(0, 0, close(4));
|
||||
ASSERT_SYS(0, 0, close(3));
|
||||
WAIT(exit, 0);
|
||||
PARENT();
|
||||
EXPECT_SYS(0, 0, close(3));
|
||||
EXPECT_SYS(0, 3, socket(AF_INET, SOCK_STREAM, IPPROTO_TCP));
|
||||
EXPECT_SYS(0, 0, connect(3, (struct sockaddr *)&addr, sizeof(addr)));
|
||||
EXPECT_SYS(0, 5, read(3, buf, 16));
|
||||
EXPECT_STREQ("hello", buf);
|
||||
EXPECT_SYS(0, 0, close(3));
|
||||
WAIT(exit, 0);
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/atomic.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/timeval.h"
|
||||
|
@ -32,6 +33,7 @@
|
|||
#include "libc/sysv/consts/so.h"
|
||||
#include "libc/sysv/consts/sock.h"
|
||||
#include "libc/sysv/consts/sol.h"
|
||||
#include "libc/testlib/subprocess.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
#include "libc/time/time.h"
|
||||
|
||||
|
@ -41,13 +43,16 @@ void SetUpOnce(void) {
|
|||
ASSERT_SYS(0, 0, pledge("stdio rpath cpath proc unix", 0));
|
||||
}
|
||||
|
||||
void DatagramServer(void) {
|
||||
TEST(unix, datagram) {
|
||||
if (IsWindows()) return; // no unix datagram on windows :'(
|
||||
atomic_bool *ready = _mapshared(1);
|
||||
SPAWN(fork);
|
||||
char buf[256] = {0};
|
||||
uint32_t len = sizeof(struct sockaddr_un);
|
||||
struct sockaddr_un addr = {AF_UNIX, "foo.sock"};
|
||||
alarm(3);
|
||||
ASSERT_SYS(0, 3, socket(AF_UNIX, SOCK_DGRAM, 0));
|
||||
ASSERT_SYS(0, 0, bind(3, (void *)&addr, len));
|
||||
*ready = true;
|
||||
bzero(&addr, sizeof(addr));
|
||||
ASSERT_SYS(0, 0, getsockname(3, (void *)&addr, &len));
|
||||
ASSERT_EQ(11, len);
|
||||
|
@ -55,33 +60,21 @@ void DatagramServer(void) {
|
|||
ASSERT_SYS(0, 5, read(3, buf, 256));
|
||||
EXPECT_STREQ("hello", buf);
|
||||
ASSERT_SYS(0, 0, close(3));
|
||||
}
|
||||
|
||||
TEST(unix, datagram) {
|
||||
if (IsWindows()) return; // no unix datagram on windows :'(
|
||||
int ws;
|
||||
PARENT();
|
||||
while (!*ready) sched_yield();
|
||||
ASSERT_SYS(0, 3, socket(AF_UNIX, SOCK_DGRAM, 0));
|
||||
uint32_t len = sizeof(struct sockaddr_un);
|
||||
struct sockaddr_un addr = {AF_UNIX, "foo.sock"};
|
||||
if (!fork()) {
|
||||
DatagramServer();
|
||||
_Exit(0);
|
||||
}
|
||||
alarm(3);
|
||||
while (!fileexists(addr.sun_path)) usleep(10000);
|
||||
ASSERT_SYS(0, 3, socket(AF_UNIX, SOCK_DGRAM, 0));
|
||||
ASSERT_SYS(0, 5, sendto(3, "hello", 5, 0, (struct sockaddr *)&addr, len));
|
||||
ASSERT_SYS(0, 0, close(3));
|
||||
ASSERT_NE(-1, wait(&ws));
|
||||
EXPECT_TRUE(WIFEXITED(ws));
|
||||
EXPECT_EQ(0, WEXITSTATUS(ws));
|
||||
alarm(0);
|
||||
WAIT(exit, 0);
|
||||
munmap(ready, 1);
|
||||
}
|
||||
|
||||
void StreamServer(void) {
|
||||
void StreamServer(atomic_bool *ready) {
|
||||
char buf[256] = {0};
|
||||
uint32_t len = sizeof(struct sockaddr_un);
|
||||
struct sockaddr_un addr = {AF_UNIX, "foo.sock"};
|
||||
alarm(3);
|
||||
ASSERT_SYS(0, 3, socket(AF_UNIX, SOCK_STREAM, 0));
|
||||
ASSERT_SYS(0, 0, bind(3, (void *)&addr, len));
|
||||
bzero(&addr, sizeof(addr));
|
||||
|
@ -92,6 +85,7 @@ void StreamServer(void) {
|
|||
ASSERT_SYS(0, 0, listen(3, 10));
|
||||
bzero(&addr, sizeof(addr));
|
||||
len = sizeof(addr);
|
||||
*ready = true;
|
||||
ASSERT_SYS(0, 4, accept(3, (struct sockaddr *)&addr, &len));
|
||||
ASSERT_EQ(AF_UNIX, addr.sun_family);
|
||||
EXPECT_STREQ("", addr.sun_path);
|
||||
|
@ -101,26 +95,26 @@ void StreamServer(void) {
|
|||
}
|
||||
|
||||
TEST(unix, stream) {
|
||||
if (IsWindows() && !IsAtLeastWindows10()) return;
|
||||
int ws;
|
||||
uint32_t len = sizeof(struct sockaddr_un);
|
||||
struct sockaddr_un addr = {AF_UNIX, "foo.sock"};
|
||||
if (IsWindows() && !IsAtLeastWindows10()) return;
|
||||
atomic_bool *ready = _mapshared(1);
|
||||
// TODO(jart): move this line down when kFdProcess is gone
|
||||
ASSERT_SYS(0, 3, socket(AF_UNIX, SOCK_STREAM, 0));
|
||||
if (!fork()) {
|
||||
close(3);
|
||||
StreamServer();
|
||||
StreamServer(ready);
|
||||
_Exit(0);
|
||||
}
|
||||
alarm(3);
|
||||
while (!fileexists(addr.sun_path)) usleep(10000);
|
||||
while (!*ready) sched_yield();
|
||||
uint32_t len = sizeof(struct sockaddr_un);
|
||||
struct sockaddr_un addr = {AF_UNIX, "foo.sock"};
|
||||
ASSERT_SYS(0, 0, connect(3, (void *)&addr, len));
|
||||
ASSERT_SYS(0, 5, write(3, "hello", 5));
|
||||
ASSERT_SYS(0, 0, close(3));
|
||||
ASSERT_NE(-1, wait(&ws));
|
||||
EXPECT_TRUE(WIFEXITED(ws));
|
||||
EXPECT_EQ(0, WEXITSTATUS(ws));
|
||||
alarm(0);
|
||||
munmap(ready, 1);
|
||||
}
|
||||
|
||||
TEST(unix, serverGoesDown_deletedSockFile) { // field of landmine
|
||||
|
|
|
@ -1,80 +0,0 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/intrin/bits.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/internal.h"
|
||||
#include "libc/stdio/temp.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
|
||||
#define Mode() \
|
||||
({ \
|
||||
va_list va; \
|
||||
unsigned Mode; \
|
||||
va_start(va, flags); \
|
||||
Mode = va_arg(va, unsigned); \
|
||||
va_end(va); \
|
||||
Mode; \
|
||||
})
|
||||
|
||||
static int MockOpen1(const char *file, int flags, ...) {
|
||||
static bool once;
|
||||
ASSERT_FALSE(once);
|
||||
once = true;
|
||||
EXPECT_STREQ("/tmp/mkostemps.ctre5m", file);
|
||||
EXPECT_EQ(O_RDWR | O_CREAT | O_EXCL, flags);
|
||||
EXPECT_EQ(0600, Mode());
|
||||
return 123;
|
||||
}
|
||||
|
||||
TEST(mkostempsm, test1) {
|
||||
uint64_t rando = 1;
|
||||
char path[PATH_MAX] = "/tmp/mkostemps.XXXXXX";
|
||||
EXPECT_EQ(123L, mkostempsmi(path, 0, 0, &rando, 0600, MockOpen1));
|
||||
EXPECT_STREQ("/tmp/mkostemps.ctre5m", path);
|
||||
}
|
||||
|
||||
static int MockOpen2(const char *file, int flags, ...) {
|
||||
static int state;
|
||||
switch (state) {
|
||||
case 0:
|
||||
state = 1;
|
||||
EXPECT_STREQ("/tmp/mkostemps.ctre5m", file);
|
||||
EXPECT_EQ((unsigned)(O_RDWR | O_CREAT | O_EXCL), flags);
|
||||
EXPECT_EQ(0600, Mode());
|
||||
errno = EEXIST;
|
||||
return -1;
|
||||
case 1:
|
||||
state = 1;
|
||||
EXPECT_STREQ("/tmp/mkostemps.jl1h61", file);
|
||||
EXPECT_EQ((unsigned)(O_RDWR | O_CREAT | O_EXCL), flags);
|
||||
EXPECT_EQ(0600, Mode());
|
||||
return 123;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
TEST(mkostempsm, test2) {
|
||||
uint64_t rando = 1;
|
||||
char path[PATH_MAX] = "/tmp/mkostemps.XXXXXX";
|
||||
EXPECT_EQ(123, mkostempsmi(path, 0, 0, &rando, 0600, MockOpen2));
|
||||
EXPECT_STREQ("/tmp/mkostemps.jl1h61", path);
|
||||
}
|
|
@ -107,13 +107,6 @@ TEST(system, testStderrRedirect_toStdout) {
|
|||
ASSERT_EQ(0, close(pipefd[0]));
|
||||
}
|
||||
|
||||
BENCH(system, bench) {
|
||||
testlib_extract("/zip/echo.com", "echo.com", 0755);
|
||||
EZBENCH2("system cmd", donothing, system("./echo.com hi >/dev/null"));
|
||||
EZBENCH2("cocmd echo", donothing, system("echo hi >/dev/null"));
|
||||
EZBENCH2("cocmd exit", donothing, system("exit"));
|
||||
}
|
||||
|
||||
TEST(system, and) {
|
||||
ASSERT_EQ(1, WEXITSTATUS(system("false && false")));
|
||||
ASSERT_EQ(1, WEXITSTATUS(system("true&& false")));
|
||||
|
@ -245,4 +238,13 @@ TEST(system, tr) {
|
|||
ASSERT_STREQ("HELLO\n", gc(xslurp("res", 0)));
|
||||
}
|
||||
|
||||
int system2(const char *);
|
||||
|
||||
BENCH(system, bench) {
|
||||
testlib_extract("/zip/echo.com", "echo.com", 0755);
|
||||
EZBENCH2("system cmd", donothing, system("./echo.com hi >/dev/null"));
|
||||
EZBENCH2("cocmd echo", donothing, system("echo hi >/dev/null"));
|
||||
EZBENCH2("cocmd exit", donothing, system("exit"));
|
||||
}
|
||||
|
||||
#endif /* __x86_64__ */
|
||||
|
|
|
@ -192,6 +192,6 @@ BENCH(memcpy, bench) {
|
|||
BB(256);
|
||||
BB(1023);
|
||||
BB(1024);
|
||||
BB(PAGESIZE);
|
||||
BB(4096);
|
||||
BB(FRAMESIZE);
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "libc/mem/gc.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/nexgen32e/nexgen32e.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
#include "libc/thread/thread.h"
|
||||
|
@ -80,7 +81,7 @@ TEST(pthread_cancel, synchronous) {
|
|||
pthread_t th;
|
||||
ASSERT_SYS(0, 0, pipe(pfds));
|
||||
ASSERT_EQ(0, pthread_create(&th, 0, Worker, 0));
|
||||
ASSERT_EQ(0, pthread_cancel(th));
|
||||
pthread_cancel(th);
|
||||
ASSERT_EQ(0, pthread_join(th, &rc));
|
||||
ASSERT_EQ(PTHREAD_CANCELED, rc);
|
||||
ASSERT_TRUE(gotcleanup);
|
||||
|
@ -94,7 +95,7 @@ TEST(pthread_cancel, synchronous_delayed) {
|
|||
ASSERT_SYS(0, 0, pipe(pfds));
|
||||
ASSERT_EQ(0, pthread_create(&th, 0, Worker, 0));
|
||||
usleep(10);
|
||||
ASSERT_EQ(0, pthread_cancel(th));
|
||||
pthread_cancel(th);
|
||||
ASSERT_EQ(0, pthread_join(th, &rc));
|
||||
ASSERT_EQ(PTHREAD_CANCELED, rc);
|
||||
ASSERT_TRUE(gotcleanup);
|
||||
|
@ -116,7 +117,7 @@ TEST(pthread_cancel, masked) {
|
|||
pthread_t th;
|
||||
ASSERT_SYS(0, 0, pipe(pfds));
|
||||
ASSERT_EQ(0, pthread_create(&th, 0, DisabledWorker, 0));
|
||||
ASSERT_EQ(0, pthread_cancel(th));
|
||||
pthread_cancel(th);
|
||||
ASSERT_EQ(0, pthread_join(th, &rc));
|
||||
ASSERT_EQ(0, rc);
|
||||
ASSERT_FALSE(gotcleanup);
|
||||
|
@ -130,7 +131,7 @@ TEST(pthread_cancel, masked_delayed) {
|
|||
ASSERT_SYS(0, 0, pipe(pfds));
|
||||
ASSERT_EQ(0, pthread_create(&th, 0, DisabledWorker, 0));
|
||||
usleep(10);
|
||||
ASSERT_EQ(0, pthread_cancel(th));
|
||||
pthread_cancel(th);
|
||||
ASSERT_EQ(0, pthread_join(th, &rc));
|
||||
ASSERT_EQ(0, rc);
|
||||
ASSERT_FALSE(gotcleanup);
|
||||
|
@ -150,7 +151,7 @@ TEST(pthread_cancel, condMaskedWait) {
|
|||
void *rc;
|
||||
pthread_t th;
|
||||
ASSERT_EQ(0, pthread_create(&th, 0, CondWaitMaskedWorker, 0));
|
||||
ASSERT_EQ(0, pthread_cancel(th));
|
||||
pthread_cancel(th);
|
||||
ASSERT_EQ(0, pthread_join(th, &rc));
|
||||
ASSERT_EQ(0, rc);
|
||||
}
|
||||
|
@ -160,7 +161,7 @@ TEST(pthread_cancel, condWaitMaskedDelayed) {
|
|||
pthread_t th;
|
||||
ASSERT_EQ(0, pthread_create(&th, 0, CondWaitMaskedWorker, 0));
|
||||
usleep(10);
|
||||
ASSERT_EQ(0, pthread_cancel(th));
|
||||
pthread_cancel(th);
|
||||
ASSERT_EQ(0, pthread_join(th, &rc));
|
||||
ASSERT_EQ(0, rc);
|
||||
}
|
||||
|
@ -177,7 +178,7 @@ TEST(pthread_cancel, condDeferredWait) {
|
|||
void *rc;
|
||||
pthread_t th;
|
||||
ASSERT_EQ(0, pthread_create(&th, 0, CondWaitDeferredWorker, 0));
|
||||
ASSERT_EQ(0, pthread_cancel(th));
|
||||
pthread_cancel(th);
|
||||
ASSERT_EQ(0, pthread_join(th, &rc));
|
||||
ASSERT_EQ(PTHREAD_CANCELED, rc);
|
||||
ASSERT_EQ(0, pthread_mutex_trylock(&mu));
|
||||
|
@ -189,7 +190,7 @@ TEST(pthread_cancel, condDeferredWaitDelayed) {
|
|||
pthread_t th;
|
||||
ASSERT_EQ(0, pthread_create(&th, 0, CondWaitDeferredWorker, 0));
|
||||
usleep(10);
|
||||
ASSERT_EQ(0, pthread_cancel(th));
|
||||
pthread_cancel(th);
|
||||
ASSERT_EQ(0, pthread_join(th, &rc));
|
||||
ASSERT_EQ(PTHREAD_CANCELED, rc);
|
||||
ASSERT_EQ(0, pthread_mutex_trylock(&mu));
|
||||
|
@ -252,7 +253,7 @@ TEST(pthread_cancel, async) {
|
|||
key_destructor_was_run = false;
|
||||
ASSERT_EQ(0, pthread_create(&th, 0, CpuBoundWorker, 0));
|
||||
while (!is_in_infinite_loop) pthread_yield();
|
||||
ASSERT_EQ(0, pthread_cancel(th));
|
||||
pthread_cancel(th);
|
||||
ASSERT_EQ(0, pthread_join(th, &rc));
|
||||
ASSERT_EQ(PTHREAD_CANCELED, rc);
|
||||
ASSERT_TRUE(key_destructor_was_run);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue