diff --git a/Makefile b/Makefile index 4cfa46c9b..e84903db8 100644 --- a/Makefile +++ b/Makefile @@ -83,7 +83,6 @@ o/$(MODE): \ .STRICT = 1 .UNVEIL = \ - rwcx:o/tmp \ libc/integral \ libc/disclaimer.inc \ rx:build/bootstrap \ diff --git a/build/bootstrap/make.com b/build/bootstrap/make.com index 76c624c5d..b46d31429 100755 Binary files a/build/bootstrap/make.com and b/build/bootstrap/make.com differ diff --git a/libc/calls/mkntpath.c b/libc/calls/mkntpath.c index 2dfa14f46..f3ad69e04 100644 --- a/libc/calls/mkntpath.c +++ b/libc/calls/mkntpath.c @@ -103,6 +103,20 @@ textwindows int __mkntpath2(const char *path, q += 3; z -= 7; x = 7; + } else if (IsSlash(q[0]) && IsAlpha(q[1]) && !q[2]) { + z = MIN(32767, PATH_MAX); + // turn "\c" into "\\?\c:\" + p[0] = '\\'; + p[1] = '\\'; + p[2] = '?'; + p[3] = '\\'; + p[4] = q[1]; + p[5] = ':'; + p[6] = '\\'; + p += 7; + q += 2; + z -= 7; + x = 7; } else if (IsSlash(q[0]) && IsAlpha(q[1]) && IsSlash(q[2])) { z = MIN(32767, PATH_MAX); // turn "c:\foo" into "\\?\c:\foo" diff --git a/libc/calls/symlinkat.c b/libc/calls/symlinkat.c index 6f14274ef..cbe3b9af7 100644 --- a/libc/calls/symlinkat.c +++ b/libc/calls/symlinkat.c @@ -51,6 +51,6 @@ int symlinkat(const char *target, int newdirfd, const char *linkpath) { rc = sys_symlinkat_nt(target, newdirfd, linkpath); } STRACE("symlinkat(%#s, %s, %#s) → %d% m", target, DescribeDirfd(newdirfd), - linkpath); + linkpath, rc); return rc; } diff --git a/libc/sock/nointernet.c b/libc/sock/nointernet.c index f9accce18..73a3a6083 100644 --- a/libc/sock/nointernet.c +++ b/libc/sock/nointernet.c @@ -249,19 +249,12 @@ static int WaitForTrace(int main) { // eintr isn't possible since we're blocking all signals ORDIE(pid = waitpid(-1, &ws, __WALL)); LogProcessEvent(main, pid, ws); - // once main child exits or dies, we exit / die the same way. we're - // not currently tracking pids, so it's important that a child does - // not exit before its children. otherwise the grandchildren get in - // a permanently stopped state. to address that, we'll send sigterm - // to the process group which we defined earlier. if (WIFEXITED(ws)) { if (pid == main) { - kill(-getpid(), SIGTERM); _Exit(WEXITSTATUS(ws)); } } else if (WIFSIGNALED(ws)) { if (pid == main) { - kill(-getpid(), SIGTERM); Raise(WTERMSIG(ws)); } } else if (WIFSTOPPED(ws)) { @@ -294,12 +287,6 @@ int nointernet(void) { return enosys(); } - // ensure we're at the root of a process group, so we're able to - // broadcast a termination signal later on that catches dangling - // subprocesss our child forgot to destroy. without calling this - // subprocesses could end up permanently stopped if monitor dies - setpgrp(); - // prevent crash handlers from intercepting sigsegv ORDIE(sigfillset(&set)); ORDIE(sigprocmask(SIG_SETMASK, &set, &old)); diff --git a/libc/str/strcasecmp.c b/libc/str/strcasecmp.c index 29f6d3274..9dfcf80f4 100644 --- a/libc/str/strcasecmp.c +++ b/libc/str/strcasecmp.c @@ -16,15 +16,10 @@ │ 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/str/str.h" -static inline noasan uint64_t UncheckedAlignedRead64(const char *p) { - return (uint64_t)(255 & p[7]) << 070 | (uint64_t)(255 & p[6]) << 060 | - (uint64_t)(255 & p[5]) << 050 | (uint64_t)(255 & p[4]) << 040 | - (uint64_t)(255 & p[3]) << 030 | (uint64_t)(255 & p[2]) << 020 | - (uint64_t)(255 & p[1]) << 010 | (uint64_t)(255 & p[0]) << 000; -} - /** * Compares NUL-terminated strings ascii case-insensitively. * @@ -33,7 +28,7 @@ static inline noasan uint64_t UncheckedAlignedRead64(const char *p) { * @return is <0, 0, or >0 based on tolower(uint8_t) comparison * @asyncsignalsafe */ -int strcasecmp(const char *a, const char *b) { +noasan int strcasecmp(const char *a, const char *b) { int x, y; size_t i = 0; uint64_t v, w, d; @@ -41,13 +36,17 @@ int strcasecmp(const char *a, const char *b) { if (((uintptr_t)a & 7) == ((uintptr_t)b & 7)) { for (; (uintptr_t)(a + i) & 7; ++i) { CheckEm: + if (IsAsan()) { + __asan_verify(a, i + 1); + __asan_verify(b, i + 1); + } if ((x = kToLower[a[i] & 255]) != (y = kToLower[b[i] & 255]) || !y) { return x - y; } } for (;; i += 8) { - v = UncheckedAlignedRead64(a + i); - w = UncheckedAlignedRead64(b + i); + v = *(uint64_t *)(a + i); + w = *(uint64_t *)(b + i); w = (v ^ w) | (~v & (v - 0x0101010101010101) & 0x8080808080808080); if (w) { i += (unsigned)__builtin_ctzll(w) >> 3; @@ -56,6 +55,10 @@ int strcasecmp(const char *a, const char *b) { } } else { while ((x = kToLower[a[i] & 255]) == (y = kToLower[b[i] & 255]) && y) ++i; + if (IsAsan()) { + __asan_verify(a, i + 1); + __asan_verify(b, i + 1); + } return x - y; } } diff --git a/libc/str/strcmp.c b/libc/str/strcmp.c index a13789931..58f1d5146 100644 --- a/libc/str/strcmp.c +++ b/libc/str/strcmp.c @@ -17,12 +17,9 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/dce.h" +#include "libc/intrin/asan.internal.h" #include "libc/str/str.h" -static inline noasan uint64_t UncheckedAlignedRead64(const char *p) { - return *(uint64_t *)p; -} - /** * Compares NUL-terminated strings. * @@ -31,7 +28,7 @@ static inline noasan uint64_t UncheckedAlignedRead64(const char *p) { * @return is <0, 0, or >0 based on uint8_t comparison * @asyncsignalsafe */ -int strcmp(const char *a, const char *b) { +noasan int strcmp(const char *a, const char *b) { int c; size_t i = 0; uint64_t v, w, d; @@ -44,16 +41,20 @@ int strcmp(const char *a, const char *b) { } } for (;; i += 8) { - v = UncheckedAlignedRead64(a + i); - w = UncheckedAlignedRead64(b + i); + v = *(uint64_t *)(a + i); + w = *(uint64_t *)(b + i); w = (v ^ w) | (~v & (v - 0x0101010101010101) & 0x8080808080808080); if (w) { i += (unsigned)__builtin_ctzll(w) >> 3; - return (a[i] & 255) - (b[i] & 255); + break; } } } else { while (a[i] == b[i] && b[i]) ++i; - return (a[i] & 255) - (b[i] & 255); } + if (IsAsan()) { + __asan_verify(a, i + 1); + __asan_verify(b, i + 1); + } + return (a[i] & 255) - (b[i] & 255); } diff --git a/libc/testlib/testrunner.c b/libc/testlib/testrunner.c index e06d17bc2..c75117db5 100644 --- a/libc/testlib/testrunner.c +++ b/libc/testlib/testrunner.c @@ -17,8 +17,6 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/assert.h" -#include "libc/intrin/atomic.h" -#include "libc/intrin/weaken.h" #include "libc/calls/calls.h" #include "libc/calls/state.internal.h" #include "libc/calls/strace.internal.h" @@ -29,8 +27,10 @@ #include "libc/errno.h" #include "libc/fmt/fmt.h" #include "libc/fmt/itoa.h" +#include "libc/intrin/atomic.h" #include "libc/intrin/kprintf.h" #include "libc/intrin/spinlock.h" +#include "libc/intrin/weaken.h" #include "libc/log/check.h" #include "libc/log/internal.h" #include "libc/macros.internal.h" @@ -88,7 +88,7 @@ wontreturn void testlib_abort(void) { static void SetupTmpDir(void) { char *p = g_testlib_tmpdir; - p = stpcpy(p, "o/tmp/"); + p = stpcpy(p, kTmpPath); p = stpcpy(p, program_invocation_short_name), *p++ = '.'; p = FormatInt64(p, getpid()), *p++ = '.'; p = FormatInt64(p, x++); diff --git a/libc/tinymath/fmod.S b/libc/tinymath/fmod-tiny.S similarity index 98% rename from libc/tinymath/fmod.S rename to libc/tinymath/fmod-tiny.S index 5762bcbd1..4ad6ff8ba 100644 --- a/libc/tinymath/fmod.S +++ b/libc/tinymath/fmod-tiny.S @@ -17,6 +17,7 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/macros.internal.h" +#ifdef TINY // fmod [sic] does (𝑥 rem 𝑦) w/ round()-style rounding. // @@ -28,3 +29,5 @@ fmod: ezlea fmodl,ax jmp _d2ld2 .endfn fmod,globl + +#endif /* TINY */ diff --git a/libc/tinymath/fmod.c b/libc/tinymath/fmod.c new file mode 100644 index 000000000..27e89f986 --- /dev/null +++ b/libc/tinymath/fmod.c @@ -0,0 +1,105 @@ +/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│ +│vi: set et ft=c ts=8 tw=8 fenc=utf-8 :vi│ +╚──────────────────────────────────────────────────────────────────────────────╝ +│ │ +│ Musl Libc │ +│ Copyright © 2005-2014 Rich Felker, et al. │ +│ │ +│ Permission is hereby granted, free of charge, to any person obtaining │ +│ a copy of this software and associated documentation files (the │ +│ "Software"), to deal in the Software without restriction, including │ +│ without limitation the rights to use, copy, modify, merge, publish, │ +│ distribute, sublicense, and/or sell copies of the Software, and to │ +│ permit persons to whom the Software is furnished to do so, subject to │ +│ the following conditions: │ +│ │ +│ The above copyright notice and this permission notice shall be │ +│ included in all copies or substantial portions of the Software. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │ +│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │ +│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. │ +│ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY │ +│ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, │ +│ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE │ +│ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ +│ │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "third_party/libcxx/math.h" + +asm(".ident\t\"\\n\\n\ +Musl libc (MIT License)\\n\ +Copyright 2005-2014 Rich Felker, et. al.\""); +asm(".include \"libc/disclaimer.inc\""); +// clang-format off + +/** + * Does (𝑥 rem 𝑦) w/ round()-style rounding. + * @return remainder ∈ (-|𝑦|,|𝑦|) in %xmm0 + * @define 𝑥-trunc(𝑥/𝑦)*𝑦 + */ +double fmod(double x, double y) +{ + union {double f; uint64_t i;} ux = {x}, uy = {y}; + int ex = ux.i>>52 & 0x7ff; + int ey = uy.i>>52 & 0x7ff; + int sx = ux.i>>63; + uint64_t i; + + /* in the followings uxi should be ux.i, but then gcc wrongly adds */ + /* float load/store to inner loops ruining performance and code size */ + uint64_t uxi = ux.i; + + if (uy.i<<1 == 0 || isnan(y) || ex == 0x7ff) + return (x*y)/(x*y); + if (uxi<<1 <= uy.i<<1) { + if (uxi<<1 == uy.i<<1) + return 0*x; + return x; + } + + /* normalize x and y */ + if (!ex) { + for (i = uxi<<12; i>>63 == 0; ex--, i <<= 1); + uxi <<= -ex + 1; + } else { + uxi &= -1ULL >> 12; + uxi |= 1ULL << 52; + } + if (!ey) { + for (i = uy.i<<12; i>>63 == 0; ey--, i <<= 1); + uy.i <<= -ey + 1; + } else { + uy.i &= -1ULL >> 12; + uy.i |= 1ULL << 52; + } + + /* x mod y */ + for (; ex > ey; ex--) { + i = uxi - uy.i; + if (i >> 63 == 0) { + if (i == 0) + return 0*x; + uxi = i; + } + uxi <<= 1; + } + i = uxi - uy.i; + if (i >> 63 == 0) { + if (i == 0) + return 0*x; + uxi = i; + } + for (; uxi>>52 == 0; uxi <<= 1, ex--); + + /* scale result */ + if (ex > 0) { + uxi -= 1ULL << 52; + uxi |= (uint64_t)ex << 52; + } else { + uxi >>= -ex + 1; + } + uxi |= (uint64_t)sx << 63; + ux.i = uxi; + return ux.f; +} diff --git a/libc/x/rmrf.c b/libc/x/rmrf.c index b84d78191..257920356 100644 --- a/libc/x/rmrf.c +++ b/libc/x/rmrf.c @@ -58,6 +58,8 @@ static int rmrfdir(const char *dirpath) { /** * Recursively removes file or directory. + * + * @return 0 on success, or -1 w/ errno */ int rmrf(const char *path) { int e; diff --git a/test/libc/calls/mkntpath_test.c b/test/libc/calls/mkntpath_test.c index 06baab1f6..5da2e10c2 100644 --- a/test/libc/calls/mkntpath_test.c +++ b/test/libc/calls/mkntpath_test.c @@ -50,3 +50,8 @@ TEST(mkntpath, testRemoveDoubleSlash) { EXPECT_EQ(8, __mkntpath("\\\\?\\doge", p)); EXPECT_STREQ(u"\\\\?\\doge", p); } + +TEST(mkntpath, testJustC) { + EXPECT_EQ(7, __mkntpath("/C", p)); + EXPECT_STREQ(u"\\\\?\\C:\\", p); +} diff --git a/test/libc/str/strcmp_test.c b/test/libc/str/strcmp_test.c index c17b2a064..eb953c56e 100644 --- a/test/libc/str/strcmp_test.c +++ b/test/libc/str/strcmp_test.c @@ -534,8 +534,8 @@ void longstringislong_dupe(size_t size, char data[size], char dupe[size]) { BENCH(bench_00_strcmp, bench) { size_t size; char *dupe, *data; - size = ROUNDDOWN(MAX(FRAMESIZE, getcachesize(kCpuCacheTypeData, 1)) / 2, - PAGESIZE); + + size = 14139; data = gc(malloc(size)); dupe = gc(malloc(size)); @@ -576,8 +576,7 @@ BENCH(bench_00_strcmp, bench) { BENCH(bench_01_strcasecmp, bench) { size_t size; char *dupe, *data; - size = ROUNDDOWN(MAX(FRAMESIZE, getcachesize(kCpuCacheTypeData, 1)) / 2, - PAGESIZE); + size = 141393; data = gc(malloc(size)); dupe = gc(malloc(size)); diff --git a/test/libc/tinymath/fmod_test.c b/test/libc/tinymath/fmod_test.c index 0bcfad25d..a9d9ddff0 100644 --- a/test/libc/tinymath/fmod_test.c +++ b/test/libc/tinymath/fmod_test.c @@ -17,8 +17,8 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/math.h" -#include "libc/stdio/rand.h" #include "libc/runtime/gc.internal.h" +#include "libc/stdio/rand.h" #include "libc/testlib/ezbench.h" #include "libc/testlib/testlib.h" #include "libc/x/x.h" @@ -67,7 +67,19 @@ TEST(fmodf, test) { EXPECT_STREQ("8e+20", gc(xdtoaf(fmodf(8e20, 32e20)))); } -BENCH(fmod, bench) { - EZBENCH2("fmod eze", donothing, fmodl(8, 32)); - EZBENCH2("fmod big", donothing, fmodl(5.319372648326541e+255, M_2_PI)); +BENCH(fmodf, bench) { + EZBENCH2("fmodf eze", donothing, fmodf(8, 32)); + EZBENCH2("fmodf big", donothing, fmodf(5.319372648326541e+255, M_2_PI)); +} + +BENCH(fmod, bench) { + // fmod-tiny.S goes slow in the average case, fast for big case + EZBENCH2("fmod eze", donothing, fmod(8, 32)); + // fmod.c goes fast for the average case very slow for big case + EZBENCH2("fmod big", donothing, fmod(5.319372648326541e+255, M_2_PI)); +} + +BENCH(fmodl, bench) { + EZBENCH2("fmodl eze", donothing, fmodl(8, 32)); + EZBENCH2("fmodl big", donothing, fmodl(5.319372648326541e+255, M_2_PI)); } diff --git a/test/tool/net/lunix_test.lua b/test/tool/net/lunix_test.lua index b6509fa51..4bb8bd688 100644 --- a/test/tool/net/lunix_test.lua +++ b/test/tool/net/lunix_test.lua @@ -14,7 +14,7 @@ -- PERFORMANCE OF THIS SOFTWARE. gotsigusr1 = false -tmpdir = "o/tmp/lunix_test.%d" % {unix.getpid()} +tmpdir = "%s/o/tmp/lunix_test.%d" % {os.getenv('TMPDIR'), unix.getpid()} function string.starts(String,Start) return string.sub(String,1,string.len(Start))==Start diff --git a/test/tool/net/slurp_test.lua b/test/tool/net/slurp_test.lua index 75d481968..4721c48e2 100644 --- a/test/tool/net/slurp_test.lua +++ b/test/tool/net/slurp_test.lua @@ -13,7 +13,7 @@ -- TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR -- PERFORMANCE OF THIS SOFTWARE. -tmpdir = "o/tmp/lunix_test.%d" % {unix.getpid()} +tmpdir = "%s/o/tmp/lunix_test.%d" % {os.getenv('TMPDIR'), unix.getpid()} local function Path(name) return tmpdir .. '/' .. name diff --git a/third_party/make/config.h b/third_party/make/config.h index 14385ed0b..16f429cfa 100644 --- a/third_party/make/config.h +++ b/third_party/make/config.h @@ -620,7 +620,7 @@ /* #undef HAVE__SET_INVALID_PARAMETER_HANDLER */ /* Build host information. */ -#define MAKE_HOST "x86_64-pc-cosmopolitan" +#define MAKE_HOST "x86_64-cosmopolitan" /* Define to 1 to enable job server support in GNU make. */ /* TODO(jart): make it work */ diff --git a/third_party/make/debug.h b/third_party/make/debug.h index a6363ff01..84440f107 100644 --- a/third_party/make/debug.h +++ b/third_party/make/debug.h @@ -15,6 +15,8 @@ A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ +#include "libc/intrin/likely.h" + #define DB_NONE (0x000) #define DB_BASIC (0x001) #define DB_VERBOSE (0x002) @@ -26,7 +28,7 @@ this program. If not, see . */ extern int db_level; -#define ISDB(_l) ((_l)&db_level) +#define ISDB(_l) UNLIKELY((_l)&db_level) /* When adding macros to this list be sure to update the value of XGETTEXT_OPTIONS in the po/Makevars file. */ diff --git a/third_party/make/getloadavg.c b/third_party/make/getloadavg.c deleted file mode 100644 index 24b53edb4..000000000 --- a/third_party/make/getloadavg.c +++ /dev/null @@ -1,157 +0,0 @@ -/* clang-format off */ -/* Get the system load averages. - - Copyright (C) 1985-1989, 1991-1995, 1997, 1999-2000, 2003-2020 Free Software - Foundation, Inc. - - NOTE: The canonical source of this file is maintained with gnulib. - Bugs can be reported to bug-gnulib@gnu.org. - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . */ - -/* Compile-time symbols that this file uses: - - HAVE_PSTAT_GETDYNAMIC Define this if your system has the - pstat_getdynamic function. I think it - is unique to HPUX9. The best way to get the - definition is through the AC_FUNC_GETLOADAVG - macro that comes with autoconf 2.13 or newer. - If that isn't an option, then just put - AC_CHECK_FUNCS(pstat_getdynamic) in your - configure.ac file. - HAVE_LIBPERFSTAT Define this if your system has the - perfstat_cpu_total function in libperfstat (AIX). - FIXUP_KERNEL_SYMBOL_ADDR() Adjust address in returned struct nlist. - KERNEL_FILE Name of the kernel file to nlist. - LDAV_CVT() Scale the load average from the kernel. - Returns a double. - LDAV_SYMBOL Name of kernel symbol giving load average. - LOAD_AVE_TYPE Type of the load average array in the kernel. - Must be defined unless one of - apollo, DGUX, NeXT, or UMAX is defined; - or we have libkstat; - otherwise, no load average is available. - HAVE_NLIST_H nlist.h is available. NLIST_STRUCT defaults - to this. - NLIST_STRUCT Include nlist.h, not a.out.h. - N_NAME_POINTER The nlist n_name element is a pointer, - not an array. - HAVE_STRUCT_NLIST_N_UN_N_NAME 'n_un.n_name' is member of 'struct nlist'. - LINUX_LDAV_FILE [__linux__, __ANDROID__, __CYGWIN__]: File - containing load averages. - - Specific system predefines this file uses, aside from setting - default values if not emacs: - - apollo - BSD Real BSD, not just BSD-like. - DGUX - eunice UNIX emulator under VMS. - hpux - __MSDOS__ No-op for MSDOS. - NeXT - sgi - UMAX - UMAX4_3 - VMS - _WIN32 Native Windows (possibly also defined on Cygwin) - __linux__, __ANDROID__ Linux: assumes /proc file system mounted. - Support from Michael K. Johnson. - __CYGWIN__ Cygwin emulates linux /proc/loadavg. - __NetBSD__ NetBSD: assumes /kern file system mounted. - - In addition, to avoid nesting many #ifdefs, we internally set - LDAV_DONE to indicate that the load average has been computed. - - We also #define LDAV_PRIVILEGED if a program will require - special installation to be able to call getloadavg. */ - -#include "libc/sysv/consts/o.h" -#include "libc/errno.h" -#include "libc/dce.h" -#include "libc/dce.h" -#include "libc/dce.h" -#include "libc/sysv/errfuns.h" -#include "libc/stdio/stdio.h" -#include "third_party/make/config.h" -#include "third_party/make/intprops.h" - -/* Put the 1 minute, 5 minute and 15 minute load averages - into the first NELEM elements of LOADAVG. - Return the number written (never more than 3, but may be less than NELEM), - or -1 (setting errno) if an error occurred. */ - -int -getloadavg (double loadavg[], int nelem) -{ - int elem = 0; /* Return value. */ - if (IsLinux()) { - char ldavgbuf[3 * (INT_STRLEN_BOUND (int) + sizeof ".00 ")]; - char const *ptr = ldavgbuf; - int fd, count, saved_errno; - fd = open ("/proc/loadavg", O_RDONLY); - if (fd == -1) - return -1; - count = read (fd, ldavgbuf, sizeof ldavgbuf - 1); - saved_errno = errno; - (void) close (fd); - errno = saved_errno; - if (count <= 0) - return -1; - ldavgbuf[count] = '\0'; - for (elem = 0; elem < nelem; elem++) - { - double numerator = 0; - double denominator = 1; - while (*ptr == ' ') - ptr++; - /* Finish if this number is missing, and report an error if all - were missing. */ - if (! ('0' <= *ptr && *ptr <= '9')) - { - if (elem == 0) - return enotsup(); - break; - } - while ('0' <= *ptr && *ptr <= '9') - numerator = 10 * numerator + (*ptr++ - '0'); - if (*ptr == '.') - for (ptr++; '0' <= *ptr && *ptr <= '9'; ptr++) - numerator = 10 * numerator + (*ptr - '0'), denominator *= 10; - loadavg[elem++] = numerator / denominator; - } - } else if (IsNetbsd()) { - unsigned long int load_ave[3], scale; - int count; - FILE *fp; - fp = fopen ("/kern/loadavg", "r"); - if (fp == NULL) - return -1; - count = fscanf (fp, "%lu %lu %lu %lu\n", - &load_ave[0], &load_ave[1], &load_ave[2], - &scale); - fclose (fp); - if (count != 4) - return enotsup(); - for (elem = 0; elem < nelem; elem++) - loadavg[elem] = (double) load_ave[elem] / (double) scale; - } else if (IsWindows()) { - for ( ; elem < nelem; elem++) - loadavg[elem] = 0.0; - } else { - errno = ENOSYS; - elem = -1; - } - return elem; -} diff --git a/third_party/make/job.c b/third_party/make/job.c index a571b7497..3852add06 100644 --- a/third_party/make/job.c +++ b/third_party/make/job.c @@ -1,4 +1,3 @@ -/* clang-format off */ /* Job execution and handling for GNU Make. Copyright (C) 1988-2020 Free Software Foundation, Inc. This file is part of GNU Make. @@ -21,55 +20,40 @@ this program. If not, see . */ #include "third_party/make/filedef.h" #include "third_party/make/job.h" /**/ -#include "third_party/make/commands.h" -#include "third_party/make/os.h" -#include "third_party/make/variable.h" -#include "libc/log/log.h" -#include "libc/runtime/stack.h" -#include "libc/calls/calls.h" -#include "libc/x/x.h" -#include "libc/intrin/safemacros.internal.h" -#include "libc/x/x.h" -#include "libc/runtime/runtime.h" -#include "libc/intrin/safemacros.internal.h" -#include "libc/elf/struct/ehdr.h" -#include "libc/intrin/bits.h" -#include "libc/intrin/kprintf.h" -#include "libc/intrin/kprintf.h" -#include "libc/intrin/safemacros.internal.h" -#include "libc/runtime/runtime.h" -#include "libc/elf/def.h" -#include "libc/intrin/kprintf.h" -#include "libc/elf/struct/phdr.h" -#include "libc/elf/def.h" -#include "libc/elf/elf.h" -#include "libc/calls/calls.h" -#include "libc/sysv/consts/prot.h" -#include "libc/sysv/consts/map.h" -#include "libc/intrin/kprintf.h" -#include "libc/sysv/consts/o.h" -#include "libc/calls/struct/timeval.h" -#include "libc/x/x.h" -#include "libc/intrin/kprintf.h" -#include "libc/time/time.h" -#include "libc/calls/calls.h" -#include "libc/intrin/kprintf.h" #include "libc/assert.h" -#include "libc/sysv/consts/pr.h" +#include "libc/calls/calls.h" #include "libc/calls/struct/bpf.h" #include "libc/calls/struct/filter.h" #include "libc/calls/struct/seccomp.h" -#include "libc/calls/struct/filter.h" -#include "libc/sysv/consts/pr.h" -#include "libc/sysv/consts/pr.h" -#include "libc/sysv/consts/audit.h" -#include "libc/sysv/consts/nrlinux.h" -#include "libc/macros.internal.h" +#include "libc/calls/struct/timeval.h" +#include "libc/elf/def.h" +#include "libc/elf/elf.h" +#include "libc/elf/struct/ehdr.h" +#include "libc/elf/struct/phdr.h" +#include "libc/fmt/fmt.h" +#include "libc/intrin/bits.h" +#include "libc/intrin/safemacros.internal.h" +#include "libc/log/backtrace.internal.h" +#include "libc/log/log.h" #include "libc/log/rop.h" -#include "libc/intrin/kprintf.h" +#include "libc/macros.internal.h" +#include "libc/runtime/runtime.h" +#include "libc/runtime/stack.h" #include "libc/sock/sock.h" -#include "libc/intrin/kprintf.h" +#include "libc/str/str.h" +#include "libc/sysv/consts/audit.h" +#include "libc/sysv/consts/map.h" +#include "libc/sysv/consts/nrlinux.h" +#include "libc/sysv/consts/o.h" +#include "libc/sysv/consts/pr.h" +#include "libc/sysv/consts/prot.h" +#include "libc/time/time.h" +#include "libc/x/x.h" +#include "third_party/make/commands.h" #include "third_party/make/dep.h" +#include "third_party/make/os.h" +#include "third_party/make/variable.h" +// clang-format off #define GOTO_SLOW \ do { \ @@ -391,6 +375,134 @@ child_error (struct child *child, } +/* [jart] manage temporary directories per rule */ + +const char * +get_tmpdir (struct file *file) +{ + const struct variable *var; + if ((var = lookup_variable_in_set (STRING_SIZE_TUPLE("TMPDIR"), + file->variables->set)) || + (file->pat_variables && + (var = lookup_variable_in_set (STRING_SIZE_TUPLE("TMPDIR"), + file->pat_variables->set))) || + (var = lookup_variable (STRING_SIZE_TUPLE("TMPDIR")))) + return variable_expand (var->value); + else + return kTmpPath; +} + +char * +new_tmpdir (const char *tmp, struct file *file) +{ + const char *s; + int c, e, i, j; + char *dir, *tmpdir; + char cwd[PATH_MAX]; + char path[PATH_MAX]; + + /* create temporary directory in tmp */ + i = 0; + + /* ensure tmpdir will be absolute */ + if (tmp[0] != '/') + { + if (getcwd(cwd, sizeof(cwd))) + { + for (j = 0; cwd[j]; ++j) + if (i < PATH_MAX) + path[i++] = cwd[j]; + if (i && path[i - 1] != '/') + if (i < PATH_MAX) + path[i++] = '/'; + } + else + DB (DB_JOBS, (_("Failed to get current directory\n"))); + } + + /* copy old tmpdir */ + for (j = 0; tmp[j]; ++j) + if (i < PATH_MAX) + path[i++] = tmp[j]; + + /* append slash */ + if (i && path[i - 1] != '/') + if (i < PATH_MAX) + path[i++] = '/'; + + /* append target name safely */ + for (j = 0; (c = file->name[j]); ++j) + { + if (isalnum(c)) + c = tolower(c); + else + c = '_'; + if (i < PATH_MAX) + path[i++] = c; + } + + /* copy random template */ + s = ".XXXXXX"; + for (j = 0; s[j]; ++j) + if (i < PATH_MAX) + path[i++] = s[j]; + + /* add nul terminator */ + if (i + 11 < PATH_MAX) + path[i] = 0; + else + { + DB (DB_JOBS, (_("Creating TMPDIR in %s for %s is too long\n"), + tmp, file->name)); + return 0; + } + + /* create temp directory with random data */ + e = errno; + if (!(tmpdir = mkdtemp (path)) && errno == ENOENT) + { + /* create parent directories if necessary */ + char *dir; + errno = e; + dir = xstrdup (path); + if (!makedirs (dirname (dir), 0700)) + tmpdir = mkdtemp (path); + free (dir); + } + + /* returned string must be free'd */ + if (tmpdir) + { + tmpdir = xstrdup (tmpdir); + DB (DB_JOBS, (_("Created TMPDIR %s\n"), path)); + } + else + DB (DB_JOBS, (_("Creating TMPDIR %s failed %s\n"), + path, strerror (errno))); + + return tmpdir; +} + +void +delete_tmpdir (struct child *c) +{ + if (!c->tmpdir) return; + + DB (DB_JOBS, (_("Deleting TMPDIR %s\n"), c->tmpdir)); + + if (!isdirectory (c->tmpdir)) + DB (DB_JOBS, (_("Warning TMPDIR %s doesn't exist\n"), c->tmpdir)); + + errno = 0; + if (rmrf (c->tmpdir)) + DB (DB_JOBS, (_("Deleting TMPDIR %s failed %s\n"), + c->tmpdir, strerror(errno))); + + free (c->tmpdir); + c->tmpdir = 0; +} + + /* Handle a dead child. This handler may or may not ever be installed. If we're using the jobserver feature without pselect(), we need it. @@ -642,6 +754,7 @@ reap_children (int block, int err) } if (exit_sig != 0 || delete_on_error) delete_child_targets (c); + delete_tmpdir (c); } else { @@ -693,10 +806,13 @@ reap_children (int block, int err) delete_child_targets (c); } else - /* There are no more commands. We got through them all - without an unignored error. Now the target has been - successfully updated. */ - c->file->update_status = us_success; + { + /* There are no more commands. We got through them all + without an unignored error. Now the target has been + successfully updated. */ + c->file->update_status = us_success; + delete_tmpdir (c); + } } /* When we get here, all the commands for c->file are finished. */ @@ -800,6 +916,7 @@ free_child (struct child *child) free (child->environment); } + free (child->tmpdir); free (child->cmd_name); free (child); } @@ -1133,10 +1250,12 @@ start_waiting_job (struct child *c) void new_job (struct file *file) { + struct commands *cmds = file->cmds; + struct variable *var; struct child *c; - char **lines; unsigned int i; + char **lines; /* Let any previously decided-upon jobs that are waiting for the load to go down start before this new one. */ @@ -1157,6 +1276,14 @@ new_job (struct file *file) c->file = file; c->sh_batch_file = NULL; + /* [jart] manage temporary directories per rule */ + if ((c->tmpdir = new_tmpdir (get_tmpdir (file), file))) + { + var = define_variable_for_file ("TMPDIR", 6, c->tmpdir, + o_override, 0, file); + var->export = v_export; + } + /* Cache dontcare flag because file->dontcare can be changed once we return. Check dontcare inheritance mechanism for details. */ c->dontcare = file->dontcare; @@ -1473,83 +1600,12 @@ load_too_high (void) OK, I'm not sure exactly how to handle that, but for sure we need to clamp this value at the number of cores before this can be enabled. */ -#define PROC_FD_INIT -1 - static int proc_fd = PROC_FD_INIT; - double load, guess; time_t now; -#ifdef WINDOWS32 - /* sub_proc.c is limited in the number of objects it can wait for. */ - if (process_table_full ()) - return 1; -#endif - if (max_load_average < 0) return 0; - /* If we haven't tried to open /proc/loadavg, try now. */ -#define LOADAVG "/proc/loadavg" - if (proc_fd == -2) - { - EINTRLOOP (proc_fd, open (LOADAVG, O_RDONLY)); - if (proc_fd < 0) - DB (DB_JOBS, ("Using system load detection method.\n")); - else - { - DB (DB_JOBS, ("Using " LOADAVG " load detection method.\n")); - fd_noinherit (proc_fd); - } - } - - /* Try to read /proc/loadavg if we managed to open it. */ - if (proc_fd >= 0) - { - int r; - - EINTRLOOP (r, lseek (proc_fd, 0, SEEK_SET)); - if (r >= 0) - { -#define PROC_LOADAVG_SIZE 64 - char avg[PROC_LOADAVG_SIZE+1]; - - EINTRLOOP (r, read (proc_fd, avg, PROC_LOADAVG_SIZE)); - if (r >= 0) - { - const char *p; - - /* The syntax of /proc/loadavg is: - <1m> <5m> <15m> / - The load is considered too high if there are more jobs - running than the requested average. */ - - avg[r] = '\0'; - p = strchr (avg, ' '); - if (p) - p = strchr (p+1, ' '); - if (p) - p = strchr (p+1, ' '); - - if (p && ISDIGIT(p[1])) - { - int cnt = atoi (p+1); - DB (DB_JOBS, ("Running: system = %d / make = %u (max requested = %f)\n", - cnt, job_slots_used, max_load_average)); - return (double)cnt > max_load_average; - } - - DB (DB_JOBS, ("Failed to parse " LOADAVG ": %s\n", avg)); - } - } - - /* If we 𝑔𝑜𝑡 𝑕𝑒𝑟𝑒, something went wrong. Give up on this method. */ - if (r < 0) - DB (DB_JOBS, ("Failed to read " LOADAVG ": %s\n", strerror (errno))); - - close (proc_fd); - proc_fd = -1; - } - /* Find the real system load average. */ make_access (); if (getloadavg (&load, 1) != 1) @@ -1622,7 +1678,7 @@ start_waiting_jobs (void) bool -GetPermPrefix (const char *path, char out_perm[5], const char **out_path) +get_perm_prefix (const char *path, char out_perm[5], const char **out_path) { int c, n; for (n = 0;;) @@ -1656,7 +1712,7 @@ Unveil (const char *path, const char *perm) char permprefix[5]; /* if path is like `rwcx:o/tmp` then `rwcx` will override perm */ - if (path && GetPermPrefix (path, permprefix, &path)) + if (path && get_perm_prefix (path, permprefix, &path)) perm = permprefix; fp[0] = 0; @@ -1665,6 +1721,8 @@ Unveil (const char *path, const char *perm) (fp[1] = tilde_expand ((fp[0] = xstrdup (path))))) path = fp[1]; + DB (DB_JOBS, (_("Unveiling %s with permissions %s\n"), path, perm)); + e = errno; if (unveil (path, perm) != -1) { @@ -1690,7 +1748,7 @@ Unveil (const char *path, const char *perm) } int -UnveilVariable (const struct variable *var) +unveil_variable (const struct variable *var) { char *val, *tok, *state, *start; if (!var) return 0; @@ -1759,7 +1817,7 @@ child_execute_job (struct childbase *child, int good_stdin, char **argv) if (fderr != FD_STDERR) EINTRLOOP (r, dup2 (fderr, FD_STDERR)); - g_strict = Vartoi (lookup_variable (STRING_SIZE_TUPLE(".STRICT"))); + g_strict = Vartoi (lookup_variable (STRING_SIZE_TUPLE (".STRICT"))); intptr_t loc = (intptr_t)child; /* we can cast if it's on the heap ;_; */ if (!(GetStackAddr() < loc && loc < GetStackAddr() + GetStackSize())) { @@ -1798,6 +1856,8 @@ child_execute_job (struct childbase *child, int good_stdin, char **argv) errno = 0; if (sandboxed) { + DB (DB_JOBS, (_("Sandboxing %s\n"), c->file->name)); + if (!g_strict && argv[0][0] == '/' && IsDynamicExecutable (argv[0])) { /* @@ -1854,10 +1914,14 @@ child_execute_job (struct childbase *child, int good_stdin, char **argv) /* unveil executable */ RETURN_ON_ERROR (Unveil (argv[0], "rx")); + /* unveil temporary directory */ + if (c->tmpdir) + RETURN_ON_ERROR (Unveil (c->tmpdir, "rwcx")); + + /* unveil lazy mode files */ if (!g_strict) { RETURN_ON_ERROR (Unveil ("/tmp", "rwc")); - RETURN_ON_ERROR (Unveil ("o/tmp", "rwcx")); RETURN_ON_ERROR (Unveil ("/dev/zero", "r")); RETURN_ON_ERROR (Unveil ("/dev/null", "rw")); RETURN_ON_ERROR (Unveil ("/dev/full", "rw")); @@ -1893,6 +1957,8 @@ child_execute_job (struct childbase *child, int good_stdin, char **argv) c->file->name, strerror (errno)); return -1; } + DB (DB_JOBS, (_("Unveiling %s with permissions %s\n"), + c->file->name, "rwx")); if (unveil (c->file->name, "rwx") && errno != ENOSYS) { OSS (error, NILF, "%s: unveil target failed %s", @@ -1915,17 +1981,17 @@ child_execute_job (struct childbase *child, int good_stdin, char **argv) /* unveil explicit .UNVEIL entries */ RETURN_ON_ERROR - (UnveilVariable + (unveil_variable (lookup_variable (STRING_SIZE_TUPLE (".UNVEIL")))); RETURN_ON_ERROR - (UnveilVariable + (unveil_variable (lookup_variable_in_set (STRING_SIZE_TUPLE (".UNVEIL"), c->file->variables->set))); if (c->file->pat_variables) RETURN_ON_ERROR - (UnveilVariable + (unveil_variable (lookup_variable_in_set (STRING_SIZE_TUPLE (".UNVEIL"), c->file->pat_variables->set))); diff --git a/third_party/make/job.h b/third_party/make/job.h index 870d0b98a..1219258a6 100644 --- a/third_party/make/job.h +++ b/third_party/make/job.h @@ -41,6 +41,7 @@ struct child struct file *file; /* File being remade. */ + char *tmpdir; /* Temporary directory */ char *sh_batch_file; /* Script file for shell commands */ char **command_lines; /* Array of variable-expanded cmd lines. */ char *command_ptr; /* Ptr into command_lines[command_line]. */ diff --git a/third_party/make/main.c b/third_party/make/main.c index faab247fa..5071c7c4a 100644 --- a/third_party/make/main.c +++ b/third_party/make/main.c @@ -45,6 +45,8 @@ this program. If not, see . */ #include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h" +#include "libc/log/log.h" +#include "libc/log/log.h" #include "third_party/make/getopt.h" STATIC_STACK_SIZE(0x200000); // 2mb stack @@ -355,6 +357,10 @@ static const char *const usage[] = Consider FILE to be infinitely new.\n"), N_("\ --warn-undefined-variables Warn when an undefined variable is referenced.\n"), + N_("\ + --strace Log system calls.\n"), + N_("\ + --ftrace Log function calls.\n"), NULL }; @@ -1101,11 +1107,7 @@ main (int argc, char **argv, char **envp) /* Figure out where we are. */ -#ifdef WINDOWS32 - if (getcwd_fs (current_directory, GET_PATH_MAX) == 0) -#else if (getcwd (current_directory, GET_PATH_MAX) == 0) -#endif { #ifdef HAVE_GETCWD perror_with_name ("getcwd", ""); @@ -2980,7 +2982,7 @@ print_version (void) /* Do it only once. */ return; - printf ("%sLandlock Make 1.0.1 (GNU Make %s)\n", precede, version_string); + printf ("%sLandlock Make 1.1.1 (GNU Make %s)\n", precede, version_string); if (!remote_description || *remote_description == '\0') printf (_("%sBuilt for %s\n"), precede, make_host); @@ -2993,6 +2995,8 @@ print_version (void) year, and none of the rest of it should be translated (including the word "Copyright"), so it hardly seems worth it. */ + printf ("%sCopyright (C) 2022 Justine Alexandra Roberts Tunney\n", + precede); printf ("%sCopyright (C) 1988-2020 Free Software Foundation, Inc.\n", precede); diff --git a/third_party/make/make.mk b/third_party/make/make.mk index 3df09c3db..b034c1cf8 100644 --- a/third_party/make/make.mk +++ b/third_party/make/make.mk @@ -65,7 +65,6 @@ THIRD_PARTY_MAKE_SRCS_LIB = \ third_party/make/fcntl.c \ third_party/make/fd-hook.c \ third_party/make/findprog-in.c \ - third_party/make/getloadavg.c \ third_party/make/getprogname.c \ third_party/make/stripslash.c \ third_party/make/unistd.c \ diff --git a/third_party/mbedtls/test/test.mk b/third_party/mbedtls/test/test.mk index d7acf12b5..177828317 100644 --- a/third_party/mbedtls/test/test.mk +++ b/third_party/mbedtls/test/test.mk @@ -408,6 +408,7 @@ o/$(MODE)/third_party/mbedtls/test/test_suite_cipher.padding.com.dbg: \ $(APE_NO_MODIFY_SELF) @$(APELINK) +o/$(MODE)/third_party/mbedtls/test/test_suite_ctr_drbg.com.runs: private .UNVEIL += rwc:o/tmp o/$(MODE)/third_party/mbedtls/test/test_suite_ctr_drbg.com: o/$(MODE)/third_party/mbedtls/test/test_suite_ctr_drbg.com.dbg o/$(MODE)/third_party/mbedtls/test/test_suite_ctr_drbg.com.dbg: \ $(THIRD_PARTY_MBEDTLS_TEST_DEPS) \ @@ -586,6 +587,7 @@ o/$(MODE)/third_party/mbedtls/test/test_suite_hkdf.com.dbg: \ $(APE_NO_MODIFY_SELF) @$(APELINK) +o/$(MODE)/third_party/mbedtls/test/test_suite_hmac_drbg.misc.com.runs: private .UNVEIL += rwc:o/tmp o/$(MODE)/third_party/mbedtls/test/test_suite_hmac_drbg.misc.com: o/$(MODE)/third_party/mbedtls/test/test_suite_hmac_drbg.misc.com.dbg o/$(MODE)/third_party/mbedtls/test/test_suite_hmac_drbg.misc.com.dbg: \ $(THIRD_PARTY_MBEDTLS_TEST_DEPS) \ @@ -668,6 +670,7 @@ o/$(MODE)/third_party/mbedtls/test/test_suite_memory_buffer_alloc.com.dbg: \ $(APE_NO_MODIFY_SELF) @$(APELINK) +o/$(MODE)/third_party/mbedtls/test/test_suite_mpi.com.runs: private .UNVEIL += rwc:o/tmp o/$(MODE)/third_party/mbedtls/test/test_suite_mpi.com: o/$(MODE)/third_party/mbedtls/test/test_suite_mpi.com.dbg o/$(MODE)/third_party/mbedtls/test/test_suite_mpi.com.dbg: \ $(THIRD_PARTY_MBEDTLS_TEST_DEPS) \ diff --git a/third_party/quickjs/quickjs-libc.c b/third_party/quickjs/quickjs-libc.c index 60123889f..07fb0622f 100644 --- a/third_party/quickjs/quickjs-libc.c +++ b/third_party/quickjs/quickjs-libc.c @@ -615,24 +615,6 @@ static JSValue js_std_getenv(JSContext *ctx, JSValueConst this_val, return JS_NewString(ctx, str); } -#if defined(_WIN32) -static void setenv(const char *name, const char *value, int overwrite) -{ - char *str; - size_t name_len, value_len; - name_len = strlen(name); - value_len = strlen(value); - str = malloc(name_len + 1 + value_len + 1); - memcpy(str, name, name_len); - str[name_len] = '='; - memcpy(str + name_len + 1, value, value_len); - str[name_len + 1 + value_len] = '\0'; - _putenv(str); - free(str); -} - -#endif /* _WIN32 */ - static JSValue js_std_setenv(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) {