From aeeb85142246b3fc9f4267ccdd88358e163ce118 Mon Sep 17 00:00:00 2001 From: Justine Tunney Date: Fri, 6 Aug 2021 14:12:11 -0700 Subject: [PATCH] Fix bugs and make improvements to redbean - Abort if .init.lua fails - Refactor redbean to use new append library - Use first certificate if SNI routing fails - Use function/data sections when building Lua - Don't use self-signed auto-generated cert for client - Add -D staging dirs to redbean lua module default path --- libc/rand/measureentropy.c | 3 +- libc/runtime/memtrack.h | 18 +- libc/stdio/append.internal.h | 25 +- libc/stdio/appendd.c | 17 +- libc/stdio/appendf.c | 11 +- libc/stdio/appendr.c | 71 ++++ libc/stdio/appends.c | 14 +- libc/stdio/appendw.c | 30 +- libc/stdio/appendz.c | 3 + libc/stdio/stdio.mk | 4 + libc/stdio/vappendf.c | 4 +- test/libc/rand/getrandom_test.c | 123 ------ test/libc/rand/measureentropy_test.c | 146 +++++++ test/libc/stdio/vappendf_test.c | 87 ++++- third_party/lua/loadlib.c | 9 +- third_party/lua/lua.h | 44 +-- third_party/lua/lua.mk | 5 + third_party/lua/luaconf.h | 79 +--- third_party/mbedtls/config.h | 1 + third_party/mbedtls/ecp384.c | 32 +- third_party/mbedtls/ecp_internal.h | 1 - third_party/mbedtls/test/secp384r1_test.c | 39 +- tool/net/demo/printpayload.lua | 2 +- tool/net/help.txt | 3 +- tool/net/net.mk | 1 - tool/net/redbean.c | 444 ++++++++++++---------- 26 files changed, 703 insertions(+), 513 deletions(-) create mode 100644 libc/stdio/appendr.c create mode 100644 test/libc/rand/measureentropy_test.c diff --git a/libc/rand/measureentropy.c b/libc/rand/measureentropy.c index 4c18a2044..d591ade21 100644 --- a/libc/rand/measureentropy.c +++ b/libc/rand/measureentropy.c @@ -44,9 +44,10 @@ double MeasureEntropy(const char *p, size_t n) { if (h[i]) { x = h[i]; x /= n; - e += x * log2(1 / x); + e += x * log(x); } } + e = -(e / M_LN2); } return e; } diff --git a/libc/runtime/memtrack.h b/libc/runtime/memtrack.h index 8f7e71a9b..5862f8a72 100644 --- a/libc/runtime/memtrack.h +++ b/libc/runtime/memtrack.h @@ -32,16 +32,18 @@ struct MemoryIntervals { } p[128]; }; -extern struct MemoryIntervals _mmi; +extern hidden struct MemoryIntervals _mmi; -unsigned FindMemoryInterval(const struct MemoryIntervals *, int) nosideeffect; -bool AreMemoryIntervalsOk(const struct MemoryIntervals *) nosideeffect; -void PrintMemoryIntervals(int, const struct MemoryIntervals *); -int TrackMemoryInterval(struct MemoryIntervals *, int, int, long, int, int); +unsigned FindMemoryInterval(const struct MemoryIntervals *, + int) nosideeffect hidden; +bool AreMemoryIntervalsOk(const struct MemoryIntervals *) nosideeffect hidden; +void PrintMemoryIntervals(int, const struct MemoryIntervals *) hidden; +int TrackMemoryInterval(struct MemoryIntervals *, int, int, long, int, + int) hidden; int ReleaseMemoryIntervals(struct MemoryIntervals *, int, int, - void (*)(struct MemoryIntervals *, int, int)); -void ReleaseMemoryNt(struct MemoryIntervals *, int, int); -int UntrackMemoryIntervals(void *, size_t); + void (*)(struct MemoryIntervals *, int, int)) hidden; +void ReleaseMemoryNt(struct MemoryIntervals *, int, int) hidden; +int UntrackMemoryIntervals(void *, size_t) hidden; COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ diff --git a/libc/stdio/append.internal.h b/libc/stdio/append.internal.h index 047211f68..bb71336c1 100644 --- a/libc/stdio/append.internal.h +++ b/libc/stdio/append.internal.h @@ -1,5 +1,5 @@ -#ifndef COSMOPOLITAN_LIBC_STDIO_APPEND_INTERNAL_H_ -#define COSMOPOLITAN_LIBC_STDIO_APPEND_INTERNAL_H_ +#ifndef COSMOPOLITAN_LIBC_STDIO_APPEND_H_ +#define COSMOPOLITAN_LIBC_STDIO_APPEND_H_ #include "libc/fmt/pflink.h" #define APPEND_COOKIE 21578 @@ -8,22 +8,23 @@ COSMOPOLITAN_C_START_ struct appendz { - size_t i; /* data size */ - size_t n; /* allocation size */ + size_t i; + size_t n; }; -int appendf(char **, const char *, ...); -int vappendf(char **, const char *, va_list); -int appends(char **, const char *); -int appendd(char **, const void *, size_t); -int appendw(char **, uint64_t); struct appendz appendz(char *); +ssize_t appendr(char **, size_t); +ssize_t appendd(char **, const void *, size_t); +ssize_t appendw(char **, uint64_t); +ssize_t appends(char **, const char *); +ssize_t appendf(char **, const char *, ...); +ssize_t vappendf(char **, const char *, va_list); #if defined(__GNUC__) && !defined(__STRICT_ANSI__) -#define appendf(BUF, FMT, ...) (appendf)(BUF, PFLINK(FMT), ##__VA_ARGS__) -#define vappendf(BUF, FMT, VA) (vappendf)(BUF, PFLINK(FMT), VA) +#define appendf(BUF, FMT, ...) appendf(BUF, PFLINK(FMT), ##__VA_ARGS__) +#define vappendf(BUF, FMT, VA) vappendf(BUF, PFLINK(FMT), VA) #endif COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ -#endif /* COSMOPOLITAN_LIBC_STDIO_APPEND_INTERNAL_H_ */ +#endif /* COSMOPOLITAN_LIBC_STDIO_APPEND_H_ */ diff --git a/libc/stdio/appendd.c b/libc/stdio/appendd.c index 18e08f8eb..ffffbcd9b 100644 --- a/libc/stdio/appendd.c +++ b/libc/stdio/appendd.c @@ -26,11 +26,24 @@ #define W sizeof(size_t) /** - * Appends raw data to buffer. + * Appends data to buffer, e.g. + * + * char *b = 0; + * appendd(&b, "hello", 5); + * free(b); + * + * The resulting buffer is guaranteed to be NUL-terminated, i.e. + * `!b[appendz(b).i]` will be the case. + * + * @param s may contain nul characters and may be null if `l` is zero + * @param l is byte length of `s` + * @return bytes appended (always `l`) or -1 if `ENOMEM` + * @see appendz(b).i to get buffer length */ -int appendd(char **b, const void *s, size_t l) { +ssize_t appendd(char **b, const void *s, size_t l) { char *p; struct appendz z; + assert(b); z = appendz((p = *b)); if (ROUNDUP(z.i + l + 1, 8) + W > z.n) { if (!z.n) z.n = W * 2; diff --git a/libc/stdio/appendf.c b/libc/stdio/appendf.c index 209675139..3991d4a9a 100644 --- a/libc/stdio/appendf.c +++ b/libc/stdio/appendf.c @@ -19,9 +19,16 @@ #include "libc/stdio/append.internal.h" /** - * Appends formatted data to buffer. + * Appends formatted string to buffer, e.g. + * + * char *b = 0; + * appendf(&b, "hello %d\n", 123); + * free(b); + * + * @return bytes appended or -1 if `ENOMEM` + * @see appendz(b).i to get buffer length */ -int(appendf)(char **b, const char *fmt, ...) { +ssize_t(appendf)(char **b, const char *fmt, ...) { int n; va_list va; va_start(va, fmt); diff --git a/libc/stdio/appendr.c b/libc/stdio/appendr.c new file mode 100644 index 000000000..c49b216a2 --- /dev/null +++ b/libc/stdio/appendr.c @@ -0,0 +1,71 @@ +/*-*- 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/assert.h" +#include "libc/dce.h" +#include "libc/macros.internal.h" +#include "libc/mem/mem.h" +#include "libc/stdio/append.internal.h" +#include "libc/str/str.h" + +#define W sizeof(size_t) + +/** + * Resets length of append buffer, e.g. + * + * char *b = 0; + * appends(&b, "hello"); + * appendr(&b, 1); + * assert(!strcmp(b, "h")); + * appendr(&b, 0); + * assert(!strcmp(b, "")); + * free(b); + * + * If `i` is greater than the current length then the extra bytes are + * filled with NUL characters. + * + * The resulting buffer is guarranteed to be NUL-terminated, i.e. + * `!b[appendz(b).i]` will be the case. + * + * @return `i` or -1 if `ENOMEM` + * @see appendz(b).i to get buffer length + */ +ssize_t appendr(char **b, size_t i) { + char *p; + struct appendz z; + assert(b); + z = appendz((p = *b)); + z.n = ROUNDUP(i + 1, 8) + W; + if ((p = realloc(p, z.n))) { + z.n = malloc_usable_size(p); + assert(!(z.n & (W - 1))); + *b = p; + } else { + return -1; + } + if (i > z.i) { + memset(p, z.i, i - z.i); + } + z.i = i; + p[z.i] = 0; + if (!IsTiny() && W == 8) { + z.i |= (size_t)APPEND_COOKIE << 48; + } + *(size_t *)(p + z.n - W) = z.i; + return i; +} diff --git a/libc/stdio/appends.c b/libc/stdio/appends.c index b42d86d6f..e2fc22743 100644 --- a/libc/stdio/appends.c +++ b/libc/stdio/appends.c @@ -20,8 +20,18 @@ #include "libc/str/str.h" /** - * Appends string to buffer. + * Appends string to buffer, e.g. + * + * char *b = 0; + * appends(&b, "hello"); + * free(b); + * + * The resulting buffer is guaranteed to be NUL-terminated, i.e. + * `!b[appendz(b).i]` will be the case. + * + * @return bytes appended (always `strlen(s)`) or -1 if `ENOMEM` + * @see appendz(b).i to get buffer length */ -int appends(char **b, const char *s) { +ssize_t appends(char **b, const char *s) { return appendd(b, s, strlen(s)); } diff --git a/libc/stdio/appendw.c b/libc/stdio/appendw.c index 3e54669dd..4ea9a1615 100644 --- a/libc/stdio/appendw.c +++ b/libc/stdio/appendw.c @@ -19,15 +19,33 @@ #include "libc/bits/bits.h" #include "libc/nexgen32e/bsr.h" #include "libc/stdio/append.internal.h" -#include "libc/stdio/stdio.h" /** - * Appends string to buffer. + * Appends character or word-encoded string to buffer. + * + * Up to eight characters can be appended. For example: + * + * appendw(&s, 'h'|'i'<<8); + * + * Is equivalent to: + * + * appends(&s, "hi"); + * + * The special case: + * + * appendw(&s, 0); + * + * Will append a single NUL character. + * + * The resulting buffer is guaranteed to be NUL-terminated, i.e. + * `!b[appendz(b).i]` will be the case. + * + * @return bytes appended or -1 if `ENOMEM` */ -int appendw(char **b, uint64_t w) { +ssize_t appendw(char **b, uint64_t w) { char t[8]; - unsigned l; - if (!w) return 0; + unsigned n = 1; WRITE64LE(t, w); - return appendd(b, t, (bsrl(w) >> 3) + 1); + if (w) n += bsrl(w) >> 3; + return appendd(b, t, n); } diff --git a/libc/stdio/appendz.c b/libc/stdio/appendz.c index b06c2ea9e..12133dd68 100644 --- a/libc/stdio/appendz.c +++ b/libc/stdio/appendz.c @@ -25,6 +25,9 @@ /** * Returns size of append buffer. + * + * @return i is number of bytes stored in buffer + * @return n is number of bytes in allocation */ struct appendz appendz(char *p) { struct appendz z; diff --git a/libc/stdio/stdio.mk b/libc/stdio/stdio.mk index a54636e9c..ad5ae77ae 100644 --- a/libc/stdio/stdio.mk +++ b/libc/stdio/stdio.mk @@ -55,6 +55,10 @@ o/$(MODE)/libc/stdio/fputc.o: \ OVERRIDE_CFLAGS += \ -O3 +o//libc/stdio/appendw.o: \ + OVERRIDE_CFLAGS += \ + -O2 + LIBC_STDIO_LIBS = $(foreach x,$(LIBC_STDIO_ARTIFACTS),$($(x))) LIBC_STDIO_SRCS = $(foreach x,$(LIBC_STDIO_ARTIFACTS),$($(x)_SRCS)) LIBC_STDIO_HDRS = $(foreach x,$(LIBC_STDIO_ARTIFACTS),$($(x)_HDRS)) diff --git a/libc/stdio/vappendf.c b/libc/stdio/vappendf.c index 4e2c03014..531f7ca86 100644 --- a/libc/stdio/vappendf.c +++ b/libc/stdio/vappendf.c @@ -25,9 +25,9 @@ #define W sizeof(size_t) /** - * Appends data to buffer. + * Appends formatted string to buffer. */ -int(vappendf)(char **b, const char *f, va_list v) { +ssize_t(vappendf)(char **b, const char *f, va_list v) { char *p; int r, s; va_list w; diff --git a/test/libc/rand/getrandom_test.c b/test/libc/rand/getrandom_test.c index 2cf6ffb1d..cf335e5bd 100644 --- a/test/libc/rand/getrandom_test.c +++ b/test/libc/rand/getrandom_test.c @@ -258,126 +258,3 @@ TEST(getrandom, sanityTest) { } } } - -TEST(MeasureEntropy, test) { - MeasureEntropy(kMoby, 1000); - EXPECT_EQ(00, lroundl(10 * MeasureEntropy(" ", 12))); - EXPECT_EQ(16, lroundl(10 * MeasureEntropy("abcabcabcabc", 12))); - EXPECT_EQ(36, lroundl(10 * MeasureEntropy("abcdefghijkl", 12))); - EXPECT_EQ(49, lroundl(10 * MeasureEntropy(kMoby, 512))); -} - -TEST(MeasureEntropy, testElfExecutable) { - EXPECT_EQ(19, lroundl(10 * MeasureEntropy("\ -\x7f\x45\x4c\x46\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\ -\x03\x00\x3e\x00\x01\x00\x00\x00\x18\xd7\x00\x00\x00\x00\x00\x00\ -\x40\x00\x00\x00\x00\x00\x00\x00\xc8\xd0\x0c\x00\x00\x00\x00\x00\ -\x00\x00\x00\x00\x40\x00\x38\x00\x09\x00\x40\x00\x16\x00\x15\x00\ -\x06\x00\x00\x00\x04\x00\x00\x00\x40\x00\x00\x00\x00\x00\x00\x00\ -\x40\x00\x00\x00\x00\x00\x00\x00\x40\x00\x00\x00\x00\x00\x00\x00\ -\xf8\x01\x00\x00\x00\x00\x00\x00\xf8\x01\x00\x00\x00\x00\x00\x00\ -\x08\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x04\x00\x00\x00\ -\x38\x02\x00\x00\x00\x00\x00\x00\x38\x02\x00\x00\x00\x00\x00\x00\ -\x38\x02\x00\x00\x00\x00\x00\x00\x19\x00\x00\x00\x00\x00\x00\x00\ -\x19\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\ -\x01\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ -\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ -\x90\xbc\x00\x00\x00\x00\x00\x00\x90\xbc\x00\x00\x00\x00\x00\x00\ -\x00\x10\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x05\x00\x00\x00\ -\x00\xc0\x00\x00\x00\x00\x00\x00\x00\xc0\x00\x00\x00\x00\x00\x00\ -\x00\xc0\x00\x00\x00\x00\x00\x00\x62\xb2\x09\x00\x00\x00\x00\x00\ -\x62\xb2\x09\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\ -\x01\x00\x00\x00\x04\x00\x00\x00\x00\x80\x0a\x00\x00\x00\x00\x00\ -\x00\x80\x0a\x00\x00\x00\x00\x00\x00\x80\x0a\x00\x00\x00\x00\x00\ -\xe4\x09\x02\x00\x00\x00\x00\x00\xe4\x09\x02\x00\x00\x00\x00\x00\ -\x00\x10\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x06\x00\x00\x00\ -\xc0\x95\x0c\x00\x00\x00\x00\x00\xc0\xa5\x0c\x00\x00\x00\x00\x00\ -\xc0\xa5\x0c\x00\x00\x00\x00\x00\x64\x3a\x00\x00\x00\x00\x00\x00\ -\xa8\x42\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\ -\x02\x00\x00\x00\x06\x00\x00\x00\xa0\xc2\x0c\x00\x00\x00\x00\x00\ -\xa0\xd2\x0c\x00\x00\x00\x00\x00\xa0\xd2\x0c\x00\x00\x00\x00\x00\ -\x80\x01\x00\x00\x00\x00\x00\x00\x80\x01\x00\x00\x00\x00\x00\x00\ -\x08\x00\x00\x00\x00\x00\x00\x00\x51\xe5\x74\x64\x06\x00\x00\x00\ -\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ -\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ -\x00\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00", - 512))); -} - -TEST(MeasureEntropy, testApeExecutable) { - EXPECT_EQ(53, lroundl(10 * MeasureEntropy("\ -\x7f\x45\x4c\x46\x02\x01\x01\x09\x00\x00\x00\x00\x00\x00\x00\x00\ -\x02\x00\x3e\x00\x01\x00\x00\x00\x0a\x11\x40\x00\x00\x00\x00\x00\ -\xe0\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ -\x00\x00\x00\x00\x40\x00\x38\x00\x04\x00\x00\x00\x00\x00\x00\x00\ -\xb2\x40\xeb\x00\xeb\x14\x90\x90\xeb\x06\x48\x83\xec\x08\x31\xd2\ -\xbd\x00\x00\xeb\x05\xe9\xb0\x10\x00\x00\xfc\x0f\x1f\x87\x3e\xe0\ -\xbf\x00\x70\x31\xc9\x8e\xc1\xfa\x8e\xd7\x89\xcc\xfb\x0e\x1f\xe8\ -\x00\x00\x5e\x81\xee\x72\x00\xb8\x00\x02\x50\x50\x07\x31\xff\xb9\ -\x00\x02\xf3\xa4\x0f\x1f\x87\xd2\xff\xea\x8e\x20\x00\x00\x8e\xd9\ -\xb9\x00\x1b\xb8\x50\x00\x8e\xc0\x31\xc0\x31\xff\xf3\xaa\x80\xfa\ -\x40\x74\x13\xe8\x15\x00\x07\xb0\x01\x31\xc9\x30\xf6\xbf\x40\x03\ -\xe8\x48\x00\x4f\x75\xfa\xea\x20\x25\x00\x00\x53\x52\xb4\x08\xcd\ -\x13\x72\x2c\x88\xcf\x80\xe7\x3f\x80\xe1\xc0\xd0\xc1\xd0\xc1\x86\ -\xcd\x1e\x06\x1f\x31\xf6\x8e\xc6\xbe\x10\x15\x87\xf7\xa5\xa5\xa5\ -\xa5\xa5\xa4\x1f\x93\xab\x91\xab\x92\xab\x58\xaa\x92\x5b\xc3\x5a\ -\x80\xf2\x80\x31\xc0\xcd\x13\x72\xf7\xeb\xc1\x50\x51\x86\xcd\xd0\ -\xc9\xd0\xc9\x08\xc1\x31\xdb\xb0\x01\xb4\x02\xcd\x13\x59\x58\x72\ -\x1d\x8c\xc6\x83\xc6\x20\x8e\xc6\xfe\xc0\x3a\x06\x1c\x15\x76\x0d\ -\xb0\x01\xfe\xc6\x3a\x36\x20\x15\x76\x03\x30\xf6\x41\xc3\x50\x31\ -\xc0\xcd\x13\x58\xeb\xc5\x89\xfe\xac\x84\xc0\x74\x09\xbb\x07\x00\ -\xb4\x0e\xcd\x10\xeb\xf2\xc3\x57\xbf\x78\x24\xe8\xe8\xff\x5f\xe8\ -\xe4\xff\xbf\x80\x24\xe8\xde\xff\xf3\x90\xeb\xfc\xb9\x04\x00\xbe\ -\x00\x04\xad\x85\xc0\x74\x0b\x51\x56\x97\xbe\x9e\x24\xe8\x05\x00\ -\x5e\x59\xe2\xee\xc3\x89\xfa\x85\xd2\x74\x14\x52\x56\x31\xc9\xb1\ -\x03\x01\xca\xac\x5e\x0c\x80\xee\x5a\xac\xee\x42\x49\x79\xfa\xc3\ -\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ -\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ -\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ -\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ -\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ -\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ -\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x55\xaa", - 512))); -} - -TEST(MeasureEntropy, testDevUrandom) { - EXPECT_EQ(76, lroundl(10 * MeasureEntropy("\ -\x67\xa6\x8f\x6f\x6f\x01\xa4\x60\xa5\x5a\x6a\xfa\x06\xfd\xbb\xbe\ -\xe4\x73\x2f\xc4\x20\x25\xd9\xb2\x78\x7d\x9f\xaf\x5d\x03\x49\x01\ -\x90\x94\x8a\xc0\x33\x78\xe0\x65\xd8\x9c\x19\x96\x25\x90\xc8\x6e\ -\xf2\x65\xac\x72\xd9\x8e\x58\x05\x26\x22\xa3\x58\x41\x40\xee\x3c\ -\x3a\xb0\x08\x7c\x70\x0e\x23\xdc\x52\x10\x21\x5c\xb7\x3d\x3a\xce\ -\x7c\xd7\x2a\x8c\x35\x0c\x21\x2b\x03\x75\xbe\x0c\x49\x5b\xdb\x7a\ -\x7e\xeb\x27\x03\x56\xca\x9f\xf8\x00\xb4\x4d\x5b\xd6\xde\x41\xd6\ -\x86\x7b\x3c\x13\xd4\x2d\xd4\xe9\x79\x05\x48\xcc\xa5\x17\xf8\xb6\ -\x74\xdf\x39\x70\x32\x64\x70\x10\xfb\x53\x06\x87\xef\xff\x9f\x4c\ -\x07\xee\x09\x54\xb8\xda\x1a\x49\x9b\x12\x3a\xf9\xc3\x55\xbc\xa5\ -\xad\x6c\x3d\x1f\x39\x84\xc6\xac\x45\x14\x4f\xa9\xfc\xd6\xfb\xce\ -\x41\xf8\x78\x85\xe5\x72\x9c\x0c\xd3\x81\x9b\xa4\x72\xc9\xd5\xc8\ -\xc2\x3c\xcc\x36\x58\xf6\x23\x2a\x2e\x9c\x38\xea\x73\x17\xf0\x72\ -\x2d\x57\xf8\xc5\x62\x84\xb7\xce\x24\x7b\x46\x65\xc7\xf3\x78\x88\ -\x77\x36\x93\x25\x5d\x78\xc9\xfb\x24\xbb\xec\x2f\x77\x4f\x82\xd8\ -\x63\x23\xd1\x39\x54\x78\x14\x7d\x24\xc8\x1a\xed\x32\x2d\x7b\xdc\ -\xf4\x92\xb1\xaf\x0d\x9b\xba\xb6\x72\xfb\xb2\x7f\x8f\xd5\x4c\x5e\ -\x05\xa7\x05\x15\xc5\x51\xd0\x86\x0a\xce\x04\x84\x1e\xba\x44\xf3\ -\xbc\x09\xa9\x4e\xc1\xc7\xbd\x7e\x45\x38\x04\xa3\x6c\xfa\x46\x57\ -\x40\x93\xbf\xdd\x12\x05\x6c\xb0\xee\x08\x40\x74\xc9\xda\xe7\x30\ -\xfa\x1f\x12\xc8\x31\x33\x53\xe4\x65\x2a\xe8\xbf\x2b\x3c\xd6\xcc\ -\xec\x8f\x9a\x6f\xe1\xe0\xe6\x81\x0a\xf5\x46\x07\xeb\xcd\xba\xcb\ -\xa1\xe5\x4a\x42\xd6\x20\xce\xb6\x16\xcf\x73\x30\x25\x17\xe3\x00\ -\x2b\x58\x93\x86\x74\x57\x48\x8b\x2a\x35\x88\xc7\x84\x18\x53\x23\ -\xba\xc3\x06\x0a\xd7\x09\xf2\xcb\xe1\xb1\x39\x07\xaf\x2d\xb2\xbc\ -\x7d\x71\x91\x6f\x71\x53\x82\xed\x51\x96\xbf\x90\xb4\x4a\x9a\x20\ -\x21\x8a\x72\xa3\xbc\xfc\xb9\xcd\x47\x5e\x38\x9c\xd2\xf9\xae\x7f\ -\xb2\x1a\x2a\x81\x68\x31\x53\xb2\x11\xfa\x80\x71\x31\xdd\xde\x56\ -\x9c\x5f\x3f\x50\xb5\x5f\x99\x5d\x36\x34\x23\x13\xa9\xf0\x04\x3d\ -\xa0\xee\x1c\xe5\xe3\x8d\x60\x76\x62\x5a\xd2\xa3\xa2\x51\xea\x75\ -\xab\x1f\x2f\xc4\x08\x35\x5d\xf3\x28\x5d\x59\x67\x88\xf0\x61\x6c\ -\x8b\x5f\xaf\x90\xa9\x90\xfe\x36\x29\xcc\x02\xf7\x2f\xa7\x19\x0e", - 512))); -} - -BENCH(getrandom, bench) { - EZBENCH2("MeasureEntropy", donothing, MeasureEntropy(kMoby, 512)); -} diff --git a/test/libc/rand/measureentropy_test.c b/test/libc/rand/measureentropy_test.c new file mode 100644 index 000000000..6e5aea2aa --- /dev/null +++ b/test/libc/rand/measureentropy_test.c @@ -0,0 +1,146 @@ +/*-*- 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/math.h" +#include "libc/rand/rand.h" +#include "libc/testlib/ezbench.h" +#include "libc/testlib/hyperion.h" +#include "libc/testlib/testlib.h" + +TEST(MeasureEntropy, test) { + MeasureEntropy(kMoby, 1000); + EXPECT_EQ(00, lroundl(10 * MeasureEntropy(" ", 12))); + EXPECT_EQ(16, lroundl(10 * MeasureEntropy("abcabcabcabc", 12))); + EXPECT_EQ(36, lroundl(10 * MeasureEntropy("abcdefghijkl", 12))); + EXPECT_EQ(49, lroundl(10 * MeasureEntropy(kMoby, 512))); +} + +TEST(MeasureEntropy, testElfExecutable) { + EXPECT_EQ(19, lroundl(10 * MeasureEntropy("\ +\x7f\x45\x4c\x46\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\ +\x03\x00\x3e\x00\x01\x00\x00\x00\x18\xd7\x00\x00\x00\x00\x00\x00\ +\x40\x00\x00\x00\x00\x00\x00\x00\xc8\xd0\x0c\x00\x00\x00\x00\x00\ +\x00\x00\x00\x00\x40\x00\x38\x00\x09\x00\x40\x00\x16\x00\x15\x00\ +\x06\x00\x00\x00\x04\x00\x00\x00\x40\x00\x00\x00\x00\x00\x00\x00\ +\x40\x00\x00\x00\x00\x00\x00\x00\x40\x00\x00\x00\x00\x00\x00\x00\ +\xf8\x01\x00\x00\x00\x00\x00\x00\xf8\x01\x00\x00\x00\x00\x00\x00\ +\x08\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x04\x00\x00\x00\ +\x38\x02\x00\x00\x00\x00\x00\x00\x38\x02\x00\x00\x00\x00\x00\x00\ +\x38\x02\x00\x00\x00\x00\x00\x00\x19\x00\x00\x00\x00\x00\x00\x00\ +\x19\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\ +\x01\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ +\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ +\x90\xbc\x00\x00\x00\x00\x00\x00\x90\xbc\x00\x00\x00\x00\x00\x00\ +\x00\x10\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x05\x00\x00\x00\ +\x00\xc0\x00\x00\x00\x00\x00\x00\x00\xc0\x00\x00\x00\x00\x00\x00\ +\x00\xc0\x00\x00\x00\x00\x00\x00\x62\xb2\x09\x00\x00\x00\x00\x00\ +\x62\xb2\x09\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\ +\x01\x00\x00\x00\x04\x00\x00\x00\x00\x80\x0a\x00\x00\x00\x00\x00\ +\x00\x80\x0a\x00\x00\x00\x00\x00\x00\x80\x0a\x00\x00\x00\x00\x00\ +\xe4\x09\x02\x00\x00\x00\x00\x00\xe4\x09\x02\x00\x00\x00\x00\x00\ +\x00\x10\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x06\x00\x00\x00\ +\xc0\x95\x0c\x00\x00\x00\x00\x00\xc0\xa5\x0c\x00\x00\x00\x00\x00\ +\xc0\xa5\x0c\x00\x00\x00\x00\x00\x64\x3a\x00\x00\x00\x00\x00\x00\ +\xa8\x42\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\ +\x02\x00\x00\x00\x06\x00\x00\x00\xa0\xc2\x0c\x00\x00\x00\x00\x00\ +\xa0\xd2\x0c\x00\x00\x00\x00\x00\xa0\xd2\x0c\x00\x00\x00\x00\x00\ +\x80\x01\x00\x00\x00\x00\x00\x00\x80\x01\x00\x00\x00\x00\x00\x00\ +\x08\x00\x00\x00\x00\x00\x00\x00\x51\xe5\x74\x64\x06\x00\x00\x00\ +\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ +\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ +\x00\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00", + 512))); +} + +TEST(MeasureEntropy, testApeExecutable) { + EXPECT_EQ(53, lroundl(10 * MeasureEntropy("\ +\x7f\x45\x4c\x46\x02\x01\x01\x09\x00\x00\x00\x00\x00\x00\x00\x00\ +\x02\x00\x3e\x00\x01\x00\x00\x00\x0a\x11\x40\x00\x00\x00\x00\x00\ +\xe0\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ +\x00\x00\x00\x00\x40\x00\x38\x00\x04\x00\x00\x00\x00\x00\x00\x00\ +\xb2\x40\xeb\x00\xeb\x14\x90\x90\xeb\x06\x48\x83\xec\x08\x31\xd2\ +\xbd\x00\x00\xeb\x05\xe9\xb0\x10\x00\x00\xfc\x0f\x1f\x87\x3e\xe0\ +\xbf\x00\x70\x31\xc9\x8e\xc1\xfa\x8e\xd7\x89\xcc\xfb\x0e\x1f\xe8\ +\x00\x00\x5e\x81\xee\x72\x00\xb8\x00\x02\x50\x50\x07\x31\xff\xb9\ +\x00\x02\xf3\xa4\x0f\x1f\x87\xd2\xff\xea\x8e\x20\x00\x00\x8e\xd9\ +\xb9\x00\x1b\xb8\x50\x00\x8e\xc0\x31\xc0\x31\xff\xf3\xaa\x80\xfa\ +\x40\x74\x13\xe8\x15\x00\x07\xb0\x01\x31\xc9\x30\xf6\xbf\x40\x03\ +\xe8\x48\x00\x4f\x75\xfa\xea\x20\x25\x00\x00\x53\x52\xb4\x08\xcd\ +\x13\x72\x2c\x88\xcf\x80\xe7\x3f\x80\xe1\xc0\xd0\xc1\xd0\xc1\x86\ +\xcd\x1e\x06\x1f\x31\xf6\x8e\xc6\xbe\x10\x15\x87\xf7\xa5\xa5\xa5\ +\xa5\xa5\xa4\x1f\x93\xab\x91\xab\x92\xab\x58\xaa\x92\x5b\xc3\x5a\ +\x80\xf2\x80\x31\xc0\xcd\x13\x72\xf7\xeb\xc1\x50\x51\x86\xcd\xd0\ +\xc9\xd0\xc9\x08\xc1\x31\xdb\xb0\x01\xb4\x02\xcd\x13\x59\x58\x72\ +\x1d\x8c\xc6\x83\xc6\x20\x8e\xc6\xfe\xc0\x3a\x06\x1c\x15\x76\x0d\ +\xb0\x01\xfe\xc6\x3a\x36\x20\x15\x76\x03\x30\xf6\x41\xc3\x50\x31\ +\xc0\xcd\x13\x58\xeb\xc5\x89\xfe\xac\x84\xc0\x74\x09\xbb\x07\x00\ +\xb4\x0e\xcd\x10\xeb\xf2\xc3\x57\xbf\x78\x24\xe8\xe8\xff\x5f\xe8\ +\xe4\xff\xbf\x80\x24\xe8\xde\xff\xf3\x90\xeb\xfc\xb9\x04\x00\xbe\ +\x00\x04\xad\x85\xc0\x74\x0b\x51\x56\x97\xbe\x9e\x24\xe8\x05\x00\ +\x5e\x59\xe2\xee\xc3\x89\xfa\x85\xd2\x74\x14\x52\x56\x31\xc9\xb1\ +\x03\x01\xca\xac\x5e\x0c\x80\xee\x5a\xac\xee\x42\x49\x79\xfa\xc3\ +\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ +\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ +\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ +\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ +\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ +\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ +\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x55\xaa", + 512))); +} + +TEST(MeasureEntropy, testDevUrandom) { + EXPECT_EQ(76, lroundl(10 * MeasureEntropy("\ +\x67\xa6\x8f\x6f\x6f\x01\xa4\x60\xa5\x5a\x6a\xfa\x06\xfd\xbb\xbe\ +\xe4\x73\x2f\xc4\x20\x25\xd9\xb2\x78\x7d\x9f\xaf\x5d\x03\x49\x01\ +\x90\x94\x8a\xc0\x33\x78\xe0\x65\xd8\x9c\x19\x96\x25\x90\xc8\x6e\ +\xf2\x65\xac\x72\xd9\x8e\x58\x05\x26\x22\xa3\x58\x41\x40\xee\x3c\ +\x3a\xb0\x08\x7c\x70\x0e\x23\xdc\x52\x10\x21\x5c\xb7\x3d\x3a\xce\ +\x7c\xd7\x2a\x8c\x35\x0c\x21\x2b\x03\x75\xbe\x0c\x49\x5b\xdb\x7a\ +\x7e\xeb\x27\x03\x56\xca\x9f\xf8\x00\xb4\x4d\x5b\xd6\xde\x41\xd6\ +\x86\x7b\x3c\x13\xd4\x2d\xd4\xe9\x79\x05\x48\xcc\xa5\x17\xf8\xb6\ +\x74\xdf\x39\x70\x32\x64\x70\x10\xfb\x53\x06\x87\xef\xff\x9f\x4c\ +\x07\xee\x09\x54\xb8\xda\x1a\x49\x9b\x12\x3a\xf9\xc3\x55\xbc\xa5\ +\xad\x6c\x3d\x1f\x39\x84\xc6\xac\x45\x14\x4f\xa9\xfc\xd6\xfb\xce\ +\x41\xf8\x78\x85\xe5\x72\x9c\x0c\xd3\x81\x9b\xa4\x72\xc9\xd5\xc8\ +\xc2\x3c\xcc\x36\x58\xf6\x23\x2a\x2e\x9c\x38\xea\x73\x17\xf0\x72\ +\x2d\x57\xf8\xc5\x62\x84\xb7\xce\x24\x7b\x46\x65\xc7\xf3\x78\x88\ +\x77\x36\x93\x25\x5d\x78\xc9\xfb\x24\xbb\xec\x2f\x77\x4f\x82\xd8\ +\x63\x23\xd1\x39\x54\x78\x14\x7d\x24\xc8\x1a\xed\x32\x2d\x7b\xdc\ +\xf4\x92\xb1\xaf\x0d\x9b\xba\xb6\x72\xfb\xb2\x7f\x8f\xd5\x4c\x5e\ +\x05\xa7\x05\x15\xc5\x51\xd0\x86\x0a\xce\x04\x84\x1e\xba\x44\xf3\ +\xbc\x09\xa9\x4e\xc1\xc7\xbd\x7e\x45\x38\x04\xa3\x6c\xfa\x46\x57\ +\x40\x93\xbf\xdd\x12\x05\x6c\xb0\xee\x08\x40\x74\xc9\xda\xe7\x30\ +\xfa\x1f\x12\xc8\x31\x33\x53\xe4\x65\x2a\xe8\xbf\x2b\x3c\xd6\xcc\ +\xec\x8f\x9a\x6f\xe1\xe0\xe6\x81\x0a\xf5\x46\x07\xeb\xcd\xba\xcb\ +\xa1\xe5\x4a\x42\xd6\x20\xce\xb6\x16\xcf\x73\x30\x25\x17\xe3\x00\ +\x2b\x58\x93\x86\x74\x57\x48\x8b\x2a\x35\x88\xc7\x84\x18\x53\x23\ +\xba\xc3\x06\x0a\xd7\x09\xf2\xcb\xe1\xb1\x39\x07\xaf\x2d\xb2\xbc\ +\x7d\x71\x91\x6f\x71\x53\x82\xed\x51\x96\xbf\x90\xb4\x4a\x9a\x20\ +\x21\x8a\x72\xa3\xbc\xfc\xb9\xcd\x47\x5e\x38\x9c\xd2\xf9\xae\x7f\ +\xb2\x1a\x2a\x81\x68\x31\x53\xb2\x11\xfa\x80\x71\x31\xdd\xde\x56\ +\x9c\x5f\x3f\x50\xb5\x5f\x99\x5d\x36\x34\x23\x13\xa9\xf0\x04\x3d\ +\xa0\xee\x1c\xe5\xe3\x8d\x60\x76\x62\x5a\xd2\xa3\xa2\x51\xea\x75\ +\xab\x1f\x2f\xc4\x08\x35\x5d\xf3\x28\x5d\x59\x67\x88\xf0\x61\x6c\ +\x8b\x5f\xaf\x90\xa9\x90\xfe\x36\x29\xcc\x02\xf7\x2f\xa7\x19\x0e", + 512))); +} + +BENCH(getrandom, bench) { + EZBENCH2("MeasureEntropy", donothing, MeasureEntropy(kMoby, 512)); +} diff --git a/test/libc/stdio/vappendf_test.c b/test/libc/stdio/vappendf_test.c index b1fbef240..e6632e62b 100644 --- a/test/libc/stdio/vappendf_test.c +++ b/test/libc/stdio/vappendf_test.c @@ -22,14 +22,17 @@ TEST(vappendf, test) { char *b = 0; - appendf(&b, "hello "); + ASSERT_NE(-1, appendf(&b, "hello ")); EXPECT_EQ(6, appendz(b).i); + EXPECT_EQ(0, b[appendz(b).i]); EXPECT_EQ(6, strlen(b)); // guarantees nul terminator - appendf(&b, " world\n"); + ASSERT_NE(-1, appendf(&b, " world\n")); EXPECT_EQ(13, appendz(b).i); + EXPECT_EQ(0, b[appendz(b).i]); EXPECT_EQ(13, strlen(b)); - appendd(&b, "\0", 1); // supports binary + ASSERT_NE(-1, appendd(&b, "\0", 1)); // supports binary EXPECT_EQ(14, appendz(b).i); + EXPECT_EQ(0, b[appendz(b).i]); EXPECT_EQ(13, strlen(b)); EXPECT_EQ(0, b[13]); EXPECT_EQ(0, b[14]); @@ -37,12 +40,17 @@ TEST(vappendf, test) { free(b); } -TEST(vappends, test) { +TEST(appends, test) { char *b = 0; - appends(&b, "hello "); + ASSERT_NE(-1, appends(&b, "")); + EXPECT_NE(0, b); + EXPECT_EQ(0, appendz(b).i); + EXPECT_EQ(0, b[appendz(b).i]); + ASSERT_NE(-1, appends(&b, "hello ")); EXPECT_EQ(6, appendz(b).i); + EXPECT_EQ(0, b[appendz(b).i]); EXPECT_EQ(6, strlen(b)); // guarantees nul terminator - appends(&b, " world\n"); + ASSERT_NE(-1, appends(&b, " world\n")); EXPECT_EQ(13, appendz(b).i); EXPECT_EQ(13, strlen(b)); EXPECT_EQ(0, b[13]); @@ -50,6 +58,69 @@ TEST(vappends, test) { free(b); } +TEST(appendd, test) { + char *b = 0; + ASSERT_NE(-1, appendd(&b, 0, 0)); + EXPECT_NE(0, b); + EXPECT_EQ(0, appendz(b).i); + EXPECT_EQ(0, b[appendz(b).i]); + ASSERT_NE(-1, appendd(&b, "hello ", 6)); + EXPECT_EQ(6, appendz(b).i); + EXPECT_EQ(0, b[appendz(b).i]); + EXPECT_EQ(6, strlen(b)); // guarantees nul terminator + ASSERT_NE(-1, appendd(&b, " world\n", 7)); + EXPECT_EQ(13, appendz(b).i); + EXPECT_EQ(13, strlen(b)); + EXPECT_EQ(0, b[13]); + EXPECT_STREQ("hello world\n", b); + free(b); +} + +TEST(appendw, test) { + char *b = 0; + ASSERT_NE(-1, appendw(&b, 0)); + EXPECT_EQ(1, appendz(b).i); + EXPECT_EQ(0, b[0]); + EXPECT_EQ(0, b[1]); + ASSERT_NE(-1, appendw(&b, 'h')); + EXPECT_EQ(2, appendz(b).i); + EXPECT_EQ(0, b[0]); + EXPECT_EQ('h', b[1]); + EXPECT_EQ(0, b[2]); + ASSERT_NE(-1, appendw(&b, 'e' | 'l' << 8 | 'l' << 16 | 'o' << 24 | + (uint64_t)'!' << 32)); + EXPECT_EQ(7, appendz(b).i); + EXPECT_EQ(0, b[0]); + EXPECT_EQ('h', b[1]); + EXPECT_EQ('e', b[2]); + EXPECT_EQ('l', b[3]); + EXPECT_EQ('l', b[4]); + EXPECT_EQ('o', b[5]); + EXPECT_EQ('!', b[6]); + EXPECT_EQ(0, b[7]); + free(b); +} + +TEST(appendr, test) { + char *b = 0; + ASSERT_NE(-1, appends(&b, "hello")); + EXPECT_EQ(5, appendz(b).i); + ASSERT_NE(-1, appendr(&b, 1)); + EXPECT_EQ(0, strcmp(b, "h")); + EXPECT_EQ(1, appendz(b).i); + ASSERT_NE(-1, appendr(&b, 0)); + EXPECT_EQ(0, appendz(b).i); + EXPECT_EQ(0, strcmp(b, "")); + ASSERT_NE(-1, appendr(&b, 5)); + EXPECT_EQ(0, b[0]); + EXPECT_EQ(0, b[1]); + EXPECT_EQ(0, b[2]); + EXPECT_EQ(0, b[3]); + EXPECT_EQ(0, b[4]); + EXPECT_EQ(0, b[5]); + free(b); +} + BENCH(vappendf, bench) { const char t[] = {0}; char *b = 0; @@ -57,6 +128,8 @@ BENCH(vappendf, bench) { free(b), b = 0; EZBENCH2("appends", donothing, appends(&b, "1")); free(b), b = 0; + EZBENCH2("appendw", donothing, appendw(&b, 'B')); + free(b), b = 0; EZBENCH2("appendd", donothing, appendd(&b, t, 1)); - free(b); + free(b), b = 0; } diff --git a/third_party/lua/loadlib.c b/third_party/lua/loadlib.c index 0ad59525a..ae7631f9a 100644 --- a/third_party/lua/loadlib.c +++ b/third_party/lua/loadlib.c @@ -16,6 +16,8 @@ #include "third_party/lua/lua.h" #include "third_party/lua/lualib.h" +const char *g_lua_path_default = LUA_PATH_DEFAULT; + /* clang-format off */ /* @@ -728,12 +730,17 @@ static void createclibstable (lua_State *L) { } +static const char *GetLuaPathDefault(void) { + return g_lua_path_default; +} + + LUAMOD_API int luaopen_package (lua_State *L) { createclibstable(L); luaL_newlib(L, pk_funcs); /* create 'package' table */ createsearcherstable(L); /* set paths */ - setpath(L, "path", LUA_PATH_VAR, LUA_PATH_DEFAULT); + setpath(L, "path", LUA_PATH_VAR, g_lua_path_default); setpath(L, "cpath", LUA_CPATH_VAR, LUA_CPATH_DEFAULT); /* store config information */ lua_pushliteral(L, LUA_DIRSEP "\n" LUA_PATH_SEP "\n" LUA_PATH_MARK "\n" diff --git a/third_party/lua/lua.h b/third_party/lua/lua.h index 180bdc4d4..f13f63f57 100644 --- a/third_party/lua/lua.h +++ b/third_party/lua/lua.h @@ -1,15 +1,8 @@ -/* -** $Id: lua.h $ -** Lua - A Scripting Language -** Lua.org, PUC-Rio, Brazil (http://www.lua.org) -** See Copyright Notice at the end of this file -*/ - -#ifndef lua_h -#define lua_h - +#ifndef COSMOPOLITAN_THIRD_PARTY_LUA_LUA_H_ +#define COSMOPOLITAN_THIRD_PARTY_LUA_LUA_H_ #include "third_party/lua/luaconf.h" - +#if !(__ASSEMBLER__ + __LINKER__ + 0) +COSMOPOLITAN_C_START_ /* clang-format off */ #define LUA_VERSION_MAJOR "5" @@ -489,29 +482,8 @@ struct lua_Debug { /* }====================================================================== */ +extern const char *g_lua_path_default; -/****************************************************************************** -* Copyright (C) 1994-2021 Lua.org, PUC-Rio. -* -* 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. -******************************************************************************/ - - -#endif +COSMOPOLITAN_C_END_ +#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ +#endif /* COSMOPOLITAN_THIRD_PARTY_LUA_LUA_H_ */ diff --git a/third_party/lua/lua.mk b/third_party/lua/lua.mk index 50a78b0ec..87978d7c5 100644 --- a/third_party/lua/lua.mk +++ b/third_party/lua/lua.mk @@ -60,6 +60,11 @@ o/$(MODE)/third_party/lua/lauxlib.o: \ OVERRIDE_CFLAGS += \ -DSTACK_FRAME_UNLIMITED +$(THIRD_PARTY_LUA_OBJS): \ + OVERRIDE_CFLAGS += \ + -ffunction-sections \ + -fdata-sections + .PHONY: o/$(MODE)/third_party/lua o/$(MODE)/third_party/lua: \ $(THIRD_PARTY_LUA_BINS) \ diff --git a/third_party/lua/luaconf.h b/third_party/lua/luaconf.h index 1bc9480fd..3ac2ae905 100644 --- a/third_party/lua/luaconf.h +++ b/third_party/lua/luaconf.h @@ -1,17 +1,13 @@ -/* -** $Id: luaconf.h $ -** Configuration file for Lua -** See Copyright Notice in lua.h -*/ - #ifndef luaconf_h #define luaconf_h - -#define LUA_USE_POSIX +#include "libc/assert.h" +#include "libc/dce.h" #include "libc/fmt/fmt.h" #include "libc/limits.h" #include "third_party/gdtoa/gdtoa.h" +#define LUA_USE_POSIX + /* clang-format off */ /* @@ -193,63 +189,20 @@ */ #define LUA_VDIR LUA_VERSION_MAJOR "." LUA_VERSION_MINOR -#if defined(_WIN32) /* { */ -/* -** In Windows, any exclamation mark ('!') in the path is replaced by the -** path of the directory of the executable file of the current process. -*/ -#define LUA_LDIR "!\\lua\\" -#define LUA_CDIR "!\\" -#define LUA_SHRDIR "!\\..\\share\\lua\\" LUA_VDIR "\\" - -#if !defined(LUA_PATH_DEFAULT) -#define LUA_PATH_DEFAULT \ - LUA_LDIR"?.lua;" LUA_LDIR"?\\init.lua;" \ - LUA_CDIR"?.lua;" LUA_CDIR"?\\init.lua;" \ - LUA_SHRDIR"?.lua;" LUA_SHRDIR"?\\init.lua;" \ - ".\\?.lua;" ".\\?\\init.lua" -#endif - -#if !defined(LUA_CPATH_DEFAULT) -#define LUA_CPATH_DEFAULT \ - LUA_CDIR"?.dll;" \ - LUA_CDIR"..\\lib\\lua\\" LUA_VDIR "\\?.dll;" \ - LUA_CDIR"loadall.dll;" ".\\?.dll" -#endif - -#else /* }{ */ #define LUA_ROOT "zip:" #define LUA_LDIR LUA_ROOT ".lua/" #define LUA_CDIR LUA_ROOT ".lua/" -#if !defined(LUA_PATH_DEFAULT) -#define LUA_PATH_DEFAULT \ - LUA_LDIR"?.lua;" LUA_LDIR"?/init.lua" -#endif - -#if !defined(LUA_CPATH_DEFAULT) -#define LUA_CPATH_DEFAULT \ - LUA_CDIR"?.so;" LUA_CDIR"loadall.so;" "./?.so" -#endif - -#endif /* } */ - +#define LUA_PATH_DEFAULT LUA_LDIR"?.lua;" LUA_LDIR"?/init.lua;" "./?.lua;" "./?/init.lua" +#define LUA_CPATH_DEFAULT LUA_CDIR"?.so;" LUA_CDIR"loadall.so;" "./?.so" /* @@ LUA_DIRSEP is the directory separator (for submodules). ** CHANGE it if your machine does not use "/" as the directory separator ** and is not Windows. (On Windows Lua automatically uses "\".) */ -#if !defined(LUA_DIRSEP) - -#if defined(_WIN32) -#define LUA_DIRSEP "\\" -#else #define LUA_DIRSEP "/" -#endif - -#endif /* }================================================================== */ @@ -269,20 +222,8 @@ ** the libraries, you may want to use the following definition (define ** LUA_BUILD_AS_DLL to get it). */ -#if defined(LUA_BUILD_AS_DLL) /* { */ - -#if defined(LUA_CORE) || defined(LUA_LIB) /* { */ -#define LUA_API __declspec(dllexport) -#else /* }{ */ -#define LUA_API __declspec(dllimport) -#endif /* } */ - -#else /* }{ */ - #define LUA_API extern -#endif /* } */ - /* ** More often than not the libs go together with the core. @@ -305,12 +246,7 @@ ** give a warning about it. To avoid these warnings, change to the ** default definition. */ -#if defined(__GNUC__) && ((__GNUC__*100 + __GNUC_MINOR__) >= 302) && \ - defined(__ELF__) /* { */ -#define LUAI_FUNC /* __attribute__((visibility("internal"))) */ extern -#else /* }{ */ #define LUAI_FUNC extern -#endif /* } */ #define LUAI_DDEC(dec) LUAI_FUNC dec #define LUAI_DDEF /* empty */ @@ -710,8 +646,7 @@ @@ LUA_USE_APICHECK turns on several consistency checks on the C API. ** Define it as a help when debugging C code. */ -#if defined(LUA_USE_APICHECK) -#include +#if IsModeDbg() #define luai_apicheck(l,e) assert(e) #endif diff --git a/third_party/mbedtls/config.h b/third_party/mbedtls/config.h index 5c8b8ff5b..f7242ab26 100644 --- a/third_party/mbedtls/config.h +++ b/third_party/mbedtls/config.h @@ -2,6 +2,7 @@ #define MBEDTLS_CONFIG_H_ #include "libc/dce.h" +/* /\* uncomment for testing old cpu code paths *\/ */ /* #include "libc/nexgen32e/x86feature.h" */ /* #undef X86_HAVE */ /* #define X86_HAVE(x) 0 */ diff --git a/third_party/mbedtls/ecp384.c b/third_party/mbedtls/ecp384.c index def25a586..ee5199630 100644 --- a/third_party/mbedtls/ecp384.c +++ b/third_party/mbedtls/ecp384.c @@ -35,21 +35,22 @@ mbedtls_p384_isz( uint64_t p[6] ) return( !p[0] & !p[1] & !p[2] & !p[3] & !p[4] & !p[5] ); } -bool mbedtls_p384_gte( uint64_t p[7] ) +static bool +mbedtls_p384_gte( uint64_t p[7] ) { return( (((int64_t)p[6] > 0) | (!p[6] & - (p[5] > 0xffffffffffffffff | - (p[5] == 0xffffffffffffffff & - (p[4] > 0xffffffffffffffff | - (p[4] == 0xffffffffffffffff & - (p[3] > 0xffffffffffffffff | - (p[3] == 0xffffffffffffffff & - (p[2] > 0xfffffffffffffffe | - (p[2] == 0xfffffffffffffffe & - (p[1] > 0xffffffff00000000 | - (p[1] == 0xffffffff00000000 & - (p[0] > 0x00000000ffffffff | + ((p[5] > 0xffffffffffffffff) | + ((p[5] == 0xffffffffffffffff) & + ((p[4] > 0xffffffffffffffff) | + ((p[4] == 0xffffffffffffffff) & + ((p[3] > 0xffffffffffffffff) | + ((p[3] == 0xffffffffffffffff) & + ((p[2] > 0xfffffffffffffffe) | + ((p[2] == 0xfffffffffffffffe) & + ((p[1] > 0xffffffff00000000) | + ((p[1] == 0xffffffff00000000) & + ((p[0] > 0x00000000ffffffff) | (p[0] == 0x00000000ffffffff)))))))))))))) ); } @@ -128,7 +129,8 @@ mbedtls_p384_gro( uint64_t p[7] ) #endif } -void mbedtls_p384_rum( uint64_t p[7] ) +static inline void +mbedtls_p384_rum( uint64_t p[7] ) { while( mbedtls_p384_gte( p ) ) mbedtls_p384_red( p ); @@ -142,9 +144,7 @@ void mbedtls_p384_mod( uint64_t X[12] ) mbedtls_p384_gro(X); } while( (int64_t)X[6] < 0 ); } else { - while( mbedtls_p384_gte(X) ){ - mbedtls_p384_red(X); - } + mbedtls_p384_rum(X); } } diff --git a/third_party/mbedtls/ecp_internal.h b/third_party/mbedtls/ecp_internal.h index bdfe46b4f..4a5af7dd4 100644 --- a/third_party/mbedtls/ecp_internal.h +++ b/third_party/mbedtls/ecp_internal.h @@ -261,7 +261,6 @@ int mbedtls_p384_normalize_jac( const mbedtls_ecp_group *, int mbedtls_p384_normalize_jac_many( const mbedtls_ecp_group *, mbedtls_ecp_point *[], size_t ); -void mbedtls_p384_rum( uint64_t p[7] ); void mbedtls_p384_mod( uint64_t X[12] ); #endif /* COSMOPOLITAN_THIRD_PARTY_MBEDTLS_ECP_INTERNAL_H_ */ diff --git a/third_party/mbedtls/test/secp384r1_test.c b/third_party/mbedtls/test/secp384r1_test.c index b1f023785..8525ccce3 100644 --- a/third_party/mbedtls/test/secp384r1_test.c +++ b/third_party/mbedtls/test/secp384r1_test.c @@ -27,6 +27,8 @@ #include "third_party/mbedtls/math.h" #ifdef MBEDTLS_ECP_C +/*P=0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffff*/ + int ecp_mod_p384_old(mbedtls_mpi *); int GetEntropy(void *c, unsigned char *p, size_t n) { @@ -97,14 +99,6 @@ TEST(secp384r1, needsDownwardCorrection) { TEST(secp384r1, needsUpwardCorrection) { int i; - uint64_t P[6] = { - 0x00000000ffffffff, // - 0xffffffff00000000, // - 0xfffffffffffffffe, // - 0xffffffffffffffff, // - 0xffffffffffffffff, // - 0xffffffffffffffff, // - }; uint64_t X[12] = { 0x0000000000000000, // 0x0000000000000000, // @@ -136,6 +130,35 @@ TEST(secp384r1, needsUpwardCorrection) { } } +TEST(secp384r1, largestInput_quasiModNeedsTwoDownwardCorrections) { + int i; + uint64_t X[12] = { + // X = (P-1)*(P-1) + 0xfffffffc00000004, // + 0x0000000400000000, // + 0xfffffffe00000002, // + 0x0000000200000000, // + 0x0000000000000001, // + 0x0000000000000000, // + 0x00000001fffffffc, // + 0xfffffffe00000000, // + 0xfffffffffffffffd, // + 0xffffffffffffffff, // + 0xffffffffffffffff, // + 0xffffffffffffffff, // + }; + uint64_t W[12] /* W = X mod P */ = { + 0x0000000000000001, // + }; + mbedtls_p384_mod(X); + if (memcmp(W, X, 12 * 8)) { + for (i = 0; i < 12; ++i) { + printf("0x%016lx vs. 0x%016lx %d\n", W[i], X[i], W[i] == X[i]); + } + ASSERT_TRUE(false); + } +} + BENCH(secp384r1, bench) { mbedtls_mpi A; mbedtls_mpi_init(&A); diff --git a/tool/net/demo/printpayload.lua b/tool/net/demo/printpayload.lua index 3c0f255a0..e4d133d4b 100644 --- a/tool/net/demo/printpayload.lua +++ b/tool/net/demo/printpayload.lua @@ -1,3 +1,3 @@ SetStatus(200) -SetHeader("Content-Type", GetHeader("Content-Type")) +SetHeader("Content-Type", GetHeader("Content-Type") or "text/plain") Write(GetPayload()) diff --git a/tool/net/help.txt b/tool/net/help.txt index 4b2bce2e3..c51893cc1 100644 --- a/tool/net/help.txt +++ b/tool/net/help.txt @@ -244,7 +244,8 @@ SECURITY Subject Alternative Names (SAN) or the Common Name (CN) of subject if SAN isn't used. This means you don't need to reveal your whole domain portfolio to each client just to have ssl. You can just use different - certificates for each domain if you choose to do so. + certificates for each domain if you choose to do so. If redbean can't + find an appropriate match, then the first certificate will be chosen. Your redbean has been secured with algorithms so strong that, until a few decades ago, it was illegal to share them with with those outside diff --git a/tool/net/net.mk b/tool/net/net.mk index 90f4d4783..63e4bf183 100644 --- a/tool/net/net.mk +++ b/tool/net/net.mk @@ -151,7 +151,6 @@ o/$(MODE)/tool/net/redbean-demo.com: \ @$(COMPILE) -AZIP -T$@ o/$(MODE)/host/third_party/infozip/zip.com -qj $@ tool/net/demo/404.html tool/net/favicon.ico tool/net/redbean.png tool/net/demo/redbean-form.lua tool/net/demo/redbean-xhr.lua tool/net/demo/printpayload.lua tool/net/demo/fetch.lua @echo Uncompressed for HTTP Range requests | $(COMPILE) -AZIP -T$@ o/$(MODE)/host/third_party/infozip/zip.com -cqj0 $@ tool/net/demo/seekable.txt @$(COMPILE) -AZIP -T$@ o/$(MODE)/host/third_party/infozip/zip.com -q $@ tool/net/ tool/net/demo/ tool/net/demo/index.html tool/net/demo/redbean.css tool/net/redbean.c net/http/parsehttpmessage.c net/http/parseurl.c net/http/encodeurl.c test/net/http/parsehttpmessage_test.c test/net/http/parseurl_test.c - @printf "

