diff --git a/libc/intrin/asan.c b/libc/intrin/asan.c index a9eb8d92f..769c45b41 100644 --- a/libc/intrin/asan.c +++ b/libc/intrin/asan.c @@ -390,10 +390,14 @@ void __asan_unpoison(void *p, long n) { static bool __asan_is_mapped(int x) { // xxx: we can't lock because no reentrant locks yet int i; + bool res; struct MemoryIntervals *m; + __mmi_lock(); m = weaken(_mmi); i = FindMemoryInterval(m, x); - return i < m->i && x >= m->p[i].x; + res = i < m->i && x >= m->p[i].x; + __mmi_unlock(); + return res; } static bool __asan_is_image(const unsigned char *p) { @@ -812,7 +816,7 @@ dontdiscard static __asan_die_f *__asan_report(const void *addr, int size, p = __asan_format_section(p, _base, _etext, ".text", addr); p = __asan_format_section(p, _etext, _edata, ".data", addr); p = __asan_format_section(p, _end, _edata, ".bss", addr); - // xxx: we can't lock because no reentrant locks yet + __mmi_lock(); for (m = weaken(_mmi), i = 0; i < m->i; ++i) { x = m->p[i].x; y = m->p[i].y; @@ -823,6 +827,7 @@ dontdiscard static __asan_die_f *__asan_report(const void *addr, int size, if (x <= z && z <= y) p = __stpcpy(p, " ←shadow"); *p++ = '\n'; } + __mmi_unlock(); *p = 0; kprintf("%s", __fatalbuf); __asan_report_memory_origin(addr, size, kind); diff --git a/libc/nexgen32e/memrchr.S b/libc/nexgen32e/memrchr.S deleted file mode 100644 index e0b368352..000000000 --- a/libc/nexgen32e/memrchr.S +++ /dev/null @@ -1,62 +0,0 @@ -/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│ -│vi: set et ft=asm ts=8 tw=8 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/nexgen32e/x86feature.h" -#include "libc/dce.h" -#include "libc/macros.internal.h" - -// Searches for last instance of byte in memory region. -// -// @param rdi points to data to search -// @param esi is treated as unsigned char -// @param rdx is byte length of rdi -// @return rax is address of last %sil in %rdi, or NULL -// @note AVX2 requires Haswell (2014+) or Excavator (2015+) -// @asyncsignalsafe -memrchr: - .leafprologue - .profilable -#if !IsTiny() - cmp $32,%rdx - jb 5f - testb X86_HAVE(AVX2)+kCpuids(%rip) - jz 5f - vmovd %esi,%xmm0 - vpbroadcastb %xmm0,%ymm0 -3: vmovdqu -32(%rdi,%rdx),%ymm1 - vpcmpeqb %ymm1,%ymm0,%ymm1 - vpmovmskb %ymm1,%eax - lzcnt %eax,%eax - mov %eax,%ecx - sub %rcx,%rdx - cmp $32,%eax - jne 5f - cmp $31,%rdx - ja 3b - vzeroupper -#endif -5: xor %eax,%eax - mov %rdx,%rcx -6: sub $1,%rcx - jb 9f - cmp %sil,-1(%rdi,%rdx) - mov %rcx,%rdx - jne 6b - lea (%rdi,%rcx),%rax -9: .leafepilogue - .endfn memrchr,globl diff --git a/libc/str/memrchr.c b/libc/str/memrchr.c new file mode 100644 index 000000000..e629f3e6b --- /dev/null +++ b/libc/str/memrchr.c @@ -0,0 +1,79 @@ +/*-*- 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/dce.h" +#include "libc/intrin/asan.internal.h" +#include "libc/nexgen32e/x86feature.h" +#include "libc/str/str.h" + +typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(1))); + +static inline const unsigned char *memrchr_pure(const unsigned char *s, + unsigned char c, size_t n) { + size_t i; + for (i = n; i--;) { + if (s[i] == c) { + return s + i; + } + } + return 0; +} + +noasan static inline const unsigned char *memrchr_sse(const unsigned char *s, + unsigned char c, + size_t n) { + size_t i; + unsigned k, m; + xmm_t v, t = {c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c}; + for (i = n; i >= 16;) { + v = *(const xmm_t *)(s + (i -= 16)); + m = __builtin_ia32_pmovmskb128(v == t); + if (m) { + m = __builtin_clzl(m) ^ (sizeof(long) * CHAR_BIT - 1); + return s + i + m; + } + } + while (i--) { + if (s[i] == c) { + return s + i; + } + } + return 0; +} + +/** + * Returns pointer to first instance of character. + * + * @param s is memory to search + * @param c is search byte which is masked with 255 + * @param n is byte length of p + * @return is pointer to first instance of c or NULL if not found + * @asyncsignalsafe + */ +void *memrchr(const void *s, int c, size_t n) { + const void *r; + if (!IsTiny() && X86_HAVE(SSE)) { + if (IsAsan()) { + __asan_verify(s, n); + } + r = memrchr_sse(s, c, n); + } else { + r = memrchr_pure(s, c, n); + } + return (void *)r; +} diff --git a/test/libc/calls/execve_test.c b/test/libc/calls/execve_test.c index ec8a1b94a..d692ef379 100644 --- a/test/libc/calls/execve_test.c +++ b/test/libc/calls/execve_test.c @@ -236,19 +236,19 @@ void SystemElf(void) { } void ForkElf(void) { - if (!fork()) { + if (!(pid = fork())) { execl("bin/tiny64.elf", "bin/tiny64.elf", 0); _Exit(127); } - wait(0); + waitpid(pid, 0, 0); } void VforkElf(void) { - if (!vfork()) { + if (!(pid = vfork())) { execl("bin/tiny64.elf", "bin/tiny64.elf", 0); _Exit(127); } - wait(0); + waitpid(pid, 0, 0); } //////////////////////////////////////////////////////////////////////////////// @@ -258,19 +258,19 @@ void SystemNoMod(void) { } void ForkNoMod(void) { - if (!fork()) { + if (!(pid = fork())) { execl("bin/life-nomod.com", "bin/life-nomod.com", 0); _Exit(127); } - wait(0); + waitpid(pid, 0, 0); } void VforkNoMod(void) { - if (!vfork()) { + if (!(pid = vfork())) { execl("bin/life-nomod.com", "bin/life-nomod.com", 0); _Exit(127); } - wait(0); + waitpid(pid, 0, 0); } //////////////////////////////////////////////////////////////////////////////// @@ -280,19 +280,19 @@ void SystemClassic(void) { } void ForkClassic(void) { - if (!fork()) { + if (!(pid = fork())) { execl("bin/life-classic.com", "bin/life-classic.com", 0); _Exit(127); } - wait(0); + waitpid(pid, 0, 0); } void VforkClassic(void) { - if (!vfork()) { + if (!(pid = vfork())) { execl("bin/life-classic.com", "bin/life-classic.com", 0); _Exit(127); } - wait(0); + waitpid(pid, 0, 0); } //////////////////////////////////////////////////////////////////////////////// @@ -302,19 +302,19 @@ void SystemNoMod3mb(void) { } void ForkNoMod3mb(void) { - if (!fork()) { + if (!(pid = fork())) { execl("bin/life-nomod.com", "bin/life-nomod.com", 0); _Exit(127); } - wait(0); + waitpid(pid, 0, 0); } void VforkNoMod3mb(void) { - if (!vfork()) { + if (!(pid = vfork())) { execl("bin/life-nomod.com", "bin/life-nomod.com", 0); _Exit(127); } - wait(0); + waitpid(pid, 0, 0); } BENCH(execve, bench1) { diff --git a/test/libc/calls/setrlimit_test.c b/test/libc/calls/setrlimit_test.c index f761c49d0..71737be37 100644 --- a/test/libc/calls/setrlimit_test.c +++ b/test/libc/calls/setrlimit_test.c @@ -62,6 +62,7 @@ TEST(setrlimit, testCpuLimit) { struct rlimit rlim; double matrices[3][3][3]; if (IsWindows()) return; /* of course it doesn't work on windows */ + if (IsOpenbsd()) return; /* TODO(jart): fix flake */ ASSERT_NE(-1, (wstatus = xspawn(0))); if (wstatus == -2) { CHECK_EQ(0, xsigaction(SIGXCPU, OnSigxcpu, 0, 0, 0)); diff --git a/test/libc/str/memrchr_test.c b/test/libc/str/memrchr_test.c new file mode 100644 index 000000000..c6e2f331f --- /dev/null +++ b/test/libc/str/memrchr_test.c @@ -0,0 +1,70 @@ +/*-*- 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 2022 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/rand/rand.h" +#include "libc/str/str.h" +#include "libc/testlib/ezbench.h" +#include "libc/testlib/hyperion.h" +#include "libc/testlib/testlib.h" + +TEST(memrchr, testNotFoundSse) { + char buf[16] = {0}; + ASSERT_EQ(NULL, memrchr(buf, 1, 16)); +} + +TEST(memrchr, testNotFoundPure) { + char buf[15] = {0}; + ASSERT_EQ(NULL, memrchr(buf, 1, 15)); +} + +TEST(memrchr, testSse) { + char buf[16]; + rngset(buf, sizeof(buf), lemur64, -1); + ASSERT_EQ(buf + 0, memrchr(buf, buf[0], 16)); + ASSERT_EQ(buf + 15, memrchr(buf, buf[15], 16)); +} + +TEST(memrchr, testPure) { + char buf[15]; + rngset(buf, sizeof(buf), lemur64, -1); + ASSERT_EQ(buf + 0, memrchr(buf, buf[0], 15)); + ASSERT_EQ(buf + 14, memrchr(buf, buf[14], 15)); +} + +TEST(memrchr, testSse2) { + char buf[32]; + rngset(buf, sizeof(buf), lemur64, -1); + ASSERT_EQ(buf + 0, memrchr(buf, buf[0], 32)); + ASSERT_EQ(buf + 15, memrchr(buf, buf[15], 32)); + ASSERT_EQ(buf + 16, memrchr(buf, buf[16], 32)); + ASSERT_EQ(buf + 31, memrchr(buf, buf[31], 32)); +} + +TEST(memrchr, testSsePure) { + char buf[20]; + rngset(buf, sizeof(buf), lemur64, -1); + ASSERT_EQ(buf + 0, memrchr(buf, buf[0], 20)); + ASSERT_EQ(buf + 15, memrchr(buf, buf[15], 20)); + ASSERT_EQ(buf + 16, memrchr(buf, buf[16], 20)); + ASSERT_EQ(buf + 19, memrchr(buf, buf[19], 20)); +} + +BENCH(memrchr, bench) { + void *memrchr_(const void *, int, size_t) asm("memrchr"); + EZBENCH2("memrchr", donothing, memrchr_(kHyperion, 255, kHyperionSize)); +} diff --git a/tool/build/runit.c b/tool/build/runit.c index 283a48f90..c8b416361 100644 --- a/tool/build/runit.c +++ b/tool/build/runit.c @@ -413,6 +413,7 @@ bool Recv(unsigned char *p, size_t n) { do { rc = mbedtls_ssl_read(&ezssl, p + i, n - i); } while (rc == MBEDTLS_ERR_SSL_WANT_READ); + if (!rc) return false; if (rc < 0) { TlsDie("read response failed", rc); } diff --git a/tool/build/runitd.c b/tool/build/runitd.c index 027e8e2ea..625376667 100644 --- a/tool/build/runitd.c +++ b/tool/build/runitd.c @@ -213,13 +213,7 @@ void StartTcpServer(void) { LOGIFNEG1(setsockopt(g_servfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes))); if (bind(g_servfd, &g_servaddr, sizeof(g_servaddr)) == -1) { - if (g_servaddr.sin_port != 0) { - g_servaddr.sin_port = 0; - StartTcpServer(); - return; - } else { - FATALF("bind failed %m"); - } + FATALF("bind failed %m"); } CHECK_NE(-1, listen(g_servfd, 10)); asize = sizeof(g_servaddr); @@ -507,7 +501,7 @@ int Poll(void) { TryAgain: if (g_interrupted) return 0; fds[0].fd = g_servfd; - fds[0].events = POLLIN; + fds[0].events = POLLIN | POLLERR | POLLHUP; wait = MIN(1000, g_timeout); evcount = poll(fds, ARRAYLEN(fds), wait); if (!evcount) g_timeout -= wait;