Thank you for using redbean the tiniest most vertically integrated actually portable web server with superior performance." | $(COMPILE) -AZIP -T$@ o/$(MODE)/host/third_party/infozip/zip.com -z $@ @$(COMPILE) -AMKDIR -T$@ mkdir -p o/$(MODE)/tool/net/virtualbean.justine.lol/ @$(COMPILE) -ACP -T$@ cp tool/net/redbean.png o/$(MODE)/tool/net/virtualbean.justine.lol/redbean.png @$(COMPILE) -ACP -T$@ cp tool/net/demo/virtualbean.html o/$(MODE)/tool/net/virtualbean.justine.lol/index.html diff --git a/tool/net/redbean.c b/tool/net/redbean.c index fdad733d9..62a5ef794 100644 --- a/tool/net/redbean.c +++ b/tool/net/redbean.c @@ -51,6 +51,7 @@ #include "libc/runtime/gc.internal.h" #include "libc/runtime/runtime.h" #include "libc/sock/sock.h" +#include "libc/stdio/append.internal.h" #include "libc/stdio/stdio.h" #include "libc/str/str.h" #include "libc/str/undeflate.h" @@ -91,6 +92,7 @@ #include "third_party/lua/lauxlib.h" #include "third_party/lua/ltests.h" #include "third_party/lua/lua.h" +#include "third_party/lua/luaconf.h" #include "third_party/lua/lualib.h" #include "third_party/mbedtls/asn1.h" #include "third_party/mbedtls/asn1write.h" @@ -352,6 +354,7 @@ static uint32_t clientaddrsize; static lua_State *L; static size_t zsize; +static char *outbuf; static char *content; static uint8_t *zmap; static uint8_t *zbase; @@ -384,7 +387,6 @@ static ssize_t (*generator)(struct iovec[3]); static struct Buffer inbuf; static struct Buffer oldin; static struct Buffer hdrbuf; -static struct Buffer outbuf; static struct timeval timeout; static struct Buffer effectivepath; @@ -526,57 +528,14 @@ static void CollectGarbage(void) { } static void UseOutput(void) { - content = FreeLater(outbuf.p); - contentlength = outbuf.n; - outbuf.p = 0; - outbuf.n = 0; - outbuf.c = 0; + content = FreeLater(outbuf); + contentlength = appendz(outbuf).i; + outbuf = 0; } static void DropOutput(void) { - FreeLater(outbuf.p); - outbuf.p = 0; - outbuf.n = 0; - outbuf.c = 0; -} - -static void ClearOutput(void) { - outbuf.n = 0; -} - -static void Grow(size_t n) { - do { - if (outbuf.c) { - outbuf.c += outbuf.c >> 1; - } else { - outbuf.c = 16 * 1024; - } - } while (n > outbuf.c); - outbuf.p = xrealloc(outbuf.p, outbuf.c); -} - -static void AppendData(const char *data, size_t size) { - size_t n; - n = outbuf.n + size; - if (n > outbuf.c) Grow(n); - memcpy(outbuf.p + outbuf.n, data, size); - outbuf.n = n; -} - -static void Append(const char *fmt, ...) { - int n; - char *p; - va_list va, vb; - va_start(va, fmt); - va_copy(vb, va); - n = vsnprintf(outbuf.p + outbuf.n, outbuf.c - outbuf.n, fmt, va); - if (n >= outbuf.c - outbuf.n) { - Grow(outbuf.n + n + 1); - vsnprintf(outbuf.p + outbuf.n, outbuf.c - outbuf.n, fmt, vb); - } - va_end(vb); - va_end(va); - outbuf.n += n; + FreeLater(outbuf); + outbuf = 0; } static char *MergePaths(const char *p, size_t n, const char *q, size_t m, @@ -641,9 +600,11 @@ static mbedtls_x509_crt *GetTrustedCertificate(mbedtls_x509_name *name) { return 0; } -static void UseCertificate(mbedtls_ssl_config *c, struct Cert *kp) { - VERBOSEF("using %s certificate %`'s", mbedtls_pk_get_name(&kp->cert->pk), - gc(FormatX509Name(&kp->cert->subject))); +static void UseCertificate(mbedtls_ssl_config *c, struct Cert *kp, + const char *role) { + VERBOSEF("using %s certificate %`'s for HTTPS %s", + mbedtls_pk_get_name(&kp->cert->pk), + gc(FormatX509Name(&kp->cert->subject)), role); CHECK_EQ(0, mbedtls_ssl_conf_own_cert(c, kp->cert, kp->key)); } @@ -947,8 +908,8 @@ static void ProgramTimeout(long ms) { timeout.tv_sec = ms; /* -(keepalive seconds) */ timeout.tv_usec = 0; } else { - if (ms <= 30) { - fprintf(stderr, "error: timeout needs to be 31ms or greater\n"); + if (ms < 10) { + fprintf(stderr, "error: timeout needs to be 10ms or greater\n"); exit(1); } d = ldiv(ms, 1000); @@ -1168,57 +1129,57 @@ static void ReportWorkerExit(int pid, int ws) { } } -static void AppendResourceReport(struct rusage *ru, const char *nl) { +static void AppendResourceReport(char **b, struct rusage *ru, const char *nl) { long utime, stime; long double ticks; if (ru->ru_maxrss) { - Append("ballooned to %,ldkb in size%s", ru->ru_maxrss, nl); + appendf(b, "ballooned to %,ldkb in size%s", ru->ru_maxrss, nl); } if ((utime = ru->ru_utime.tv_sec * 1000000 + ru->ru_utime.tv_usec) | (stime = ru->ru_stime.tv_sec * 1000000 + ru->ru_stime.tv_usec)) { ticks = ceill((long double)(utime + stime) / (1000000.L / CLK_TCK)); - Append("needed %,ldµs cpu (%d%% kernel)%s", utime + stime, - (int)((long double)stime / (utime + stime) * 100), nl); + appendf(b, "needed %,ldµs cpu (%d%% kernel)%s", utime + stime, + (int)((long double)stime / (utime + stime) * 100), nl); if (ru->ru_idrss) { - Append("needed %,ldkb memory on average%s", lroundl(ru->ru_idrss / ticks), - nl); + appendf(b, "needed %,ldkb memory on average%s", + lroundl(ru->ru_idrss / ticks), nl); } if (ru->ru_isrss) { - Append("needed %,ldkb stack on average%s", lroundl(ru->ru_isrss / ticks), - nl); + appendf(b, "needed %,ldkb stack on average%s", + lroundl(ru->ru_isrss / ticks), nl); } if (ru->ru_ixrss) { - Append("mapped %,ldkb shared on average%s", lroundl(ru->ru_ixrss / ticks), - nl); + appendf(b, "mapped %,ldkb shared on average%s", + lroundl(ru->ru_ixrss / ticks), nl); } } if (ru->ru_minflt || ru->ru_majflt) { - Append("caused %,ld page faults (%d%% memcpy)%s", - ru->ru_minflt + ru->ru_majflt, - (int)((long double)ru->ru_minflt / (ru->ru_minflt + ru->ru_majflt) * - 100), - nl); + appendf(b, "caused %,ld page faults (%d%% memcpy)%s", + ru->ru_minflt + ru->ru_majflt, + (int)((long double)ru->ru_minflt / (ru->ru_minflt + ru->ru_majflt) * + 100), + nl); } if (ru->ru_nvcsw + ru->ru_nivcsw > 1) { - Append( - "%,ld context switches (%d%% consensual)%s", + appendf( + b, "%,ld context switches (%d%% consensual)%s", ru->ru_nvcsw + ru->ru_nivcsw, (int)((long double)ru->ru_nvcsw / (ru->ru_nvcsw + ru->ru_nivcsw) * 100), nl); } if (ru->ru_msgrcv || ru->ru_msgsnd) { - Append("received %,ld message%s and sent %,ld%s", ru->ru_msgrcv, - ru->ru_msgrcv == 1 ? "" : "s", ru->ru_msgsnd, nl); + appendf(b, "received %,ld message%s and sent %,ld%s", ru->ru_msgrcv, + ru->ru_msgrcv == 1 ? "" : "s", ru->ru_msgsnd, nl); } if (ru->ru_inblock || ru->ru_oublock) { - Append("performed %,ld read%s and %,ld write i/o operations%s", - ru->ru_inblock, ru->ru_inblock == 1 ? "" : "s", ru->ru_oublock, nl); + appendf(b, "performed %,ld read%s and %,ld write i/o operations%s", + ru->ru_inblock, ru->ru_inblock == 1 ? "" : "s", ru->ru_oublock, nl); } if (ru->ru_nsignals) { - Append("received %,ld signals%s", ru->ru_nsignals, nl); + appendf(b, "received %,ld signals%s", ru->ru_nsignals, nl); } if (ru->ru_nswap) { - Append("got swapped %,ld times%s", ru->ru_nswap, nl); + appendf(b, "got swapped %,ld times%s", ru->ru_nswap, nl); } } @@ -1251,16 +1212,16 @@ static void AddRusage(struct rusage *x, const struct rusage *y) { } static void ReportWorkerResources(int pid, struct rusage *ru) { - const char *s; + char *s, *b = 0; if (logrusage || LOGGABLE(kLogDebug)) { - AppendResourceReport(ru, "\n"); - if (outbuf.n) { - if ((s = IndentLines(outbuf.p, outbuf.n - 1, 0, 1))) { + AppendResourceReport(&b, ru, "\n"); + if (b) { + if ((s = IndentLines(b, appendz(b).i - 1, 0, 1))) { flogf(kLogInfo, __FILE__, __LINE__, NULL, "resource report for pid %d\n%s", pid, s); free(s); } - ClearOutput(); + free(b); } } } @@ -1512,68 +1473,101 @@ static void WipeServingKeys(void) { /* mbedtls_ssl_key_cert_free(conf.key_cert); */ } -static int TlsRouteCertificate(mbedtls_ssl_context *ssl, int i, - const unsigned char *host, size_t size) { - int rc; - if (!(rc = mbedtls_ssl_set_hs_own_cert(ssl, certs.p[i].cert, - certs.p[i].key))) { - DEBUGF("TlsRoute(%`'.*s) %s %`'s", size, host, - mbedtls_pk_get_name(&certs.p[i].cert->pk), - gc(FormatX509Name(&certs.p[i].cert->subject))); - return 0; - } else { - return -1; +static bool CertHasCommonName(const mbedtls_x509_crt *cert, + const unsigned char *host, size_t size) { + const mbedtls_x509_name *name; + for (name = &cert->subject; name; name = name->next) { + if (!MBEDTLS_OID_CMP(MBEDTLS_OID_AT_CN, &name->oid)) { + if (SlicesEqualCase(host, size, name->val.p, name->val.len)) { + return true; + } + break; + } } + return false; +} + +static bool CertHasHost(const mbedtls_x509_crt *cert, const unsigned char *host, + size_t size) { + const mbedtls_x509_sequence *cur; + for (cur = &cert->subject_alt_names; cur; cur = cur->next) { + if ((cur->buf.tag & MBEDTLS_ASN1_TAG_VALUE_MASK) == + MBEDTLS_X509_SAN_DNS_NAME && + SlicesEqualCase(host, size, cur->buf.p, cur->buf.len)) { + return true; + } + } + return false; +} + +static bool CertHasIp(const mbedtls_x509_crt *cert, uint32_t ip) { + const mbedtls_x509_sequence *cur; + for (cur = &cert->subject_alt_names; cur; cur = cur->next) { + if ((cur->buf.tag & MBEDTLS_ASN1_TAG_VALUE_MASK) == + MBEDTLS_X509_SAN_IP_ADDRESS && + cur->buf.len == 4 && ip == READ32BE(cur->buf.p)) { + return true; + } + } + return false; +} + +static bool IsServerCert(mbedtls_pk_type_t type, int i) { + return certs.p[i].cert && certs.p[i].key && !certs.p[i].cert->ca_istrue && + mbedtls_pk_get_type(certs.p[i].key) == type && + !mbedtls_x509_crt_check_extended_key_usage( + certs.p[i].cert, MBEDTLS_OID_SERVER_AUTH, + MBEDTLS_OID_SIZE(MBEDTLS_OID_SERVER_AUTH)); +} + +static bool TlsRouteFind(mbedtls_pk_type_t type, mbedtls_ssl_context *ssl, + const unsigned char *host, size_t size, int64_t ip) { + int i; + for (i = 0; i < certs.n; ++i) { + if (IsServerCert(type, i) && + (((certs.p[i].cert->ext_types & MBEDTLS_X509_EXT_SUBJECT_ALT_NAME) && + (ip == -1 ? CertHasHost(certs.p[i].cert, host, size) + : CertHasIp(certs.p[i].cert, ip))) || + CertHasCommonName(certs.p[i].cert, host, size))) { + CHECK_EQ( + 0, mbedtls_ssl_set_hs_own_cert(ssl, certs.p[i].cert, certs.p[i].key)); + DEBUGF("TlsRoute(%s, %`'.*s) %s %`'s", mbedtls_pk_type_name(type), size, + host, mbedtls_pk_get_name(&certs.p[i].cert->pk), + gc(FormatX509Name(&certs.p[i].cert->subject))); + return true; + } + } + return false; +} + +static bool TlsRouteFirst(mbedtls_pk_type_t type, mbedtls_ssl_context *ssl) { + int i; + for (i = 0; i < certs.n; ++i) { + if (IsServerCert(type, i)) { + CHECK_EQ( + 0, mbedtls_ssl_set_hs_own_cert(ssl, certs.p[i].cert, certs.p[i].key)); + DEBUGF("TlsRoute(%s) %s %`'s", mbedtls_pk_type_name(type), + mbedtls_pk_get_name(&certs.p[i].cert->pk), + gc(FormatX509Name(&certs.p[i].cert->subject))); + return true; + } + } + return false; } static int TlsRoute(void *ctx, mbedtls_ssl_context *ssl, const unsigned char *host, size_t size) { - int rc; - size_t i; int64_t ip; - int santype; - const mbedtls_x509_name *name; - const mbedtls_x509_sequence *cur; + bool ok1, ok2; ip = ParseIp((const char *)host, size); - for (rc = -1, i = 0; i < certs.n; ++i) { - if (!certs.p[i].key || !certs.p[i].cert || certs.p[i].cert->ca_istrue || - mbedtls_x509_crt_check_extended_key_usage( - certs.p[i].cert, MBEDTLS_OID_SERVER_AUTH, - MBEDTLS_OID_SIZE(MBEDTLS_OID_SERVER_AUTH))) { - continue; - } - if (ip == -1) { - if (certs.p[i].cert->ext_types & MBEDTLS_X509_EXT_SUBJECT_ALT_NAME) { - for (cur = &certs.p[i].cert->subject_alt_names; cur; cur = cur->next) { - if ((cur->buf.tag & MBEDTLS_ASN1_TAG_VALUE_MASK) == - MBEDTLS_X509_SAN_DNS_NAME && - SlicesEqualCase(host, size, cur->buf.p, cur->buf.len)) { - if (!TlsRouteCertificate(ssl, i, host, size)) rc = 0; - break; - } - } - } else { - for (name = &certs.p[i].cert->subject; name; name = name->next) { - if (!MBEDTLS_OID_CMP(MBEDTLS_OID_AT_CN, &name->oid) && - SlicesEqualCase(host, size, name->val.p, name->val.len)) { - if (!TlsRouteCertificate(ssl, i, host, size)) rc = 0; - break; - } - } - } - } else if (certs.p[i].cert->ext_types & MBEDTLS_X509_EXT_SUBJECT_ALT_NAME) { - for (cur = &certs.p[i].cert->subject_alt_names; cur; cur = cur->next) { - if ((cur->buf.tag & MBEDTLS_ASN1_TAG_VALUE_MASK) == - MBEDTLS_X509_SAN_IP_ADDRESS && - cur->buf.len == 4 && ip == READ32BE(cur->buf.p)) { - if (!TlsRouteCertificate(ssl, i, host, size)) rc = 0; - break; - } - } - } + ok1 = TlsRouteFind(MBEDTLS_PK_ECKEY, ssl, host, size, ip); + ok2 = TlsRouteFind(MBEDTLS_PK_RSA, ssl, host, size, ip); + if (!ok1 && !ok2) { + VERBOSEF("TlsRoute(%`'.*s) not found", size, host); + ok1 = TlsRouteFirst(MBEDTLS_PK_ECKEY, ssl); + ok2 = TlsRouteFirst(MBEDTLS_PK_RSA, ssl); } - if (rc) VERBOSEF("TlsRoute(%`'.*s) not found", size, host); - return rc; + return ok1 || ok2 ? 0 : -1; } static bool TlsSetup(void) { @@ -1872,19 +1866,19 @@ static void LoadCertificates(void) { certs.p[i].cert, MBEDTLS_OID_SERVER_AUTH, MBEDTLS_OID_SIZE(MBEDTLS_OID_SERVER_AUTH))) { LogCertificate("using server certificate", certs.p[i].cert); - UseCertificate(&conf, certs.p + i); + UseCertificate(&conf, certs.p + i, "server"); havecert = true; } if (!mbedtls_x509_crt_check_extended_key_usage( certs.p[i].cert, MBEDTLS_OID_CLIENT_AUTH, MBEDTLS_OID_SIZE(MBEDTLS_OID_CLIENT_AUTH))) { LogCertificate("using client certificate", certs.p[i].cert); - UseCertificate(&confcli, certs.p + i); + UseCertificate(&confcli, certs.p + i, "client"); haveclientcert = true; } } } - if (!havecert || !haveclientcert) { + if (!havecert) { if ((ksk = GetKeySigningKey()).key) { DEBUGF("generating ssl certificates using %`'s", gc(FormatX509Name(&ksk.cert->subject))); @@ -1898,14 +1892,14 @@ static void LoadCertificates(void) { } #ifdef MBEDTLS_ECP_C ecp = GenerateEcpCertificate(ksk.key ? &ksk : 0); - if (!havecert) UseCertificate(&conf, &ecp); - if (!haveclientcert) UseCertificate(&confcli, &ecp); + if (!havecert) UseCertificate(&conf, &ecp, "server"); + if (!haveclientcert && ksk.key) UseCertificate(&confcli, &ecp, "client"); AppendCert(ecp.cert, ecp.key); #endif #ifdef MBEDTLS_RSA_C rsa = GenerateRsaCertificate(ksk.key ? &ksk : 0); - if (!havecert) UseCertificate(&conf, &rsa); - if (!haveclientcert) UseCertificate(&confcli, &rsa); + if (!havecert) UseCertificate(&conf, &rsa, "server"); + if (!haveclientcert && ksk.key) UseCertificate(&confcli, &rsa, "client"); AppendCert(rsa.cert, rsa.key); #endif } @@ -2409,11 +2403,12 @@ static void AppendLogo(void) { char *p, *q; struct Asset *a; if ((a = GetAsset("/redbean.png", 12)) && (p = LoadAsset(a, &n))) { - q = EncodeBase64(p, n, &n); - Append("\"[logo]\"\r\n"); - free(q); + if ((q = EncodeBase64(p, n, &n))) { + appends(&outbuf, "\"[logo]\"\r\n"); + free(q); + } free(p); } } @@ -2438,15 +2433,17 @@ static ssize_t Send(struct iovec *iov, int iovlen) { static char *CommitOutput(char *p) { uint32_t crc; + size_t outbuflen; if (!contentlength) { - if (istext && outbuf.n >= 100) { + outbuflen = appendz(outbuf).i; + if (istext && outbuflen >= 100) { p = stpcpy(p, "Vary: Accept-Encoding\r\n"); if (!IsTiny() && ClientAcceptsGzip()) { gzipped = true; - crc = crc32_z(0, outbuf.p, outbuf.n); + crc = crc32_z(0, outbuf, outbuflen); WRITE32LE(gzip_footer + 0, crc); - WRITE32LE(gzip_footer + 4, outbuf.n); - content = FreeLater(Deflate(outbuf.p, outbuf.n, &contentlength)); + WRITE32LE(gzip_footer + 4, outbuflen); + content = FreeLater(Deflate(outbuf, outbuflen, &contentlength)); DropOutput(); } else { UseOutput(); @@ -2463,11 +2460,11 @@ static char *CommitOutput(char *p) { static char *ServeDefaultErrorPage(char *p, unsigned code, const char *reason) { p = AppendContentType(p, "text/html; charset=ISO-8859-1"); reason = FreeLater(EscapeHtml(reason, -1, 0)); - Append("\ + appends(&outbuf, "\ \r\n\ "); - Append("%d %s", code, reason); - Append("\ + appendf(&outbuf, "%d %s", code, reason); + appendf(&outbuf, "\ \r\n\ \r\n\

\r\n"); AppendLogo(); - Append("%d %s\r\n", code, reason); - Append("

\r\n"); + appendf(&outbuf, "%d %s\r\n", code, reason); + appends(&outbuf, "\r\n"); UseOutput(); return p; } @@ -2486,7 +2483,7 @@ static char *ServeErrorImpl(unsigned code, const char *reason) { char *p, *s; struct Asset *a; LockInc(&shared->c.errors); - ClearOutput(); + DropOutput(); p = SetStatus(code, reason); s = xasprintf("/%d.html", code); a = GetAsset(s, strlen(s)); @@ -2868,7 +2865,7 @@ static char *ServeListing(void) { size_t i, n, pathlen, rn[6]; LockInc(&shared->c.listingrequests); if (msg.method != kHttpGet && msg.method != kHttpHead) return BadMethod(); - Append("\ + appends(&outbuf, "\ \r\n\ \r\n\ redbean zip listing\r\n\ @@ -2885,15 +2882,16 @@ td { padding-right: 3em; }\r\n\

\r\n"); AppendLogo(); rp[0] = EscapeHtml(brand, -1, &rn[0]); - AppendData(rp[0], rn[0]); + appendd(&outbuf, rp[0], rn[0]); free(rp[0]); - Append("

\r\n" - "
%.*s
\r\n" - "
\r\n" - "
\r\n" - "
\r\n",
-         strnlen(GetZipCdirComment(zcdir), GetZipCdirCommentSize(zcdir)),
-         GetZipCdirComment(zcdir));
+  appendf(&outbuf,
+          "\r\n"
+          "
%.*s
\r\n" + "
\r\n" + "\r\n" + "
\r\n",
+          strnlen(GetZipCdirComment(zcdir), GetZipCdirCommentSize(zcdir)),
+          GetZipCdirComment(zcdir));
   memset(w, 0, sizeof(w));
   n = GetZipCdirRecords(zcdir);
   for (zcf = zbase + GetZipCdirOffset(zcdir); n--;
@@ -2925,14 +2923,16 @@ td { padding-right: 3em; }\r\n\
       iso8601(tb, &tm);
       if (IsCompressionMethodSupported(ZIP_CFILE_COMPRESSIONMETHOD(zcf)) &&
           IsAcceptablePath(path, pathlen)) {
-        Append("%-*.*s %s  %0*o %4s  %,*ld  %'s\r\n",
-               rn[2], rp[2], w[0], rn[4], rp[4], tb, w[1], GetZipCfileMode(zcf),
-               DescribeCompressionRatio(rb, zcf), w[2],
-               GetZipCfileUncompressedSize(zcf), rp[3]);
+        appendf(&outbuf,
+                "%-*.*s %s  %0*o %4s  %,*ld  %'s\r\n",
+                rn[2], rp[2], w[0], rn[4], rp[4], tb, w[1],
+                GetZipCfileMode(zcf), DescribeCompressionRatio(rb, zcf), w[2],
+                GetZipCfileUncompressedSize(zcf), rp[3]);
       } else {
-        Append("%-*.*s %s  %0*o %4s  %,*ld  %'s\r\n", w[0], rn[4], rp[4], tb,
-               w[1], GetZipCfileMode(zcf), DescribeCompressionRatio(rb, zcf),
-               w[2], GetZipCfileUncompressedSize(zcf), rp[3]);
+        appendf(&outbuf, "%-*.*s %s  %0*o %4s  %,*ld  %'s\r\n", w[0], rn[4],
+                rp[4], tb, w[1], GetZipCfileMode(zcf),
+                DescribeCompressionRatio(rb, zcf), w[2],
+                GetZipCfileUncompressedSize(zcf), rp[3]);
       }
       free(rp[4]);
       free(rp[3]);
@@ -2942,42 +2942,44 @@ td { padding-right: 3em; }\r\n\
     }
     free(path);
   }
-  Append("
\r\n"); p = SetStatus(200, "OK"); p = AppendContentType(p, "text/html"); p = AppendCache(p, 0); @@ -2989,11 +2991,11 @@ static const char *MergeNames(const char *a, const char *b) { } static void AppendLong1(const char *a, long x) { - if (x) Append("%s: %ld\r\n", a, x); + if (x) appendf(&outbuf, "%s: %ld\r\n", a, x); } static void AppendLong2(const char *a, const char *b, long x) { - if (x) Append("%s.%s: %ld\r\n", a, b, x); + if (x) appendf(&outbuf, "%s.%s: %ld\r\n", a, b, x); } static void AppendTimeval(const char *a, struct timeval *tv) { @@ -3687,6 +3689,7 @@ static void LogBody(const char *d, const char *s, size_t n) { } static int LuaFetch(lua_State *L) { +#define ssl nope /* TODO(jart): make this file less huge */ char *p; ssize_t rc; bool usessl; @@ -3843,7 +3846,7 @@ static int LuaFetch(lua_State *L) { bio->b = 0; bio->c = -1; mbedtls_ssl_set_bio(&sslcli, bio, TlsSend, 0, TlsRecvImpl); - while ((ret = mbedtls_ssl_handshake(&ssl))) { + while ((ret = mbedtls_ssl_handshake(&sslcli))) { switch (ret) { case MBEDTLS_ERR_SSL_WANT_READ: break; @@ -3856,7 +3859,8 @@ static int LuaFetch(lua_State *L) { } LockInc(&shared->c.sslhandshakes); VERBOSEF("SHAKEN %s:%s %s %s", host, port, - mbedtls_ssl_get_ciphersuite(&ssl), mbedtls_ssl_get_version(&ssl)); + mbedtls_ssl_get_ciphersuite(&sslcli), + mbedtls_ssl_get_version(&sslcli)); } /* @@ -4003,13 +4007,13 @@ static int LuaFetch(lua_State *L) { Finished: if (paylen && logbodies) LogBody("received", inbuf.p + hdrsize, paylen); - LOGF("FETCH %s HTTP%02d %d %s %`'.*s", method, msg.version, msg.status, urlarg, - HeaderLength(kHttpServer), HeaderData(kHttpServer)); + LOGF("FETCH %s HTTP%02d %d %s %`'.*s", method, msg.version, msg.status, + urlarg, HeaderLength(kHttpServer), HeaderData(kHttpServer)); if (followredirect && HasHeader(kHttpLocation) && - (msg.status == 301 || msg.status == 308 || // permanent redirects - msg.status == 302 || msg.status == 307 || // temporary redirects - msg.status == 303 // see other; non-GET changes to GET, body lost - ) && numredirects < maxredirects) { + (msg.status == 301 || msg.status == 308 || // permanent redirects + msg.status == 302 || msg.status == 307 || // temporary redirects + msg.status == 303 /* see other; non-GET changes to GET, body lost */) && + numredirects < maxredirects) { // if 303, then remove body and set method to GET if (msg.status == 303) { body = ""; @@ -4018,8 +4022,8 @@ Finished: } // create table if needed if (!lua_istable(L, 2)) { - lua_settop(L, 1); // pop body if present - lua_createtable(L, 0, 3); // body, method, numredirects + lua_settop(L, 1); // pop body if present + lua_createtable(L, 0, 3); // body, method, numredirects } lua_pushlstring(L, body, bodylen); lua_setfield(L, -2, "body"); @@ -4058,6 +4062,7 @@ VerifyFailed: LuaThrowTlsError( L, gc(DescribeSslVerifyFailure(sslcli.session_negotiate->verify_result)), ret); +#undef ssl } static int LuaGetDate(lua_State *L) { @@ -4496,7 +4501,7 @@ static int LuaWrite(lua_State *L) { const char *data; if (!lua_isnil(L, 1)) { data = luaL_checklstring(L, 1, &size); - AppendData(data, size); + appendd(&outbuf, data, size); } return 0; } @@ -5173,7 +5178,7 @@ static int LuaRe(lua_State *L) { return 1; } -static bool LuaRun(const char *path) { +static bool LuaRun(const char *path, bool mandatory) { size_t pathlen; struct Asset *a; const char *code; @@ -5184,7 +5189,11 @@ static bool LuaRun(const char *path) { effectivepath.n = pathlen; DEBUGF("LuaRun(%`'s)", path); if (luaL_dostring(L, code) != LUA_OK) { - WARNF("%s %s", path, lua_tostring(L, -1)); + if (mandatory) { + FATALF("%s %s", path, lua_tostring(L, -1)); + } else { + WARNF("%s %s", path, lua_tostring(L, -1)); + } } free(code); } @@ -5341,9 +5350,21 @@ static void LuaSetConstant(lua_State *L, const char *s, long x) { lua_setglobal(L, s); } +static char *GetDefaultLuaPath(void) { + char *s; + size_t i; + for (s = 0, i = 0; i < stagedirs.n; ++i) { + appendf(&s, "%s/.lua/?.lua;%s/.lua/?/init.lua;", stagedirs.p[i].s, + stagedirs.p[i].s); + } + appends(&s, "zip:.lua/?.lua;zip:.lua/?/init.lua"); + return s; +} + static void LuaInit(void) { #ifndef STATIC size_t i; + g_lua_path_default = GetDefaultLuaPath(); L = luaL_newstate(); luaL_openlibs(L); for (i = 0; i < ARRAYLEN(kLuaLibs); ++i) { @@ -5361,7 +5382,7 @@ static void LuaInit(void) { LuaSetConstant(L, "kLogWarn", kLogWarn); LuaSetConstant(L, "kLogError", kLogError); LuaSetConstant(L, "kLogFatal", kLogFatal); - if (LuaRun("/.init.lua")) { + if (LuaRun("/.init.lua", true)) { hasonhttprequest = IsHookDefined("OnHttpRequest"); hasonclientconnection = IsHookDefined("OnClientConnection"); hasonprocesscreate = IsHookDefined("OnProcessCreate"); @@ -5376,7 +5397,7 @@ static void LuaInit(void) { static void LuaReload(void) { #ifndef STATIC - if (!LuaRun("/.reload.lua")) { + if (!LuaRun("/.reload.lua", false)) { DEBUGF("no /.reload.lua defined"); } #endif @@ -5580,7 +5601,7 @@ static void HandleHeartbeat(void) { Reindex(); getrusage(RUSAGE_SELF, &shared->server); #ifndef STATIC - LuaRun("/.heartbeat.lua"); + LuaRun("/.heartbeat.lua", false); CollectGarbage(); #endif for (i = 0; i < servers.n; ++i) { @@ -6156,13 +6177,14 @@ static bool HandleMessage(void) { } static void InitRequest(void) { + assert(!outbuf); frags = 0; + outbuf = 0; gzipped = 0; branded = 0; content = 0; msgsize = 0; loops.n = 0; - outbuf.n = 0; generator = 0; luaheaderp = 0; contentlength = 0; @@ -6614,9 +6636,9 @@ static void MemDestroy(void) { Free(&unmaplist.p), unmaplist.n = 0; Free(&freelist.p), freelist.n = 0; Free(&servers.p), servers.n = 0; - Free(&outbuf.p), outbuf.n = 0; Free(&hdrbuf.p), hdrbuf.n = 0; Free(&inbuf.p), inbuf.n = 0; + Free(&outbuf); FreeStrings(&stagedirs); FreeStrings(&hidepaths); Free(&launchbrowser);