mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-02-12 01:08:00 +00:00
Make exciting improvements
- Add Lua backtraces to redbean! - Wipe serving keys after redbean forks - Audit redbean to remove free via exit - Log SSL client ciphersuite preferences - Increase ASAN malloc() backtrace depth - Make GetSslRoots() behave as a singleton - Move leaks.c from LIBC_TESTLIB to LIBC_LOG - Add undocumented %n to printf() for newlines - Fix redbean memory leak reindexing inode change - Fix redbean memory leak with Fetch() DNS object - Restore original environ after __cxa_finalize() - Make backtrace always work after __cxa_finalize() - Introduce COUNTEXPR() diagnostic / benchmark tool - Fix a few more instances of errno being clobbered - Consolidate the ANSI color disabling internal APIs
This commit is contained in:
parent
f5831a62fa
commit
af645fcbec
61 changed files with 1354 additions and 814 deletions
|
@ -100,7 +100,8 @@ SANITIZER = \
|
||||||
NO_MAGIC = \
|
NO_MAGIC = \
|
||||||
-mno-fentry \
|
-mno-fentry \
|
||||||
-fno-stack-protector \
|
-fno-stack-protector \
|
||||||
-fwrapv
|
-fwrapv \
|
||||||
|
-fno-sanitize=all
|
||||||
|
|
||||||
OLD_CODE = \
|
OLD_CODE = \
|
||||||
-fno-strict-aliasing \
|
-fno-strict-aliasing \
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include "dsp/tty/tty.h"
|
#include "dsp/tty/tty.h"
|
||||||
#include "libc/bits/pushpop.h"
|
#include "libc/bits/pushpop.h"
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
|
#include "libc/log/internal.h"
|
||||||
#include "libc/log/log.h"
|
#include "libc/log/log.h"
|
||||||
#include "libc/nt/console.h"
|
#include "libc/nt/console.h"
|
||||||
#include "libc/nt/runtime.h"
|
#include "libc/nt/runtime.h"
|
||||||
|
@ -30,7 +31,7 @@
|
||||||
static int ttysetcursor(int fd, bool visible) {
|
static int ttysetcursor(int fd, bool visible) {
|
||||||
struct NtConsoleCursorInfo ntcursor;
|
struct NtConsoleCursorInfo ntcursor;
|
||||||
char code[8] = "\e[?25l";
|
char code[8] = "\e[?25l";
|
||||||
if (IsTerminalInarticulate()) return 0;
|
if (__nocolor) return 0;
|
||||||
if (visible) code[5] = 'h';
|
if (visible) code[5] = 'h';
|
||||||
if (SupportsWindows()) {
|
if (SupportsWindows()) {
|
||||||
GetConsoleCursorInfo(GetStdHandle(kNtStdOutputHandle), &ntcursor);
|
GetConsoleCursorInfo(GetStdHandle(kNtStdOutputHandle), &ntcursor);
|
||||||
|
|
|
@ -8,7 +8,10 @@
|
||||||
╚─────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────*/
|
||||||
#endif
|
#endif
|
||||||
#include "libc/bits/bits.h"
|
#include "libc/bits/bits.h"
|
||||||
|
#include "libc/dce.h"
|
||||||
#include "libc/log/log.h"
|
#include "libc/log/log.h"
|
||||||
|
#include "libc/runtime/runtime.h"
|
||||||
|
#include "libc/stdio/stdio.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ASAN static memory safety crash example.
|
* ASAN static memory safety crash example.
|
||||||
|
@ -40,11 +43,17 @@
|
||||||
* 0x000000000040268d: cosmo at libc/runtime/cosmo.S:64
|
* 0x000000000040268d: cosmo at libc/runtime/cosmo.S:64
|
||||||
* 0x00000000004021ae: _start at libc/crt/crt.S:77
|
* 0x00000000004021ae: _start at libc/crt/crt.S:77
|
||||||
*
|
*
|
||||||
|
* @see libc/intrin/asancodes.h for meaning of G, etc. and negative numbers
|
||||||
|
* @see libc/nexgen32e/kcp437.S for meaning of symbols
|
||||||
*/
|
*/
|
||||||
|
|
||||||
char buffer[13] = "hello";
|
char buffer[13] = "hello";
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
|
if (!IsAsan()) {
|
||||||
|
printf("this example is intended for MODE=asan or MODE=dbg\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
ShowCrashReports(); /* not needed but yoinks appropriate symbols */
|
ShowCrashReports(); /* not needed but yoinks appropriate symbols */
|
||||||
int i = 13;
|
int i = 13;
|
||||||
asm("" : "+r"(i)); /* prevent compiler being smart */
|
asm("" : "+r"(i)); /* prevent compiler being smart */
|
||||||
|
|
|
@ -8,8 +8,11 @@
|
||||||
╚─────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────*/
|
||||||
#endif
|
#endif
|
||||||
#include "libc/bits/bits.h"
|
#include "libc/bits/bits.h"
|
||||||
|
#include "libc/dce.h"
|
||||||
#include "libc/log/log.h"
|
#include "libc/log/log.h"
|
||||||
#include "libc/mem/mem.h"
|
#include "libc/mem/mem.h"
|
||||||
|
#include "libc/runtime/runtime.h"
|
||||||
|
#include "libc/stdio/stdio.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -50,9 +53,15 @@
|
||||||
* 0x000000000040270f: cosmo at libc/runtime/cosmo.S:64
|
* 0x000000000040270f: cosmo at libc/runtime/cosmo.S:64
|
||||||
* 0x00000000004021ae: _start at libc/crt/crt.S:77
|
* 0x00000000004021ae: _start at libc/crt/crt.S:77
|
||||||
*
|
*
|
||||||
|
* @see libc/intrin/asancodes.h for meaning of U, O, etc. and negative numbers
|
||||||
|
* @see libc/nexgen32e/kcp437.S for meaning of symbols
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
|
if (!IsAsan()) {
|
||||||
|
printf("this example is intended for MODE=asan or MODE=dbg\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
char *buffer;
|
char *buffer;
|
||||||
ShowCrashReports(); /* not needed but yoinks appropriate symbols */
|
ShowCrashReports(); /* not needed but yoinks appropriate symbols */
|
||||||
buffer = malloc(13);
|
buffer = malloc(13);
|
||||||
|
|
|
@ -8,8 +8,11 @@
|
||||||
╚─────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────*/
|
||||||
#endif
|
#endif
|
||||||
#include "libc/bits/bits.h"
|
#include "libc/bits/bits.h"
|
||||||
|
#include "libc/dce.h"
|
||||||
#include "libc/log/log.h"
|
#include "libc/log/log.h"
|
||||||
#include "libc/mem/mem.h"
|
#include "libc/mem/mem.h"
|
||||||
|
#include "libc/runtime/runtime.h"
|
||||||
|
#include "libc/stdio/stdio.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -21,6 +24,10 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
|
if (!IsAsan()) {
|
||||||
|
printf("this example is intended for MODE=asan or MODE=dbg\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
char *buffer;
|
char *buffer;
|
||||||
ShowCrashReports(); /* not needed but yoinks appropriate symbols */
|
ShowCrashReports(); /* not needed but yoinks appropriate symbols */
|
||||||
buffer = malloc(13);
|
buffer = malloc(13);
|
||||||
|
|
|
@ -240,19 +240,17 @@ int main(int argc, char *argv[]) {
|
||||||
*/
|
*/
|
||||||
mbedtls_ssl_config conf;
|
mbedtls_ssl_config conf;
|
||||||
mbedtls_ssl_context ssl;
|
mbedtls_ssl_context ssl;
|
||||||
mbedtls_x509_crt *cachain = 0;
|
|
||||||
mbedtls_ctr_drbg_context drbg;
|
mbedtls_ctr_drbg_context drbg;
|
||||||
if (usessl) {
|
if (usessl) {
|
||||||
mbedtls_ssl_init(&ssl);
|
mbedtls_ssl_init(&ssl);
|
||||||
mbedtls_ctr_drbg_init(&drbg);
|
mbedtls_ctr_drbg_init(&drbg);
|
||||||
mbedtls_ssl_config_init(&conf);
|
mbedtls_ssl_config_init(&conf);
|
||||||
cachain = GetSslRoots();
|
|
||||||
CHECK_EQ(0, mbedtls_ctr_drbg_seed(&drbg, GetEntropy, 0, "justine", 7));
|
CHECK_EQ(0, mbedtls_ctr_drbg_seed(&drbg, GetEntropy, 0, "justine", 7));
|
||||||
CHECK_EQ(0, mbedtls_ssl_config_defaults(&conf, MBEDTLS_SSL_IS_CLIENT,
|
CHECK_EQ(0, mbedtls_ssl_config_defaults(&conf, MBEDTLS_SSL_IS_CLIENT,
|
||||||
MBEDTLS_SSL_TRANSPORT_STREAM,
|
MBEDTLS_SSL_TRANSPORT_STREAM,
|
||||||
MBEDTLS_SSL_PRESET_DEFAULT));
|
MBEDTLS_SSL_PRESET_DEFAULT));
|
||||||
mbedtls_ssl_conf_authmode(&conf, authmode);
|
mbedtls_ssl_conf_authmode(&conf, authmode);
|
||||||
mbedtls_ssl_conf_ca_chain(&conf, cachain, 0);
|
mbedtls_ssl_conf_ca_chain(&conf, GetSslRoots(), 0);
|
||||||
mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &drbg);
|
mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &drbg);
|
||||||
if (!IsTiny()) mbedtls_ssl_conf_dbg(&conf, TlsDebug, 0);
|
if (!IsTiny()) mbedtls_ssl_conf_dbg(&conf, TlsDebug, 0);
|
||||||
CHECK_EQ(0, mbedtls_ssl_setup(&ssl, &conf));
|
CHECK_EQ(0, mbedtls_ssl_setup(&ssl, &conf));
|
||||||
|
@ -413,7 +411,6 @@ Finished:
|
||||||
mbedtls_ssl_free(&ssl);
|
mbedtls_ssl_free(&ssl);
|
||||||
mbedtls_ctr_drbg_free(&drbg);
|
mbedtls_ctr_drbg_free(&drbg);
|
||||||
mbedtls_ssl_config_free(&conf);
|
mbedtls_ssl_config_free(&conf);
|
||||||
mbedtls_x509_crt_free(cachain);
|
|
||||||
mbedtls_ctr_drbg_free(&drbg);
|
mbedtls_ctr_drbg_free(&drbg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,11 @@
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns directory portion of path.
|
* Returns directory portion of path.
|
||||||
* @param s is mutated
|
*
|
||||||
|
* This returns "." if path doesn't have slashes. If path is empty then
|
||||||
|
* this returns empty string.
|
||||||
|
*
|
||||||
|
* @param s is mutated and must not be NULL
|
||||||
*/
|
*/
|
||||||
char *dirname(char *s) {
|
char *dirname(char *s) {
|
||||||
size_t i, n;
|
size_t i, n;
|
||||||
|
|
|
@ -40,6 +40,8 @@
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
extern bool __nomultics;
|
||||||
|
|
||||||
static const char kSpecialFloats[2][2][4] = {{"INF", "inf"}, {"NAN", "nan"}};
|
static const char kSpecialFloats[2][2][4] = {{"INF", "inf"}, {"NAN", "nan"}};
|
||||||
|
|
||||||
static void __fmt_free_dtoa(char **mem) {
|
static void __fmt_free_dtoa(char **mem) {
|
||||||
|
@ -385,6 +387,11 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'n':
|
||||||
|
if (__nomultics) PUT('\r');
|
||||||
|
PUT('\n');
|
||||||
|
break;
|
||||||
|
|
||||||
case 'F':
|
case 'F':
|
||||||
case 'f':
|
case 'f':
|
||||||
if (!(flags & FLAGS_PRECISION)) prec = 6;
|
if (!(flags & FLAGS_PRECISION)) prec = 6;
|
||||||
|
|
|
@ -52,6 +52,10 @@
|
||||||
|
|
||||||
STATIC_YOINK("_init_asan");
|
STATIC_YOINK("_init_asan");
|
||||||
|
|
||||||
|
#define ASAN_MORGUE_ITEMS 512
|
||||||
|
#define ASAN_MORGUE_THRESHOLD 65536 // morgue memory O(ITEMS*THRESHOLD)
|
||||||
|
#define ASAN_TRACE_ITEMS 16 // backtrace limit on malloc origin
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @fileoverview Cosmopolitan Address Sanitizer Runtime.
|
* @fileoverview Cosmopolitan Address Sanitizer Runtime.
|
||||||
*
|
*
|
||||||
|
@ -83,8 +87,6 @@ STATIC_YOINK("_init_asan");
|
||||||
* movq (%addr),%dst
|
* movq (%addr),%dst
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define ASAN_MORGUE_SIZE 128
|
|
||||||
|
|
||||||
#define HOOK(HOOK, IMPL) \
|
#define HOOK(HOOK, IMPL) \
|
||||||
do { \
|
do { \
|
||||||
if (weaken(HOOK)) { \
|
if (weaken(HOOK)) { \
|
||||||
|
@ -104,7 +106,7 @@ STATIC_YOINK("_init_asan");
|
||||||
typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(1)));
|
typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(1)));
|
||||||
|
|
||||||
struct AsanTrace {
|
struct AsanTrace {
|
||||||
intptr_t p[4];
|
uint32_t p[ASAN_TRACE_ITEMS]; // assumes linkage into 32-bit space
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AsanExtra {
|
struct AsanExtra {
|
||||||
|
@ -139,7 +141,12 @@ struct AsanGlobal {
|
||||||
|
|
||||||
struct AsanMorgue {
|
struct AsanMorgue {
|
||||||
unsigned i;
|
unsigned i;
|
||||||
void *p[ASAN_MORGUE_SIZE];
|
void *p[ASAN_MORGUE_ITEMS];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ReportOriginHeap {
|
||||||
|
const unsigned char *a;
|
||||||
|
int z;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool __asan_noreentry;
|
bool __asan_noreentry;
|
||||||
|
@ -657,11 +664,6 @@ static void __asan_report_memory_origin_image(intptr_t a, int z) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ReportOriginHeap {
|
|
||||||
const unsigned char *a;
|
|
||||||
int z;
|
|
||||||
};
|
|
||||||
|
|
||||||
static noasan void OnMemory(void *x, void *y, size_t n, void *a) {
|
static noasan void OnMemory(void *x, void *y, size_t n, void *a) {
|
||||||
const unsigned char *p = x;
|
const unsigned char *p = x;
|
||||||
struct ReportOriginHeap *t = a;
|
struct ReportOriginHeap *t = a;
|
||||||
|
@ -725,6 +727,7 @@ nodiscard static __asan_die_f *__asan_report(const void *addr, int size,
|
||||||
uint64_t x, y, z;
|
uint64_t x, y, z;
|
||||||
char *p, *q, *base;
|
char *p, *q, *base;
|
||||||
struct MemoryIntervals *m;
|
struct MemoryIntervals *m;
|
||||||
|
++g_ftrace;
|
||||||
p = __fatalbuf;
|
p = __fatalbuf;
|
||||||
kprintf("%n\e[J\e[1;31masan error\e[0m: %s %d-byte %s at %p shadow %p%n%s%n",
|
kprintf("%n\e[J\e[1;31masan error\e[0m: %s %d-byte %s at %p shadow %p%n%s%n",
|
||||||
__asan_describe_access_poison(kind), size, message, addr,
|
__asan_describe_access_poison(kind), size, message, addr,
|
||||||
|
@ -805,6 +808,7 @@ nodiscard static __asan_die_f *__asan_report(const void *addr, int size,
|
||||||
kprintf("%s", __fatalbuf);
|
kprintf("%s", __fatalbuf);
|
||||||
__asan_report_memory_origin(addr, size, kind);
|
__asan_report_memory_origin(addr, size, kind);
|
||||||
kprintf("%nthe crash was caused by%n");
|
kprintf("%nthe crash was caused by%n");
|
||||||
|
--g_ftrace;
|
||||||
return __asan_die();
|
return __asan_die();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1005,7 +1009,7 @@ int __asan_print_trace(void *p) {
|
||||||
kprintf(" bad cookie");
|
kprintf(" bad cookie");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
kprintf("%n%p %,lu bytes [asan]", (char *)p + 16, n);
|
kprintf("%n%p %,lu bytes [asan]", (char *)p, n);
|
||||||
if (!__asan_is_mapped((((intptr_t)p >> 3) + 0x7fff8000) >> 16)) {
|
if (!__asan_is_mapped((((intptr_t)p >> 3) + 0x7fff8000) >> 16)) {
|
||||||
kprintf(" (shadow not mapped?!)");
|
kprintf(" (shadow not mapped?!)");
|
||||||
}
|
}
|
||||||
|
@ -1024,7 +1028,7 @@ static void __asan_deallocate(char *p, long kind) {
|
||||||
if ((e = __asan_get_extra(p, &c))) {
|
if ((e = __asan_get_extra(p, &c))) {
|
||||||
if (__asan_read48(e->size, &n)) {
|
if (__asan_read48(e->size, &n)) {
|
||||||
__asan_poison((uintptr_t)p, c, kind);
|
__asan_poison((uintptr_t)p, c, kind);
|
||||||
if (c <= FRAMESIZE) {
|
if (c <= ASAN_MORGUE_THRESHOLD) {
|
||||||
p = __asan_morgue_add(p);
|
p = __asan_morgue_add(p);
|
||||||
}
|
}
|
||||||
weaken(dlfree)(p);
|
weaken(dlfree)(p);
|
||||||
|
|
|
@ -16,18 +16,19 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/calls/sysdebug.internal.h"
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
|
|
||||||
#define ToUpper(c) \
|
forceinline int Identity(int c) {
|
||||||
(IsWindows() && (c) >= 'a' && (c) <= 'z' ? (c) - 'a' + 'A' : (c))
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
forceinline int ToUpper(int c) {
|
||||||
* Returns value of environment variable, or NULL if not found.
|
return 'a' <= c && c <= 'z' ? c - ('a' - 'A') : c;
|
||||||
*
|
}
|
||||||
* Environment variables can store empty string on Unix but not Windows.
|
|
||||||
*/
|
forceinline char *GetEnv(const char *s, int xlat(int)) {
|
||||||
char *getenv(const char *s) {
|
|
||||||
char **p;
|
char **p;
|
||||||
size_t i, j;
|
size_t i, j;
|
||||||
if ((p = environ)) {
|
if ((p = environ)) {
|
||||||
|
@ -39,7 +40,7 @@ char *getenv(const char *s) {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (ToUpper(s[j]) != ToUpper(p[i][j])) {
|
if (xlat(s[j]) != xlat(p[i][j])) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,3 +48,21 @@ char *getenv(const char *s) {
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns value of environment variable, or NULL if not found.
|
||||||
|
*
|
||||||
|
* Environment variables can store empty string on Unix but not Windows.
|
||||||
|
*
|
||||||
|
* @note should not be used after __cxa_finalize() is called
|
||||||
|
*/
|
||||||
|
char *getenv(const char *s) {
|
||||||
|
char *r;
|
||||||
|
if (!IsWindows()) {
|
||||||
|
r = GetEnv(s, Identity);
|
||||||
|
} else {
|
||||||
|
r = GetEnv(s, ToUpper);
|
||||||
|
}
|
||||||
|
SYSDEBUG("getenv(%#s) → %#s", s, r);
|
||||||
|
return r;
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
/*-*- 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│
|
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
│ Copyright 2021 Justine Alexandra Roberts Tunney │
|
||||||
│ │
|
│ │
|
||||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||||
│ any purpose with or without fee is hereby granted, provided that the │
|
│ any purpose with or without fee is hereby granted, provided that the │
|
||||||
|
@ -16,31 +16,17 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/bits/safemacros.internal.h"
|
#include "libc/assert.h"
|
||||||
#include "libc/log/internal.h"
|
#include "libc/dce.h"
|
||||||
#include "libc/log/libfatal.internal.h"
|
|
||||||
#include "libc/log/log.h"
|
|
||||||
#include "libc/nt/enum/version.h"
|
#include "libc/nt/enum/version.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/nt/version.h"
|
||||||
#include "libc/str/str.h"
|
|
||||||
|
|
||||||
bool g_isterminalinarticulate;
|
/**
|
||||||
|
* Returns true if we're running at least Windows 10.
|
||||||
bool IsTerminalInarticulate(void) {
|
*
|
||||||
return g_isterminalinarticulate;
|
* This function may only be called if IsWindows() is true.
|
||||||
|
*/
|
||||||
|
privileged bool(IsAtLeastWindows10)(void) {
|
||||||
|
assert(IsWindows());
|
||||||
|
return IsAtLeastWindows10();
|
||||||
}
|
}
|
||||||
|
|
||||||
textstartup noasan void g_isterminalinarticulate_init(int argc, char **argv,
|
|
||||||
char **envp,
|
|
||||||
intptr_t *auxv) {
|
|
||||||
char *s;
|
|
||||||
if (IsWindows() && NtGetVersion() < kNtVersionWindows10) {
|
|
||||||
g_isterminalinarticulate = true;
|
|
||||||
} else if ((s = __getenv(envp, "TERM"))) {
|
|
||||||
g_isterminalinarticulate = !__strcmp(s, "dumb");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const void *const g_isterminalinarticulate_ctor[] initarray = {
|
|
||||||
g_isterminalinarticulate_init,
|
|
||||||
};
|
|
|
@ -37,7 +37,7 @@ noasan noubsan int IsDebuggerPresent(bool force) {
|
||||||
char *p, buf[1024];
|
char *p, buf[1024];
|
||||||
if (!force) {
|
if (!force) {
|
||||||
if (IsGenuineCosmo()) return 0;
|
if (IsGenuineCosmo()) return 0;
|
||||||
if (__getenv(__envp, "HEISENDEBUG")) return 0;
|
if (getenv("HEISENDEBUG")) return 0;
|
||||||
}
|
}
|
||||||
if (IsWindows()) {
|
if (IsWindows()) {
|
||||||
return NtGetPeb()->BeingDebugged; /* needs noasan */
|
return NtGetPeb()->BeingDebugged; /* needs noasan */
|
|
@ -30,9 +30,8 @@ bool IsRunningUnderMake(void) {
|
||||||
return g_isrunningundermake;
|
return g_isrunningundermake;
|
||||||
}
|
}
|
||||||
|
|
||||||
textstartup void g_isrunningundermake_init(int argc, char **argv, char **envp,
|
textstartup void g_isrunningundermake_init(void) {
|
||||||
intptr_t *auxv) {
|
g_isrunningundermake = !!getenv("MAKEFLAGS");
|
||||||
g_isrunningundermake = !!__getenv(envp, "MAKEFLAGS");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const void *const g_isrunningundermake_ctor[] initarray = {
|
const void *const g_isrunningundermake_ctor[] initarray = {
|
||||||
|
|
|
@ -16,45 +16,46 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/bits/safemacros.internal.h"
|
|
||||||
#include "libc/calls/calls.h"
|
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
#include "libc/log/color.internal.h"
|
#include "libc/log/internal.h"
|
||||||
#include "libc/log/log.h"
|
#include "libc/nt/version.h"
|
||||||
#include "libc/nt/enum/version.h"
|
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
#include "libc/str/str.h"
|
|
||||||
|
#define IsDumb(s) \
|
||||||
|
(s[0] == 'd' && s[1] == 'u' && s[2] == 'm' && s[3] == 'b' && !s[4])
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if ANSI terminal colors are appropriate.
|
* Indicates if ANSI terminal colors are inappropriate.
|
||||||
*
|
*
|
||||||
* We take an optimistic approach here. We use colors, unless we see the
|
* Normally this variable should be false. We only set it to true if
|
||||||
* environment variable TERM=dumb, which is set by software like Emacs.
|
* we're running on an old version of Windows or the environment
|
||||||
* It's a common antipattern to check isatty(STDERR_FILENO), since that
|
* variable `TERM` is set to `dumb`.
|
||||||
* usually makes colors harder to get than they are to remove:
|
*
|
||||||
|
* We think colors should be the norm, since most software is usually
|
||||||
|
* too conservative about removing them. Rather than using `isatty`
|
||||||
|
* consider using sed for instances where color must be removed:
|
||||||
*
|
*
|
||||||
* sed 's/\x1b\[[;[:digit:]]*m//g' <color.txt >uncolor.txt
|
* sed 's/\x1b\[[;[:digit:]]*m//g' <color.txt >uncolor.txt
|
||||||
*
|
*
|
||||||
* Ideally, all software should be updated to understand color, since
|
* For some reason, important software is configured by default in many
|
||||||
* it's been formally standardized nearly as long as ASCII. Even old
|
* operating systems, to not only disable colors, but utf-8 too! Here's
|
||||||
* MS-DOS supports it (but Windows didn't until Windows 10) yet even
|
* an example of how a wrapper script can fix that for `less`.
|
||||||
* tools like less may need wrapper scripts, e.g.:
|
|
||||||
*
|
*
|
||||||
* #!/bin/sh
|
* #!/bin/sh
|
||||||
* LESSCHARSET=UTF-8 exec /usr/bin/less -RS "$@"
|
* LESSCHARSET=UTF-8 exec /usr/bin/less -RS "$@"
|
||||||
*
|
*
|
||||||
* It's that easy fam.
|
* Thank you for using colors!
|
||||||
*/
|
*/
|
||||||
bool cancolor(void) {
|
bool __nocolor;
|
||||||
static bool once;
|
|
||||||
static bool result;
|
optimizesize textstartup noasan void __nocolor_init(int argc, char **argv,
|
||||||
return 1;
|
char **envp,
|
||||||
if (!once) {
|
intptr_t *auxv) {
|
||||||
result = (!IsWindows() || NtGetVersion() >= kNtVersionWindows10 ||
|
char *s;
|
||||||
!ischardev(1)) &&
|
__nocolor = (IsWindows() && !IsAtLeastWindows10()) ||
|
||||||
!!strcmp(nulltoempty(getenv("DONTANSIMEBRO")), "1") &&
|
((s = getenv("TERM")) && IsDumb(s));
|
||||||
!!strcmp(nulltoempty(getenv("TERM")), "dumb");
|
|
||||||
once = true;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const void *const __nocolor_ctor[] initarray = {
|
||||||
|
__nocolor_init,
|
||||||
|
};
|
|
@ -18,6 +18,20 @@
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/log/log.h"
|
#include "libc/log/log.h"
|
||||||
|
|
||||||
const char *GetAddr2linePath(void) {
|
static const char *__addr2line;
|
||||||
return commandvenv("ADDR2LINE", "addr2line");
|
|
||||||
|
static textstartup void __addr2line_init() {
|
||||||
|
static bool once;
|
||||||
|
if (!once) {
|
||||||
|
__addr2line = commandvenv("ADDR2LINE", "addr2line");
|
||||||
|
once = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *GetAddr2linePath(void) {
|
||||||
|
return __addr2line;
|
||||||
|
}
|
||||||
|
|
||||||
|
const void *const __addr2line_ctor[] initarray = {
|
||||||
|
__addr2line_init,
|
||||||
|
};
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#include "libc/fmt/itoa.h"
|
#include "libc/fmt/itoa.h"
|
||||||
#include "libc/intrin/kprintf.h"
|
#include "libc/intrin/kprintf.h"
|
||||||
#include "libc/log/backtrace.internal.h"
|
#include "libc/log/backtrace.internal.h"
|
||||||
|
#include "libc/log/color.internal.h"
|
||||||
#include "libc/log/libfatal.internal.h"
|
#include "libc/log/libfatal.internal.h"
|
||||||
#include "libc/log/log.h"
|
#include "libc/log/log.h"
|
||||||
#include "libc/nexgen32e/gc.internal.h"
|
#include "libc/nexgen32e/gc.internal.h"
|
||||||
|
@ -47,6 +48,10 @@
|
||||||
#define kBacktraceMaxFrames 128
|
#define kBacktraceMaxFrames 128
|
||||||
#define kBacktraceBufSize ((kBacktraceMaxFrames - 1) * (18 + 1))
|
#define kBacktraceBufSize ((kBacktraceMaxFrames - 1) * (18 + 1))
|
||||||
|
|
||||||
|
static void ShowHint(const char *s) {
|
||||||
|
kprintf("%snote: %s%s%n", SUBTLE, s, RESET);
|
||||||
|
}
|
||||||
|
|
||||||
static int PrintBacktraceUsingAddr2line(int fd, const struct StackFrame *bp) {
|
static int PrintBacktraceUsingAddr2line(int fd, const struct StackFrame *bp) {
|
||||||
ssize_t got;
|
ssize_t got;
|
||||||
intptr_t addr;
|
intptr_t addr;
|
||||||
|
@ -59,15 +64,13 @@ static int PrintBacktraceUsingAddr2line(int fd, const struct StackFrame *bp) {
|
||||||
char buf[kBacktraceBufSize], *argv[kBacktraceMaxFrames];
|
char buf[kBacktraceBufSize], *argv[kBacktraceMaxFrames];
|
||||||
|
|
||||||
if (!(debugbin = FindDebugBinary())) {
|
if (!(debugbin = FindDebugBinary())) {
|
||||||
if (IsLinux()) {
|
ShowHint("can't find .com.dbg file try setting COMDBG");
|
||||||
kprintf("warning: can't find debug binary try setting COMDBG%n");
|
|
||||||
}
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(addr2line = GetAddr2linePath())) {
|
if (!(addr2line = GetAddr2linePath())) {
|
||||||
if (IsLinux()) {
|
if (IsLinux()) {
|
||||||
kprintf("warning: can't find addr2line try setting ADDR2LINE%n");
|
ShowHint("can't find addr2line on path or in ADDR2LINE");
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -79,7 +82,7 @@ static int PrintBacktraceUsingAddr2line(int fd, const struct StackFrame *bp) {
|
||||||
* tooling which can be counted upon.
|
* tooling which can be counted upon.
|
||||||
*/
|
*/
|
||||||
if (!IsLinux()) {
|
if (!IsLinux()) {
|
||||||
kprintf("note: won't print addr2line backtrace on non-linux%n");
|
ShowHint("won't print addr2line backtrace on non-linux");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,16 +173,14 @@ void ShowBacktrace(int fd, const struct StackFrame *bp) {
|
||||||
#ifdef __FNO_OMIT_FRAME_POINTER__
|
#ifdef __FNO_OMIT_FRAME_POINTER__
|
||||||
/* asan runtime depends on this function */
|
/* asan runtime depends on this function */
|
||||||
static bool noreentry;
|
static bool noreentry;
|
||||||
--g_ftrace;
|
++g_ftrace;
|
||||||
if (!bp) bp = __builtin_frame_address(0);
|
if (!bp) bp = __builtin_frame_address(0);
|
||||||
if (!noreentry) {
|
if (!noreentry) {
|
||||||
noreentry = true;
|
noreentry = true;
|
||||||
PrintBacktrace(fd, bp);
|
PrintBacktrace(fd, bp);
|
||||||
noreentry = false;
|
noreentry = false;
|
||||||
} else {
|
|
||||||
kprintf("warning: re-entered ShowBackTrace()%n");
|
|
||||||
}
|
}
|
||||||
++g_ftrace;
|
--g_ftrace;
|
||||||
#else
|
#else
|
||||||
kprintf("ShowBacktrace() needs these flags to show C backtrace:%n"
|
kprintf("ShowBacktrace() needs these flags to show C backtrace:%n"
|
||||||
"\t-D__FNO_OMIT_FRAME_POINTER__%n"
|
"\t-D__FNO_OMIT_FRAME_POINTER__%n"
|
||||||
|
|
|
@ -36,7 +36,7 @@ relegated void ___check_fail_ndebug(uint64_t want, uint64_t got,
|
||||||
const char *opchar) {
|
const char *opchar) {
|
||||||
__restore_tty(1);
|
__restore_tty(1);
|
||||||
kprintf("%n%serror: %s: check failed: 0x%x %s 0x%x (%s)%n",
|
kprintf("%n%serror: %s: check failed: 0x%x %s 0x%x (%s)%n",
|
||||||
!g_isterminalinarticulate ? "\e[J" : "", program_invocation_name,
|
!__nocolor ? "\e[J" : "", program_invocation_name, want, opchar, got,
|
||||||
want, opchar, got, strerror(errno));
|
strerror(errno));
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,20 +1,17 @@
|
||||||
#ifndef COSMOPOLITAN_LIBC_LOG_COLOR_H_
|
#ifndef COSMOPOLITAN_LIBC_LOG_COLOR_H_
|
||||||
#define COSMOPOLITAN_LIBC_LOG_COLOR_H_
|
#define COSMOPOLITAN_LIBC_LOG_COLOR_H_
|
||||||
|
#include "libc/log/internal.h"
|
||||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||||
COSMOPOLITAN_C_START_
|
|
||||||
|
|
||||||
#define CLS (cancolor() ? "\r\e[J" : "")
|
#define CLS (!__nocolor ? "\r\e[J" : "")
|
||||||
#define RED (cancolor() ? "\e[30;101m" : "")
|
#define RED (!__nocolor ? "\e[30;101m" : "")
|
||||||
#define GREEN (cancolor() ? "\e[32m" : "")
|
#define GREEN (!__nocolor ? "\e[32m" : "")
|
||||||
#define UNBOLD (cancolor() ? "\e[22m" : "")
|
#define UNBOLD (!__nocolor ? "\e[22m" : "")
|
||||||
#define RED2 (cancolor() ? "\e[91;1m" : "")
|
#define RED2 (!__nocolor ? "\e[91;1m" : "")
|
||||||
#define BLUE1 (cancolor() ? "\e[94;49m" : "")
|
#define BLUE1 (!__nocolor ? "\e[94;49m" : "")
|
||||||
#define BLUE2 (cancolor() ? "\e[34m" : "")
|
#define BLUE2 (!__nocolor ? "\e[34m" : "")
|
||||||
#define RESET (cancolor() ? "\e[0m" : "")
|
#define RESET (!__nocolor ? "\e[0m" : "")
|
||||||
#define SUBTLE (cancolor() ? "\e[35m" : "")
|
#define SUBTLE (!__nocolor ? "\e[35m" : "")
|
||||||
|
|
||||||
bool cancolor(void) nothrow nocallback nosideeffect;
|
|
||||||
|
|
||||||
COSMOPOLITAN_C_END_
|
|
||||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||||
#endif /* COSMOPOLITAN_LIBC_LOG_COLOR_H_ */
|
#endif /* COSMOPOLITAN_LIBC_LOG_COLOR_H_ */
|
||||||
|
|
|
@ -45,7 +45,7 @@
|
||||||
* or the environment variable was empty; noting that the caller
|
* or the environment variable was empty; noting that the caller
|
||||||
* should copy this string before saving it
|
* should copy this string before saving it
|
||||||
*/
|
*/
|
||||||
noasan const char *commandvenv(const char *var, const char *cmd) {
|
const char *commandvenv(const char *var, const char *cmd) {
|
||||||
const char *exepath;
|
const char *exepath;
|
||||||
static char pathbuf[PATH_MAX];
|
static char pathbuf[PATH_MAX];
|
||||||
if (*cmd == '/' || *cmd == '\\') return cmd;
|
if (*cmd == '/' || *cmd == '\\') return cmd;
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
#ifndef COSMOPOLITAN_LIBC_LOG_COUNTBRANCH_H_
|
#ifndef COSMOPOLITAN_LIBC_LOG_COUNTBRANCH_H_
|
||||||
#define COSMOPOLITAN_LIBC_LOG_COUNTBRANCH_H_
|
#define COSMOPOLITAN_LIBC_LOG_COUNTBRANCH_H_
|
||||||
|
#include "libc/macros.internal.h"
|
||||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||||
COSMOPOLITAN_C_START_
|
COSMOPOLITAN_C_START_
|
||||||
#include "libc/macros.internal.h"
|
|
||||||
|
|
||||||
#define COUNTBRANCH(x) COUNTBRANCH_(x, #x, STRINGIFY(__FILE__), __LINE__)
|
#define COUNTBRANCH(x) COUNTBRANCH_(x, #x, STRINGIFY(__FILE__), __LINE__)
|
||||||
#define COUNTBRANCH_(x, xs, file, line) \
|
#define COUNTBRANCH_(x, xs, file, line) \
|
||||||
COUNTBRANCH__(x, STRINGIFY(xs), STRINGIFY(#x), file, line)
|
COUNTBRANCH__(x, STRINGIFY(xs), STRINGIFY(xs), file, line)
|
||||||
#define COUNTBRANCH__(x, xs, xss, file, line) \
|
#define COUNTBRANCH__(x, xs, xss, file, line) \
|
||||||
({ \
|
({ \
|
||||||
bool Cond; \
|
bool Cond; \
|
||||||
|
@ -46,7 +46,7 @@ struct countbranch {
|
||||||
const char *code;
|
const char *code;
|
||||||
const char *xcode;
|
const char *xcode;
|
||||||
const char *file;
|
const char *file;
|
||||||
int line;
|
long line;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct countbranch countbranch_data[];
|
extern struct countbranch countbranch_data[];
|
||||||
|
|
|
@ -18,8 +18,10 @@
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/alg/alg.h"
|
#include "libc/alg/alg.h"
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
|
#include "libc/intrin/kprintf.h"
|
||||||
#include "libc/log/countbranch.h"
|
#include "libc/log/countbranch.h"
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
|
#include "libc/math.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
#include "libc/stdio/stdio.h"
|
#include "libc/stdio/stdio.h"
|
||||||
|
|
||||||
|
@ -35,7 +37,7 @@ static double GetPercent(const struct countbranch *p) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static double RankCounter(const struct countbranch *p) {
|
static int RankCounter(const struct countbranch *p) {
|
||||||
double x;
|
double x;
|
||||||
x = GetPercent(p);
|
x = GetPercent(p);
|
||||||
x = MIN(x, 100 - x);
|
x = MIN(x, 100 - x);
|
||||||
|
@ -65,18 +67,28 @@ static void SortCounters(size_t n) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void countbranch_report(void) {
|
void countbranch_report(void) {
|
||||||
|
double r;
|
||||||
size_t i, n;
|
size_t i, n;
|
||||||
|
int pct, nines;
|
||||||
struct countbranch *p;
|
struct countbranch *p;
|
||||||
n = CountCounters();
|
n = CountCounters();
|
||||||
SortCounters(n);
|
SortCounters(n);
|
||||||
for (i = n; i--;) {
|
for (i = n; i--;) {
|
||||||
p = countbranch_data + i;
|
p = countbranch_data + i;
|
||||||
if (strcmp(p->code, p->xcode)) {
|
if (p->total) {
|
||||||
dprintf(2, "%s:%d: %g%% taken (%,ld/%,ld) %s [%s]\n", p->file, p->line,
|
r = (double)p->taken / p->total;
|
||||||
GetPercent(p), p->taken, p->total, p->code, p->xcode);
|
pct = floor(r * 100);
|
||||||
|
nines = floor(fmod(r * 100, 1) * 100000);
|
||||||
} else {
|
} else {
|
||||||
dprintf(2, "%s:%d: %g%% taken (%,ld/%,ld) %s\n", p->file, p->line,
|
pct = 0;
|
||||||
GetPercent(p), p->taken, p->total, p->code);
|
nines = 0;
|
||||||
|
}
|
||||||
|
if (strcmp(p->code, p->xcode)) {
|
||||||
|
kprintf("%s:%-4d: %3d.%05d%% taken (%'ld/%'ld) %s [%s]\n", p->file,
|
||||||
|
p->line, pct, nines, p->taken, p->total, p->code, p->xcode);
|
||||||
|
} else {
|
||||||
|
kprintf("%s:%-4d: %3d.%05d%% taken (%'ld/%'ld) %s\n", p->file, p->line,
|
||||||
|
pct, nines, p->taken, p->total, p->code);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
85
libc/log/countexpr.h
Normal file
85
libc/log/countexpr.h
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
#ifndef COSMOPOLITAN_LIBC_LOG_COUNTEXPR_H_
|
||||||
|
#define COSMOPOLITAN_LIBC_LOG_COUNTEXPR_H_
|
||||||
|
#include "libc/macros.internal.h"
|
||||||
|
#include "libc/nexgen32e/bench.h"
|
||||||
|
#include "libc/nexgen32e/bsr.h"
|
||||||
|
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||||
|
COSMOPOLITAN_C_START_
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows nanosecond timings histogram for expr at exit().
|
||||||
|
*/
|
||||||
|
#define COUNTEXPR(expr) \
|
||||||
|
COUNTEXPR_(expr, #expr, STRINGIFY(__FILE__), __LINE__, rdtsc, rdtsc, \
|
||||||
|
"COUNTEXPR")
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Like COUNTEXPR() but can be used on function calls that return void.
|
||||||
|
*/
|
||||||
|
#define COUNTSTMT(stmt) \
|
||||||
|
(void)COUNTEXPR_((stmt, 0), #stmt, STRINGIFY(__FILE__), __LINE__, rdtsc, \
|
||||||
|
rdtsc, "COUNTSTMT")
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as COUNTEXPR() but uses Intel's expensive measurement technique.
|
||||||
|
*/
|
||||||
|
#define BENCHEXPR(expr) \
|
||||||
|
COUNTEXPR_(expr, #expr, STRINGIFY(__FILE__), __LINE__, __startbench, \
|
||||||
|
__endbench, "BENCHEXPR")
|
||||||
|
|
||||||
|
#define COUNTEXPR_(expr, code, file, line, start, stop, macro) \
|
||||||
|
COUNTEXPR__(expr, STRINGIFY(code), file, line, start, stop, STRINGIFY(macro))
|
||||||
|
|
||||||
|
#define COUNTEXPR__(expr, code, file, line, start, stop, macro) \
|
||||||
|
({ \
|
||||||
|
struct countexpr *InfO; \
|
||||||
|
uint64_t t1_, t2_, TiCkS, NaNoS; \
|
||||||
|
t1_ = start(); \
|
||||||
|
asm volatile("" ::: "memory"); \
|
||||||
|
autotype(expr) ReS = (expr); \
|
||||||
|
asm volatile("" ::: "memory"); \
|
||||||
|
t2_ = stop(); \
|
||||||
|
TiCkS = t2_ >= t1_ ? t2_ - t1_ : ~t1_ + t2_ + 1; \
|
||||||
|
asm(".section .rodata.str1.1,\"aMS\",@progbits,1\n\t" \
|
||||||
|
".align\t1\n" \
|
||||||
|
"31340:\t.asciz\t" file "\n\t" \
|
||||||
|
"31338:\t.asciz\t" code "\n" \
|
||||||
|
"31332:\t.asciz\t" macro "\n" \
|
||||||
|
".previous\n\t" \
|
||||||
|
".section .yoink\n\t" \
|
||||||
|
"nopl\tcountexpr_data(%%rip)\n\t" \
|
||||||
|
".previous\n\t" \
|
||||||
|
".section .sort.data.countexpr.2,\"a\",@progbits\n\t" \
|
||||||
|
".align\t8\n31337:\t" \
|
||||||
|
".quad\t" #line "\n\t" \
|
||||||
|
".quad\t31340b\n\t" \
|
||||||
|
".quad\t31338b\n\t" \
|
||||||
|
".quad\t31332b\n\t" \
|
||||||
|
".rept\t65\n\t" \
|
||||||
|
".quad\t0\n\t" \
|
||||||
|
".endr\n\t" \
|
||||||
|
".previous\n\t" \
|
||||||
|
"lea\t31337b(%%rip),%0" \
|
||||||
|
: "=r"(InfO)); \
|
||||||
|
/* approximation of round(x*.323018) which is usually */ \
|
||||||
|
/* the ratio, between x86 rdtsc ticks and nanoseconds */ \
|
||||||
|
NaNoS = (TiCkS * 338709) >> 20; \
|
||||||
|
++InfO->logos[NaNoS ? bsrl(NaNoS) + 1 : 0]; \
|
||||||
|
ReS; \
|
||||||
|
})
|
||||||
|
|
||||||
|
struct countexpr {
|
||||||
|
long line; /* zero for last entry */
|
||||||
|
const char *file;
|
||||||
|
const char *code;
|
||||||
|
const char *macro;
|
||||||
|
long logos[65];
|
||||||
|
};
|
||||||
|
|
||||||
|
extern struct countexpr countexpr_data[];
|
||||||
|
|
||||||
|
void countexpr_report(void);
|
||||||
|
|
||||||
|
COSMOPOLITAN_C_END_
|
||||||
|
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||||
|
#endif /* COSMOPOLITAN_LIBC_LOG_COUNTEXPR_H_ */
|
33
libc/log/countexpr_data.S
Normal file
33
libc/log/countexpr_data.S
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
|
||||||
|
│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│
|
||||||
|
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||||
|
│ Copyright 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/macros.internal.h"
|
||||||
|
#include "libc/notice.inc"
|
||||||
|
|
||||||
|
.yoink countexpr_report
|
||||||
|
|
||||||
|
.section .sort.data.countexpr.1,"a",@progbits
|
||||||
|
.align 8
|
||||||
|
.globl countexpr_data
|
||||||
|
countexpr_data:
|
||||||
|
.previous
|
||||||
|
|
||||||
|
.section .sort.data.countexpr.3,"a",@progbits
|
||||||
|
.align 8
|
||||||
|
.quad 0
|
||||||
|
.previous
|
82
libc/log/countexpr_report.c
Normal file
82
libc/log/countexpr_report.c
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
/*-*- 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/alg/alg.h"
|
||||||
|
#include "libc/assert.h"
|
||||||
|
#include "libc/calls/calls.h"
|
||||||
|
#include "libc/intrin/kprintf.h"
|
||||||
|
#include "libc/limits.h"
|
||||||
|
#include "libc/log/countexpr.h"
|
||||||
|
#include "libc/macros.internal.h"
|
||||||
|
#include "libc/runtime/runtime.h"
|
||||||
|
#include "libc/stdio/stdio.h"
|
||||||
|
|
||||||
|
static long GetLongSum(const long *h, size_t n) {
|
||||||
|
long t;
|
||||||
|
size_t i;
|
||||||
|
for (t = i = 0; i < n; ++i) {
|
||||||
|
if (__builtin_add_overflow(t, h[i], &t)) {
|
||||||
|
t = LONG_MAX;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t GetRowCount(const long *h, size_t n) {
|
||||||
|
while (n && !h[n - 1]) --n;
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void PrintHistogram(const long *h, size_t n, long t) {
|
||||||
|
size_t i;
|
||||||
|
long j, p;
|
||||||
|
char s[101];
|
||||||
|
unsigned long logos;
|
||||||
|
for (i = 0; i < n; ++i) {
|
||||||
|
p = (h[i] * 10000 + (t >> 1)) / t;
|
||||||
|
assert(0 <= p && p <= 10000);
|
||||||
|
if (p) {
|
||||||
|
for (j = 0; j < p / 100; ++j) s[j] = '#';
|
||||||
|
s[j] = 0;
|
||||||
|
logos = i ? 1ul << (i - 1) : 0;
|
||||||
|
kprintf("%'12lu %'16ld %3d.%02d%% %s%n", logos, h[i], p / 100, p % 100,
|
||||||
|
s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void countexpr_report(void) {
|
||||||
|
long hits;
|
||||||
|
struct countexpr *p;
|
||||||
|
for (p = countexpr_data; p->line; ++p) {
|
||||||
|
if ((hits = GetLongSum(p->logos, 64))) {
|
||||||
|
kprintf("%s:%d: %s(%s) %'ld hits\n", p->file, p->line, p->macro, p->code,
|
||||||
|
hits);
|
||||||
|
PrintHistogram(p->logos, 64, hits);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static textstartup void countexpr_init() {
|
||||||
|
atexit(countexpr_report);
|
||||||
|
}
|
||||||
|
|
||||||
|
const void *const countexpr_ctor[] initarray = {
|
||||||
|
countexpr_init,
|
||||||
|
};
|
|
@ -25,12 +25,8 @@
|
||||||
* @return symbol table, or NULL w/ errno on first call
|
* @return symbol table, or NULL w/ errno on first call
|
||||||
*/
|
*/
|
||||||
noasan struct SymbolTable *GetSymbolTable(void) {
|
noasan struct SymbolTable *GetSymbolTable(void) {
|
||||||
/* asan runtime depends on this function */
|
|
||||||
static bool once;
|
|
||||||
static struct SymbolTable *singleton;
|
static struct SymbolTable *singleton;
|
||||||
const char *debugbin;
|
if (!singleton) {
|
||||||
if (!once) {
|
|
||||||
once = true;
|
|
||||||
++g_ftrace;
|
++g_ftrace;
|
||||||
singleton = OpenSymbolTable(FindDebugBinary());
|
singleton = OpenSymbolTable(FindDebugBinary());
|
||||||
--g_ftrace;
|
--g_ftrace;
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/calls/termios.h"
|
#include "libc/calls/termios.h"
|
||||||
#include "libc/fmt/conv.h"
|
#include "libc/fmt/conv.h"
|
||||||
|
#include "libc/log/internal.h"
|
||||||
#include "libc/log/log.h"
|
#include "libc/log/log.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
#include "libc/sysv/consts/termios.h"
|
#include "libc/sysv/consts/termios.h"
|
||||||
|
@ -34,7 +35,7 @@
|
||||||
* @returns -1 on error or something else on success
|
* @returns -1 on error or something else on success
|
||||||
*/
|
*/
|
||||||
int getttysize(int fd, struct winsize *out) {
|
int getttysize(int fd, struct winsize *out) {
|
||||||
if (IsTerminalInarticulate()) {
|
if (__nocolor) {
|
||||||
out->ws_col = strtoimax(firstnonnull(getenv("COLUMNS"), "80"), NULL, 0);
|
out->ws_col = strtoimax(firstnonnull(getenv("COLUMNS"), "80"), NULL, 0);
|
||||||
out->ws_row = strtoimax(firstnonnull(getenv("ROWS"), "40"), NULL, 0);
|
out->ws_row = strtoimax(firstnonnull(getenv("ROWS"), "40"), NULL, 0);
|
||||||
out->ws_xpixel = 0;
|
out->ws_xpixel = 0;
|
||||||
|
|
|
@ -7,9 +7,9 @@
|
||||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||||
COSMOPOLITAN_C_START_
|
COSMOPOLITAN_C_START_
|
||||||
|
|
||||||
|
extern hidden bool __nocolor;
|
||||||
extern hidden int kCrashSigs[7];
|
extern hidden int kCrashSigs[7];
|
||||||
extern hidden bool g_isrunningundermake;
|
extern hidden bool g_isrunningundermake;
|
||||||
extern hidden bool g_isterminalinarticulate;
|
|
||||||
extern hidden struct termios g_oldtermios;
|
extern hidden struct termios g_oldtermios;
|
||||||
extern hidden struct sigaction g_oldcrashacts[7];
|
extern hidden struct sigaction g_oldcrashacts[7];
|
||||||
|
|
||||||
|
|
|
@ -69,10 +69,10 @@ static noasan bool HasLeaks(void) {
|
||||||
* services that depend on malloc() cannot be used, after calling this
|
* services that depend on malloc() cannot be used, after calling this
|
||||||
* function.
|
* function.
|
||||||
*/
|
*/
|
||||||
noasan void testlib_checkformemoryleaks(void) {
|
noasan void CheckForMemoryLeaks(void) {
|
||||||
struct mallinfo mi;
|
struct mallinfo mi;
|
||||||
if (!cmpxchg(&once, false, true)) {
|
if (!cmpxchg(&once, false, true)) {
|
||||||
kprintf("testlib_checkformemoryleaks() may only be called once\n");
|
kprintf("CheckForMemoryLeaks() may only be called once\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
__cxa_finalize(0);
|
__cxa_finalize(0);
|
|
@ -11,6 +11,8 @@
|
||||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||||
COSMOPOLITAN_C_START_
|
COSMOPOLITAN_C_START_
|
||||||
|
|
||||||
|
#define __ToUpper(c) ((c) >= 'a' && (c) <= 'z' ? (c) - 'a' + 'A' : (c))
|
||||||
|
|
||||||
extern char __fatalbuf[];
|
extern char __fatalbuf[];
|
||||||
|
|
||||||
forceinline long __sysv_exit(long rc) {
|
forceinline long __sysv_exit(long rc) {
|
||||||
|
@ -113,8 +115,6 @@ forceinline int __getpid(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
forceinline ssize_t __write(const void *p, size_t n) {
|
forceinline ssize_t __write(const void *p, size_t n) {
|
||||||
char cf;
|
|
||||||
ssize_t rc;
|
|
||||||
uint32_t wrote;
|
uint32_t wrote;
|
||||||
if (!IsWindows()) {
|
if (!IsWindows()) {
|
||||||
return __sysv_write(2, p, n);
|
return __sysv_write(2, p, n);
|
||||||
|
@ -157,25 +157,23 @@ forceinline void *__repstosb(void *di, char al, size_t cx) {
|
||||||
: "0"(di), "1"(cx), "a"(al));
|
: "0"(di), "1"(cx), "a"(al));
|
||||||
return di;
|
return di;
|
||||||
#else
|
#else
|
||||||
size_t i;
|
|
||||||
volatile char *volatile d = di;
|
volatile char *volatile d = di;
|
||||||
while (cx--) *d++ = al;
|
while (cx--) *d++ = al;
|
||||||
return d;
|
return (void *)d;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
forceinline void *__repmovsb(void *di, void *si, size_t cx) {
|
forceinline void *__repmovsb(void *di, const void *si, size_t cx) {
|
||||||
#if defined(__x86__) && defined(__GNUC__) && !defined(__STRICT_ANSI__)
|
#if defined(__x86__) && defined(__GNUC__) && !defined(__STRICT_ANSI__)
|
||||||
asm("rep movsb"
|
asm("rep movsb"
|
||||||
: "=D"(di), "=S"(si), "=c"(cx), "=m"(*(char(*)[cx])di)
|
: "=D"(di), "=S"(si), "=c"(cx), "=m"(*(char(*)[cx])di)
|
||||||
: "0"(di), "1"(si), "2"(cx), "m"(*(char(*)[cx])si));
|
: "0"(di), "1"(si), "2"(cx), "m"(*(char(*)[cx])si));
|
||||||
return di;
|
return di;
|
||||||
#else
|
#else
|
||||||
size_t i;
|
|
||||||
volatile char *volatile d = di;
|
volatile char *volatile d = di;
|
||||||
volatile char *volatile s = si;
|
volatile char *volatile s = si;
|
||||||
while (cx--) *d++ = *s++;
|
while (cx--) *d++ = *s++;
|
||||||
return d;
|
return (void *)d;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -244,24 +242,12 @@ forceinline char *__strstr(const char *haystack, const char *needle) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
forceinline char *__getenv(char **p, const char *s) {
|
forceinline const char *__strchr(const char *s, unsigned char c) {
|
||||||
size_t i, j;
|
char *r;
|
||||||
if (p) {
|
for (;; ++s) {
|
||||||
for (i = 0; p[i]; ++i) {
|
if ((*s & 255) == c) return s;
|
||||||
for (j = 0;; ++j) {
|
if (!*s) return 0;
|
||||||
if (!s[j]) {
|
|
||||||
if (p[i][j] == '=') {
|
|
||||||
return p[i] + j + 1;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (s[j] != p[i][j]) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
forceinline unsigned long __atoul(const char *p) {
|
forceinline unsigned long __atoul(const char *p) {
|
||||||
|
|
|
@ -58,6 +58,7 @@ void AppendResourceReport(char **, struct rusage *, const char *);
|
||||||
char *__get_symbol_by_addr(int64_t);
|
char *__get_symbol_by_addr(int64_t);
|
||||||
void PrintGarbage(void);
|
void PrintGarbage(void);
|
||||||
void PrintGarbageNumeric(FILE *);
|
void PrintGarbageNumeric(FILE *);
|
||||||
|
void CheckForMemoryLeaks(void);
|
||||||
|
|
||||||
#define showcrashreports() ShowCrashReports()
|
#define showcrashreports() ShowCrashReports()
|
||||||
|
|
||||||
|
|
|
@ -63,6 +63,10 @@ o/$(MODE)/libc/log/backtrace3.o: \
|
||||||
OVERRIDE_CFLAGS += \
|
OVERRIDE_CFLAGS += \
|
||||||
-fno-sanitize=all
|
-fno-sanitize=all
|
||||||
|
|
||||||
|
o/$(MODE)/libc/log/checkfail.o: \
|
||||||
|
OVERRIDE_CFLAGS += \
|
||||||
|
-mgeneral-regs-only
|
||||||
|
|
||||||
o/$(MODE)/libc/log/attachdebugger.o \
|
o/$(MODE)/libc/log/attachdebugger.o \
|
||||||
o/$(MODE)/libc/log/backtrace2.o \
|
o/$(MODE)/libc/log/backtrace2.o \
|
||||||
o/$(MODE)/libc/log/backtrace3.o \
|
o/$(MODE)/libc/log/backtrace3.o \
|
||||||
|
@ -70,7 +74,6 @@ o/$(MODE)/libc/log/checkaligned.o \
|
||||||
o/$(MODE)/libc/log/checkfail.o \
|
o/$(MODE)/libc/log/checkfail.o \
|
||||||
o/$(MODE)/libc/log/checkfail_ndebug.o \
|
o/$(MODE)/libc/log/checkfail_ndebug.o \
|
||||||
o/$(MODE)/libc/log/getsymboltable.o \
|
o/$(MODE)/libc/log/getsymboltable.o \
|
||||||
o/$(MODE)/libc/log/cancolor.o \
|
|
||||||
o/$(MODE)/libc/log/restoretty.o \
|
o/$(MODE)/libc/log/restoretty.o \
|
||||||
o/$(MODE)/libc/log/oncrash.o \
|
o/$(MODE)/libc/log/oncrash.o \
|
||||||
o/$(MODE)/libc/log/onkill.o \
|
o/$(MODE)/libc/log/onkill.o \
|
||||||
|
|
|
@ -18,50 +18,27 @@
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/bits/bits.h"
|
#include "libc/bits/bits.h"
|
||||||
#include "libc/bits/weaken.h"
|
#include "libc/bits/weaken.h"
|
||||||
#include "libc/calls/calls.h"
|
|
||||||
#include "libc/calls/internal.h"
|
#include "libc/calls/internal.h"
|
||||||
#include "libc/calls/sigbits.h"
|
#include "libc/calls/sigbits.h"
|
||||||
#include "libc/calls/struct/sigaction.h"
|
#include "libc/calls/struct/sigaction.h"
|
||||||
#include "libc/calls/struct/siginfo.h"
|
|
||||||
#include "libc/calls/struct/termios.h"
|
|
||||||
#include "libc/calls/struct/utsname.h"
|
|
||||||
#include "libc/calls/termios.h"
|
|
||||||
#include "libc/calls/ucontext.h"
|
|
||||||
#include "libc/dce.h"
|
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
#include "libc/fmt/fmt.h"
|
|
||||||
#include "libc/intrin/asan.internal.h"
|
#include "libc/intrin/asan.internal.h"
|
||||||
#include "libc/intrin/kprintf.h"
|
#include "libc/intrin/kprintf.h"
|
||||||
#include "libc/log/backtrace.internal.h"
|
#include "libc/log/backtrace.internal.h"
|
||||||
#include "libc/log/color.internal.h"
|
|
||||||
#include "libc/log/gdb.h"
|
#include "libc/log/gdb.h"
|
||||||
#include "libc/log/internal.h"
|
#include "libc/log/internal.h"
|
||||||
#include "libc/log/libfatal.internal.h"
|
#include "libc/log/libfatal.internal.h"
|
||||||
#include "libc/log/log.h"
|
#include "libc/log/log.h"
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
#include "libc/nexgen32e/bsr.h"
|
|
||||||
#include "libc/nexgen32e/stackframe.h"
|
#include "libc/nexgen32e/stackframe.h"
|
||||||
#include "libc/nt/process.h"
|
|
||||||
#include "libc/nt/runtime.h"
|
|
||||||
#include "libc/runtime/internal.h"
|
|
||||||
#include "libc/runtime/memtrack.internal.h"
|
|
||||||
#include "libc/runtime/pc.internal.h"
|
#include "libc/runtime/pc.internal.h"
|
||||||
#include "libc/runtime/runtime.h"
|
|
||||||
#include "libc/runtime/stack.h"
|
|
||||||
#include "libc/str/str.h"
|
|
||||||
#include "libc/sysv/consts/auxv.h"
|
|
||||||
#include "libc/sysv/consts/fileno.h"
|
|
||||||
#include "libc/sysv/consts/nr.h"
|
|
||||||
#include "libc/sysv/consts/o.h"
|
|
||||||
#include "libc/sysv/consts/sig.h"
|
|
||||||
#include "libc/sysv/consts/termios.h"
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @fileoverview Abnormal termination handling & GUI debugging.
|
* @fileoverview Abnormal termination handling & GUI debugging.
|
||||||
* @see libc/onkill.c
|
* @see libc/onkill.c
|
||||||
*/
|
*/
|
||||||
|
|
||||||
STATIC_YOINK("strerror_r");
|
STATIC_YOINK("strerror_r"); /* for kprintf %m */
|
||||||
|
|
||||||
static const char kGregOrder[17] forcealign(1) = {
|
static const char kGregOrder[17] forcealign(1) = {
|
||||||
13, 11, 8, 14, 12, 9, 10, 15, 16, 0, 1, 2, 3, 4, 5, 6, 7,
|
13, 11, 8, 14, 12, 9, 10, 15, 16, 0, 1, 2, 3, 4, 5, 6, 7,
|
||||||
|
@ -89,7 +66,7 @@ static const char kCrashSigNames[7][5] forcealign(1) = {
|
||||||
};
|
};
|
||||||
/* </SYNC-LIST>: showcrashreports.c, oncrashthunks.S, oncrash.c */
|
/* </SYNC-LIST>: showcrashreports.c, oncrashthunks.S, oncrash.c */
|
||||||
|
|
||||||
static relegated noasan noinstrument const char *TinyStrSignal(int sig) {
|
static relegated noinstrument const char *TinyStrSignal(int sig) {
|
||||||
size_t i;
|
size_t i;
|
||||||
for (i = 0; i < ARRAYLEN(kCrashSigs); ++i) {
|
for (i = 0; i < ARRAYLEN(kCrashSigs); ++i) {
|
||||||
if (kCrashSigs[i] && sig == kCrashSigs[i]) {
|
if (kCrashSigs[i] && sig == kCrashSigs[i]) {
|
||||||
|
@ -111,7 +88,6 @@ relegated static void ShowFunctionCalls(ucontext_t *ctx) {
|
||||||
goodframe.addr = ctx->uc_mcontext.rip;
|
goodframe.addr = ctx->uc_mcontext.rip;
|
||||||
bp = &goodframe;
|
bp = &goodframe;
|
||||||
ShowBacktrace(2, bp);
|
ShowBacktrace(2, bp);
|
||||||
kprintf("%n");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,7 +133,7 @@ relegated static void ShowGeneralRegisters(ucontext_t *ctx) {
|
||||||
long double st;
|
long double st;
|
||||||
char *p, buf[128];
|
char *p, buf[128];
|
||||||
p = buf;
|
p = buf;
|
||||||
printf("%n");
|
kprintf("%n");
|
||||||
for (i = 0, j = 0, k = 0; i < ARRAYLEN(kGregNames); ++i) {
|
for (i = 0, j = 0, k = 0; i < ARRAYLEN(kGregNames); ++i) {
|
||||||
if (j > 0) *p++ = ' ';
|
if (j > 0) *p++ = ' ';
|
||||||
if (!(s = kGregNames[(unsigned)kGregOrder[i]])[2]) *p++ = ' ';
|
if (!(s = kGregNames[(unsigned)kGregOrder[i]])[2]) *p++ = ' ';
|
||||||
|
@ -248,8 +224,8 @@ relegated void ShowCrashReport(int err, int sig, struct siginfo *si,
|
||||||
" %s%n"
|
" %s%n"
|
||||||
" %m%n"
|
" %m%n"
|
||||||
" %s %s %s %s%n",
|
" %s %s %s %s%n",
|
||||||
!g_isterminalinarticulate ? "\e[30;101m" : "",
|
!__nocolor ? "\e[30;101m" : "", !__nocolor ? "\e[0m" : "",
|
||||||
!g_isterminalinarticulate ? "\e[0m" : "", TinyStrSignal(sig),
|
TinyStrSignal(sig),
|
||||||
(ctx && (ctx->uc_mcontext.rsp >= GetStaticStackAddr(0) &&
|
(ctx && (ctx->uc_mcontext.rsp >= GetStaticStackAddr(0) &&
|
||||||
ctx->uc_mcontext.rsp <= GetStaticStackAddr(0) + PAGESIZE))
|
ctx->uc_mcontext.rsp <= GetStaticStackAddr(0) + PAGESIZE))
|
||||||
? "Stack Overflow"
|
? "Stack Overflow"
|
||||||
|
@ -285,8 +261,10 @@ relegated static void RestoreDefaultCrashSignalHandlers(void) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static wontreturn noasan relegated noinstrument void __minicrash(
|
static wontreturn relegated noinstrument void __minicrash(int sig,
|
||||||
int sig, struct siginfo *si, ucontext_t *ctx, const char *kind) {
|
struct siginfo *si,
|
||||||
|
ucontext_t *ctx,
|
||||||
|
const char *kind) {
|
||||||
kprintf("%n"
|
kprintf("%n"
|
||||||
"%n"
|
"%n"
|
||||||
"CRASHED %s WITH SIG%s%n"
|
"CRASHED %s WITH SIG%s%n"
|
||||||
|
@ -313,8 +291,8 @@ static wontreturn noasan relegated noinstrument void __minicrash(
|
||||||
*
|
*
|
||||||
* This function never returns, except for traps w/ human supervision.
|
* This function never returns, except for traps w/ human supervision.
|
||||||
*/
|
*/
|
||||||
noasan relegated noinstrument void __oncrash(int sig, struct siginfo *si,
|
relegated noinstrument void __oncrash(int sig, struct siginfo *si,
|
||||||
ucontext_t *ctx) {
|
ucontext_t *ctx) {
|
||||||
intptr_t rip;
|
intptr_t rip;
|
||||||
int gdbpid, err;
|
int gdbpid, err;
|
||||||
static bool noreentry, notpossible;
|
static bool noreentry, notpossible;
|
||||||
|
@ -325,7 +303,7 @@ noasan relegated noinstrument void __oncrash(int sig, struct siginfo *si,
|
||||||
err = errno;
|
err = errno;
|
||||||
if ((gdbpid = IsDebuggerPresent(true))) {
|
if ((gdbpid = IsDebuggerPresent(true))) {
|
||||||
DebugBreak();
|
DebugBreak();
|
||||||
} else if (g_isterminalinarticulate || g_isrunningundermake) {
|
} else if (__nocolor || g_isrunningundermake) {
|
||||||
gdbpid = -1;
|
gdbpid = -1;
|
||||||
} else if (IsLinux() && FindDebugBinary()) {
|
} else if (IsLinux() && FindDebugBinary()) {
|
||||||
RestoreDefaultCrashSignalHandlers();
|
RestoreDefaultCrashSignalHandlers();
|
||||||
|
|
|
@ -17,13 +17,19 @@
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
|
#include "libc/calls/struct/termios.h"
|
||||||
#include "libc/calls/termios.h"
|
#include "libc/calls/termios.h"
|
||||||
#include "libc/dce.h"
|
#include "libc/errno.h"
|
||||||
#include "libc/log/color.internal.h"
|
#include "libc/log/color.internal.h"
|
||||||
#include "libc/log/internal.h"
|
#include "libc/log/internal.h"
|
||||||
#include "libc/nt/runtime.h"
|
#include "libc/sysv/consts/termios.h"
|
||||||
#include "libc/str/str.h"
|
|
||||||
#include "libc/sysv/consts/nr.h"
|
/**
|
||||||
|
* @fileoverview Terminal Restoration Helper
|
||||||
|
*
|
||||||
|
* This is used by the crash reporting functions, e.g. __die(), to help
|
||||||
|
* ensure the terminal is in an unborked state after a crash happens.
|
||||||
|
*/
|
||||||
|
|
||||||
#define RESET_COLOR "\e[0m"
|
#define RESET_COLOR "\e[0m"
|
||||||
#define SHOW_CURSOR "\e[?25h"
|
#define SHOW_CURSOR "\e[?25h"
|
||||||
|
@ -32,13 +38,10 @@
|
||||||
|
|
||||||
struct termios g_oldtermios;
|
struct termios g_oldtermios;
|
||||||
|
|
||||||
asm(".section .privileged,\"ax\",@progbits\n__syscall:\n\t"
|
|
||||||
"syscall\n\t"
|
|
||||||
"ret\n\t"
|
|
||||||
".previous");
|
|
||||||
|
|
||||||
static textstartup void g_oldtermios_init() {
|
static textstartup void g_oldtermios_init() {
|
||||||
|
int e = errno;
|
||||||
tcgetattr(1, &g_oldtermios);
|
tcgetattr(1, &g_oldtermios);
|
||||||
|
errno = e;
|
||||||
}
|
}
|
||||||
|
|
||||||
const void *const g_oldtermios_ctor[] initarray = {
|
const void *const g_oldtermios_ctor[] initarray = {
|
||||||
|
@ -46,7 +49,7 @@ const void *const g_oldtermios_ctor[] initarray = {
|
||||||
};
|
};
|
||||||
|
|
||||||
void __restore_tty(int fd) {
|
void __restore_tty(int fd) {
|
||||||
if (g_oldtermios.c_lflag && isatty(fd) && cancolor()) {
|
if (g_oldtermios.c_lflag && !__nocolor && isatty(fd)) {
|
||||||
write(fd, ANSI_RESTORE, strlen(ANSI_RESTORE));
|
write(fd, ANSI_RESTORE, strlen(ANSI_RESTORE));
|
||||||
tcsetattr(fd, TCSAFLUSH, &g_oldtermios);
|
tcsetattr(fd, TCSAFLUSH, &g_oldtermios);
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,7 +72,7 @@ void ShowCrashReports(void) {
|
||||||
for (i = 0; i < ARRAYLEN(kCrashSigs); ++i) {
|
for (i = 0; i < ARRAYLEN(kCrashSigs); ++i) {
|
||||||
sigdelset(&sa.sa_mask, kCrashSigs[i]);
|
sigdelset(&sa.sa_mask, kCrashSigs[i]);
|
||||||
}
|
}
|
||||||
sigaltstack(&ss, 0);
|
if (!IsWindows()) sigaltstack(&ss, 0);
|
||||||
for (i = 0; i < ARRAYLEN(kCrashSigs); ++i) {
|
for (i = 0; i < ARRAYLEN(kCrashSigs); ++i) {
|
||||||
if (kCrashSigs[i]) {
|
if (kCrashSigs[i]) {
|
||||||
sa.sa_sigaction = (sigaction_f)__oncrash_thunks[i];
|
sa.sa_sigaction = (sigaction_f)__oncrash_thunks[i];
|
||||||
|
|
|
@ -16,9 +16,9 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/intrin/kprintf.h"
|
||||||
#include "libc/log/color.internal.h"
|
#include "libc/log/color.internal.h"
|
||||||
#include "libc/log/internal.h"
|
#include "libc/log/internal.h"
|
||||||
#include "libc/log/libfatal.internal.h"
|
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -27,19 +27,8 @@
|
||||||
* @note this is support code for __check_fail(), __assert_fail(), etc.
|
* @note this is support code for __check_fail(), __assert_fail(), etc.
|
||||||
*/
|
*/
|
||||||
relegated void __start_fatal(const char *file, int line) {
|
relegated void __start_fatal(const char *file, int line) {
|
||||||
bool colorful;
|
|
||||||
char s[16 + 16 + 16 + 16 + PATH_MAX + 16 + NAME_MAX + 16], *p = s;
|
|
||||||
__restore_tty(1);
|
__restore_tty(1);
|
||||||
colorful = cancolor();
|
kprintf("\r%serror%s:%s:%d:%s%s: ", !__nocolor ? "\e[J\e[30;101m" : "",
|
||||||
*p++ = '\r';
|
!__nocolor ? "\e[94;49m" : "", file, line,
|
||||||
if (colorful) p = __stpcpy(p, "\e[J\e[30;101m");
|
program_invocation_short_name, !__nocolor ? "\e[0m" : "");
|
||||||
p = __stpcpy(p, "error");
|
|
||||||
if (colorful) p = __stpcpy(p, "\e[94;49m"), *p++ = ':';
|
|
||||||
p = __stpcpy(p, file), *p++ = ':';
|
|
||||||
p = __intcpy(p, line), *p++ = ':';
|
|
||||||
p = __stpcpy(p, program_invocation_short_name);
|
|
||||||
if (colorful) p = __stpcpy(p, "\e[0m");
|
|
||||||
*p++ = ':';
|
|
||||||
*p++ = ' ';
|
|
||||||
__write(s, p - s);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -192,3 +192,31 @@
|
||||||
#endif
|
#endif
|
||||||
.endif
|
.endif
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
|
.macro .poison name:req kind:req
|
||||||
|
#ifdef __FSANITIZE_ADDRESS__
|
||||||
|
2323: .quad 0
|
||||||
|
.init.start 304,"_init_\name\()_poison_\@"
|
||||||
|
push %rdi
|
||||||
|
push %rsi
|
||||||
|
ezlea 2323b,di
|
||||||
|
mov $8,%esi
|
||||||
|
mov $\kind,%edx
|
||||||
|
call __asan_poison
|
||||||
|
pop %rsi
|
||||||
|
pop %rdi
|
||||||
|
.init.end 304,"_init_\name\()_poison_\@"
|
||||||
|
#endif
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.macro .underrun
|
||||||
|
#ifdef __FSANITIZE_ADDRESS__
|
||||||
|
.poison __BASE_FILE__ kAsanGlobalUnderrun
|
||||||
|
#endif
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.macro .overrun
|
||||||
|
#ifdef __FSANITIZE_ADDRESS__
|
||||||
|
.poison __BASE_FILE__ kAsanGlobalUnderrun
|
||||||
|
#endif
|
||||||
|
.endm
|
||||||
|
|
|
@ -17,46 +17,63 @@
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/alg/alg.h"
|
#include "libc/alg/alg.h"
|
||||||
|
#include "libc/calls/sysdebug.internal.h"
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
|
#include "libc/macros.internal.h"
|
||||||
#include "libc/mem/internal.h"
|
#include "libc/mem/internal.h"
|
||||||
#include "libc/mem/mem.h"
|
#include "libc/mem/mem.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
#include "libc/sysv/errfuns.h"
|
#include "libc/sysv/errfuns.h"
|
||||||
|
|
||||||
#define MAX_VARS 512
|
|
||||||
|
|
||||||
#define ToUpper(c) ((c) >= 'a' && (c) <= 'z' ? (c) - 'a' + 'A' : (c))
|
#define ToUpper(c) ((c) >= 'a' && (c) <= 'z' ? (c) - 'a' + 'A' : (c))
|
||||||
|
|
||||||
static bool once;
|
static bool once;
|
||||||
|
static size_t capacity;
|
||||||
|
|
||||||
static void PutEnvDestroy(void) {
|
static size_t GetEnvironLen(char **env) {
|
||||||
|
char **p = env;
|
||||||
|
while (*p) ++p;
|
||||||
|
return p - env;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void RestoreOriginalEnvironment(char **envp) {
|
||||||
|
environ = envp;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void PutEnvImplAtExit(void *p) {
|
||||||
|
free(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void FreeEnviron(char **env) {
|
||||||
char **a;
|
char **a;
|
||||||
for (a = environ; *a; ++a) free(*a);
|
for (a = env; *a; ++a) {
|
||||||
free(environ);
|
free(*a);
|
||||||
}
|
|
||||||
|
|
||||||
static void PutEnvInit(void) {
|
|
||||||
char **pin, **pout;
|
|
||||||
pin = environ;
|
|
||||||
pout = malloc(sizeof(char *) * MAX_VARS);
|
|
||||||
environ = pout;
|
|
||||||
while (*pin) *pout++ = strdup(*pin++);
|
|
||||||
*pout = NULL;
|
|
||||||
atexit(PutEnvDestroy);
|
|
||||||
}
|
|
||||||
|
|
||||||
void __freeenv(void *p) {
|
|
||||||
if (once) {
|
|
||||||
free(p);
|
|
||||||
}
|
}
|
||||||
|
free(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void GrowEnviron(void) {
|
||||||
|
size_t n, c;
|
||||||
|
char **a, **b, **p;
|
||||||
|
a = environ;
|
||||||
|
n = GetEnvironLen(a);
|
||||||
|
c = MAX(16ul, n) << 1;
|
||||||
|
b = calloc(c, sizeof(char *));
|
||||||
|
for (p = b; *a;) {
|
||||||
|
*p++ = strdup(*a++);
|
||||||
|
}
|
||||||
|
__cxa_atexit(FreeEnviron, b, 0);
|
||||||
|
environ = b;
|
||||||
|
capacity = c;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PutEnvImpl(char *s, bool overwrite) {
|
int PutEnvImpl(char *s, bool overwrite) {
|
||||||
char *p;
|
char *p;
|
||||||
unsigned i, namelen;
|
unsigned i, namelen;
|
||||||
if (!once) {
|
if (!once) {
|
||||||
PutEnvInit();
|
__cxa_atexit(RestoreOriginalEnvironment, environ, 0);
|
||||||
|
GrowEnviron();
|
||||||
once = true;
|
once = true;
|
||||||
}
|
}
|
||||||
for (p = s; *p && *p != '='; ++p) {
|
for (p = s; *p && *p != '='; ++p) {
|
||||||
|
@ -64,7 +81,7 @@ int PutEnvImpl(char *s, bool overwrite) {
|
||||||
*p = ToUpper(*p);
|
*p = ToUpper(*p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (*p != '=') goto fail;
|
if (*p != '=') goto Fail;
|
||||||
namelen = p + 1 - s;
|
namelen = p + 1 - s;
|
||||||
for (i = 0; environ[i]; ++i) {
|
for (i = 0; environ[i]; ++i) {
|
||||||
if (!strncmp(environ[i], s, namelen)) {
|
if (!strncmp(environ[i], s, namelen)) {
|
||||||
|
@ -72,27 +89,38 @@ int PutEnvImpl(char *s, bool overwrite) {
|
||||||
free(s);
|
free(s);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
goto replace;
|
goto Replace;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (i + 1 >= MAX_VARS) {
|
if (i + 1 >= capacity) {
|
||||||
free(s);
|
GrowEnviron();
|
||||||
return enomem();
|
|
||||||
}
|
}
|
||||||
environ[i + 1] = NULL;
|
environ[i + 1] = 0;
|
||||||
replace:
|
Replace:
|
||||||
free(environ[i]);
|
__cxa_atexit(PutEnvImplAtExit, environ[i], 0);
|
||||||
environ[i] = s;
|
environ[i] = s;
|
||||||
return 0;
|
return 0;
|
||||||
fail:
|
Fail:
|
||||||
free(s);
|
free(s);
|
||||||
return einval();
|
return einval();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* weakly called by unsetenv() when removing a pointer */
|
||||||
|
void __freeenv(void *p) {
|
||||||
|
if (once) {
|
||||||
|
__cxa_atexit(free, p, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Emplaces environment key=value.
|
* Emplaces environment key=value.
|
||||||
|
*
|
||||||
|
* @return 0 on success or non-zero on error
|
||||||
* @see setenv(), getenv()
|
* @see setenv(), getenv()
|
||||||
*/
|
*/
|
||||||
int putenv(char *string) {
|
int putenv(char *s) {
|
||||||
return PutEnvImpl(strdup(string), true);
|
int rc;
|
||||||
|
rc = PutEnvImpl(strdup(s), true);
|
||||||
|
SYSDEBUG("putenv(%#s) → %d", s, rc);
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/calls/sysdebug.internal.h"
|
||||||
#include "libc/mem/internal.h"
|
#include "libc/mem/internal.h"
|
||||||
#include "libc/mem/mem.h"
|
#include "libc/mem/mem.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
|
@ -28,9 +29,14 @@
|
||||||
* @see putenv(), getenv()
|
* @see putenv(), getenv()
|
||||||
*/
|
*/
|
||||||
int setenv(const char *name, const char *value, int overwrite) {
|
int setenv(const char *name, const char *value, int overwrite) {
|
||||||
size_t namelen = strlen(name);
|
int rc;
|
||||||
size_t valuelen = strlen(value);
|
char *s;
|
||||||
char *s = malloc(namelen + valuelen + 2);
|
size_t namelen, valuelen;
|
||||||
|
namelen = strlen(name);
|
||||||
|
valuelen = strlen(value);
|
||||||
|
s = malloc(namelen + valuelen + 2);
|
||||||
memcpy(mempcpy(mempcpy(s, name, namelen), "=", 1), value, valuelen + 1);
|
memcpy(mempcpy(mempcpy(s, name, namelen), "=", 1), value, valuelen + 1);
|
||||||
return PutEnvImpl(s, overwrite);
|
rc = PutEnvImpl(s, overwrite);
|
||||||
|
SYSDEBUG("setenv(%#s, %#s, %d) → %d", name, value, overwrite, rc);
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,15 +17,40 @@
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/bits/bits.h"
|
#include "libc/bits/bits.h"
|
||||||
#include "libc/bits/safemacros.internal.h"
|
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/calls/sysdebug.internal.h"
|
|
||||||
#include "libc/errno.h"
|
|
||||||
#include "libc/macros.internal.h"
|
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
#include "libc/runtime/symbols.internal.h"
|
#include "libc/runtime/symbols.internal.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
#include "libc/sysv/consts/auxv.h"
|
|
||||||
|
static char *g_comdbg;
|
||||||
|
static char g_comdbg_buf[PATH_MAX + 1];
|
||||||
|
|
||||||
|
static optimizesize textstartup void g_comdbg_init() {
|
||||||
|
char *p;
|
||||||
|
size_t n;
|
||||||
|
static bool once;
|
||||||
|
if (!once) {
|
||||||
|
if (!(g_comdbg = getenv("COMDBG"))) {
|
||||||
|
p = program_executable_name;
|
||||||
|
n = strlen(p);
|
||||||
|
if (n > 4 && READ32LE(p + n - 4) == READ32LE(".dbg")) {
|
||||||
|
g_comdbg = p;
|
||||||
|
} else if (n > 4 && READ32LE(p + n - 4) == READ32LE(".com") &&
|
||||||
|
n + 4 <= PATH_MAX) {
|
||||||
|
mempcpy(mempcpy(g_comdbg_buf, p, n), ".dbg", 5);
|
||||||
|
if (fileexists(g_comdbg_buf)) {
|
||||||
|
g_comdbg = g_comdbg_buf;
|
||||||
|
}
|
||||||
|
} else if (n + 8 <= PATH_MAX) {
|
||||||
|
mempcpy(mempcpy(g_comdbg_buf, p, n), ".com.dbg", 9);
|
||||||
|
if (fileexists(g_comdbg_buf)) {
|
||||||
|
g_comdbg = g_comdbg_buf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
once = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns path of binary with the debug information, or null.
|
* Returns path of binary with the debug information, or null.
|
||||||
|
@ -33,31 +58,10 @@
|
||||||
* @return path to debug binary, or NULL
|
* @return path to debug binary, or NULL
|
||||||
*/
|
*/
|
||||||
const char *FindDebugBinary(void) {
|
const char *FindDebugBinary(void) {
|
||||||
static bool once;
|
g_comdbg_init();
|
||||||
static char *res;
|
return g_comdbg;
|
||||||
static char buf[PATH_MAX + 1];
|
|
||||||
char *p;
|
|
||||||
size_t n;
|
|
||||||
if (!once) {
|
|
||||||
if (!(res = getenv("COMDBG"))) {
|
|
||||||
p = program_executable_name;
|
|
||||||
n = strlen(p);
|
|
||||||
if (n > 4 && READ32LE(p + n - 4) == READ32LE(".dbg")) {
|
|
||||||
res = p;
|
|
||||||
} else if (n > 4 && READ32LE(p + n - 4) == READ32LE(".com") &&
|
|
||||||
n + 4 <= PATH_MAX) {
|
|
||||||
mempcpy(mempcpy(buf, p, n), ".dbg", 5);
|
|
||||||
if (fileexists(buf)) {
|
|
||||||
res = buf;
|
|
||||||
}
|
|
||||||
} else if (n + 8 <= PATH_MAX) {
|
|
||||||
mempcpy(mempcpy(buf, p, n), ".com.dbg", 9);
|
|
||||||
if (fileexists(buf)) {
|
|
||||||
res = buf;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
once = true;
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const void *const g_comdbg_ctor[] initarray = {
|
||||||
|
g_comdbg_init,
|
||||||
|
};
|
||||||
|
|
|
@ -61,6 +61,10 @@ static optimizesize noasan void longsort_pure(long *x, size_t n, size_t t) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sorting algorithm for longs that doesn't take long.
|
* Sorting algorithm for longs that doesn't take long.
|
||||||
|
*
|
||||||
|
* "What disorder is this? Give me my long sort!"
|
||||||
|
* -Lord Capulet
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
void longsort(long *x, size_t n) {
|
void longsort(long *x, size_t n) {
|
||||||
size_t t, m;
|
size_t t, m;
|
||||||
|
|
|
@ -352,7 +352,6 @@ void thrashcodecache(void);
|
||||||
void testlib_finish(void);
|
void testlib_finish(void);
|
||||||
void testlib_runalltests(void);
|
void testlib_runalltests(void);
|
||||||
void testlib_runallbenchmarks(void);
|
void testlib_runallbenchmarks(void);
|
||||||
void testlib_checkformemoryleaks(void);
|
|
||||||
void testlib_runtestcases(testfn_t *, testfn_t *, testfn_t);
|
void testlib_runtestcases(testfn_t *, testfn_t *, testfn_t);
|
||||||
void testlib_runcombos(testfn_t *, testfn_t *, const struct TestFixture *,
|
void testlib_runcombos(testfn_t *, testfn_t *, const struct TestFixture *,
|
||||||
const struct TestFixture *);
|
const struct TestFixture *);
|
||||||
|
|
|
@ -59,7 +59,6 @@ LIBC_TESTLIB_A_SRCS_C = \
|
||||||
libc/testlib/comborunner.c \
|
libc/testlib/comborunner.c \
|
||||||
libc/testlib/contains.c \
|
libc/testlib/contains.c \
|
||||||
libc/testlib/endswith.c \
|
libc/testlib/endswith.c \
|
||||||
libc/testlib/leaks.c \
|
|
||||||
libc/testlib/yield.c \
|
libc/testlib/yield.c \
|
||||||
libc/testlib/ezbenchcontrol.c \
|
libc/testlib/ezbenchcontrol.c \
|
||||||
libc/testlib/ezbenchreport.c \
|
libc/testlib/ezbenchreport.c \
|
||||||
|
|
|
@ -95,13 +95,13 @@ noasan int main(int argc, char *argv[]) {
|
||||||
if (!g_testlib_failed && runbenchmarks_ && weaken(testlib_runallbenchmarks)) {
|
if (!g_testlib_failed && runbenchmarks_ && weaken(testlib_runallbenchmarks)) {
|
||||||
weaken(testlib_runallbenchmarks)();
|
weaken(testlib_runallbenchmarks)();
|
||||||
if (!g_testlib_failed) {
|
if (!g_testlib_failed) {
|
||||||
testlib_checkformemoryleaks();
|
CheckForMemoryLeaks();
|
||||||
}
|
}
|
||||||
if (!g_testlib_failed && IsRunningUnderMake()) {
|
if (!g_testlib_failed && IsRunningUnderMake()) {
|
||||||
return 254; /* compile.com considers this 0 and propagates output */
|
return 254; /* compile.com considers this 0 and propagates output */
|
||||||
}
|
}
|
||||||
} else if (!g_testlib_failed) {
|
} else if (!g_testlib_failed) {
|
||||||
testlib_checkformemoryleaks();
|
CheckForMemoryLeaks();
|
||||||
}
|
}
|
||||||
exit(min(255, g_testlib_failed));
|
exit(min(255, g_testlib_failed));
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,26 +32,40 @@
|
||||||
|
|
||||||
STATIC_YOINK("ssl_root_support");
|
STATIC_YOINK("ssl_root_support");
|
||||||
|
|
||||||
|
static void FreeSslRoots(mbedtls_x509_crt *c) {
|
||||||
|
mbedtls_x509_crt_free(c);
|
||||||
|
free(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns singleton of SSL roots stored in /zip/usr/share/ssl/root/...
|
||||||
|
*/
|
||||||
mbedtls_x509_crt *GetSslRoots(void) {
|
mbedtls_x509_crt *GetSslRoots(void) {
|
||||||
int fd;
|
int fd;
|
||||||
DIR *d;
|
DIR *d;
|
||||||
uint8_t *p;
|
uint8_t *p;
|
||||||
size_t n, m;
|
size_t n, m;
|
||||||
struct dirent *e;
|
struct dirent *e;
|
||||||
mbedtls_x509_crt *c;
|
static bool once;
|
||||||
|
static mbedtls_x509_crt *c;
|
||||||
char path[PATH_MAX + 1];
|
char path[PATH_MAX + 1];
|
||||||
c = calloc(1, sizeof(*c));
|
if (!once) {
|
||||||
m = stpcpy(path, "/zip/usr/share/ssl/root/") - path;
|
if ((c = calloc(1, sizeof(*c)))) {
|
||||||
if ((d = opendir(path))) {
|
m = stpcpy(path, "/zip/usr/share/ssl/root/") - path;
|
||||||
while ((e = readdir(d))) {
|
if ((d = opendir(path))) {
|
||||||
if (e->d_type != DT_REG) continue;
|
while ((e = readdir(d))) {
|
||||||
if (m + (n = strlen(e->d_name)) > PATH_MAX) continue;
|
if (e->d_type != DT_REG) continue;
|
||||||
memcpy(path + m, e->d_name, n + 1);
|
if (m + (n = strlen(e->d_name)) > PATH_MAX) continue;
|
||||||
CHECK((p = xslurp(path, &n)));
|
memcpy(path + m, e->d_name, n + 1);
|
||||||
CHECK_GE(mbedtls_x509_crt_parse(c, p, n + 1), 0, "%s", path);
|
CHECK((p = xslurp(path, &n)));
|
||||||
free(p);
|
CHECK_GE(mbedtls_x509_crt_parse(c, p, n + 1), 0, "%s", path);
|
||||||
|
free(p);
|
||||||
|
}
|
||||||
|
closedir(d);
|
||||||
|
}
|
||||||
|
__cxa_atexit(FreeSslRoots, c, 0);
|
||||||
}
|
}
|
||||||
closedir(d);
|
once = true;
|
||||||
}
|
}
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include "libc/log/log.h"
|
#include "libc/log/log.h"
|
||||||
#include "libc/mem/mem.h"
|
#include "libc/mem/mem.h"
|
||||||
#include "libc/runtime/gc.internal.h"
|
#include "libc/runtime/gc.internal.h"
|
||||||
|
#include "libc/runtime/internal.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
#include "libc/runtime/symbols.internal.h"
|
#include "libc/runtime/symbols.internal.h"
|
||||||
#include "libc/stdio/append.internal.h"
|
#include "libc/stdio/append.internal.h"
|
||||||
|
@ -84,7 +85,7 @@ char *StackOverrunCrash(int n) {
|
||||||
|
|
||||||
char *MemoryLeakCrash(void) {
|
char *MemoryLeakCrash(void) {
|
||||||
char *p = strdup("doge");
|
char *p = strdup("doge");
|
||||||
testlib_checkformemoryleaks();
|
CheckForMemoryLeaks();
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,6 +124,9 @@ void SetUp(void) {
|
||||||
exit((intptr_t)pMemoryLeakCrash());
|
exit((intptr_t)pMemoryLeakCrash());
|
||||||
case 7:
|
case 7:
|
||||||
exit(pNpeCrash(0));
|
exit(pNpeCrash(0));
|
||||||
|
case 8:
|
||||||
|
__cxa_finalize(0);
|
||||||
|
exit(pNpeCrash(0));
|
||||||
default:
|
default:
|
||||||
printf("preventing fork recursion: %s\n", __argv[1]);
|
printf("preventing fork recursion: %s\n", __argv[1]);
|
||||||
exit(1);
|
exit(1);
|
||||||
|
@ -550,7 +554,7 @@ TEST(ShowCrashReports, testNpeCrash) {
|
||||||
ASSERT_NE(-1, wait(&ws));
|
ASSERT_NE(-1, wait(&ws));
|
||||||
EXPECT_TRUE(WIFEXITED(ws));
|
EXPECT_TRUE(WIFEXITED(ws));
|
||||||
EXPECT_EQ(77, WEXITSTATUS(ws));
|
EXPECT_EQ(77, WEXITSTATUS(ws));
|
||||||
/* NULL is stopgap until we can copy symbol tablces into binary */
|
/* NULL is stopgap until we can copy symbol tables into binary */
|
||||||
if (!strstr(output, "null pointer dereference")) {
|
if (!strstr(output, "null pointer dereference")) {
|
||||||
fprintf(stderr, "ERROR: crash report didn't diagnose the problem\n%s\n",
|
fprintf(stderr, "ERROR: crash report didn't diagnose the problem\n%s\n",
|
||||||
gc(IndentLines(output, -1, 0, 4)));
|
gc(IndentLines(output, -1, 0, 4)));
|
||||||
|
@ -619,3 +623,57 @@ TEST(ShowCrashReports, testDataOverrunCrash) {
|
||||||
}
|
}
|
||||||
free(output);
|
free(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(ShowCrashReports, testNpeCrashAfterFinalize) {
|
||||||
|
/*
|
||||||
|
* this test makes sure we're not doing things like depending on
|
||||||
|
* environment variables after __cxa_finalize is called in cases
|
||||||
|
* where putenv() is used
|
||||||
|
*/
|
||||||
|
size_t got;
|
||||||
|
ssize_t rc;
|
||||||
|
int ws, pid, fds[2];
|
||||||
|
char *output, buf[512];
|
||||||
|
ASSERT_NE(-1, pipe2(fds, O_CLOEXEC));
|
||||||
|
ASSERT_NE(-1, (pid = vfork()));
|
||||||
|
if (!pid) {
|
||||||
|
dup2(fds[1], 1);
|
||||||
|
dup2(fds[1], 2);
|
||||||
|
execv(program_executable_name,
|
||||||
|
(char *const[]){program_executable_name, "8", 0});
|
||||||
|
_exit(127);
|
||||||
|
}
|
||||||
|
close(fds[1]);
|
||||||
|
output = 0;
|
||||||
|
appends(&output, "");
|
||||||
|
for (;;) {
|
||||||
|
rc = read(fds[0], buf, sizeof(buf));
|
||||||
|
if (rc == -1) {
|
||||||
|
ASSERT_EQ(EINTR, errno);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ((got = rc)) {
|
||||||
|
appendd(&output, buf, got);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ASSERT_NE(-1, wait(&ws));
|
||||||
|
EXPECT_TRUE(WIFEXITED(ws));
|
||||||
|
EXPECT_EQ(IsAsan() ? 77 : 128 + SIGSEGV, WEXITSTATUS(ws));
|
||||||
|
/* NULL is stopgap until we can copy symbol tables into binary */
|
||||||
|
if (!strstr(output, IsAsan() ? "null pointer dereference"
|
||||||
|
: "Uncaught SIGSEGV (SEGV_MAPERR)")) {
|
||||||
|
fprintf(stderr, "ERROR: crash report didn't diagnose the problem\n%s\n",
|
||||||
|
gc(IndentLines(output, -1, 0, 4)));
|
||||||
|
__die();
|
||||||
|
}
|
||||||
|
#ifdef __FNO_OMIT_FRAME_POINTER__
|
||||||
|
if (!OutputHasSymbol(output, "NpeCrash")) {
|
||||||
|
fprintf(stderr, "ERROR: crash report didn't have backtrace\n%s\n",
|
||||||
|
gc(IndentLines(output, -1, 0, 4)));
|
||||||
|
__die();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
free(output);
|
||||||
|
}
|
||||||
|
|
|
@ -157,6 +157,16 @@ TEST(appendd, testMemFail_doesntFreeExistingAllocation) {
|
||||||
free(b);
|
free(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(appendd, nontrivialAmountOfMemory) {
|
||||||
|
char *b = 0;
|
||||||
|
int i, n = 40000;
|
||||||
|
for (i = 0; i < n; ++i) {
|
||||||
|
ASSERT_EQ(2, appendd(&b, "hi", 2));
|
||||||
|
}
|
||||||
|
EXPECT_EQ(40000 * 2, appendz(b).i);
|
||||||
|
free(b);
|
||||||
|
}
|
||||||
|
|
||||||
BENCH(vappendf, bench) {
|
BENCH(vappendf, bench) {
|
||||||
const char t[] = {0};
|
const char t[] = {0};
|
||||||
char *b = 0;
|
char *b = 0;
|
||||||
|
|
1
third_party/lua/lapi.c
vendored
1
third_party/lua/lapi.c
vendored
|
@ -726,6 +726,7 @@ LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {
|
||||||
*/
|
*/
|
||||||
LUA_API void lua_pushboolean (lua_State *L, int b) {
|
LUA_API void lua_pushboolean (lua_State *L, int b) {
|
||||||
lua_lock(L);
|
lua_lock(L);
|
||||||
|
/* a.k.a. L->top->val.tt_ = b ? LUA_VTRUE : LUA_VFALSE; */
|
||||||
if (b)
|
if (b)
|
||||||
setbtvalue(s2v(L->top));
|
setbtvalue(s2v(L->top));
|
||||||
else
|
else
|
||||||
|
|
41
third_party/mbedtls/formatclientciphers.c
vendored
Normal file
41
third_party/mbedtls/formatclientciphers.c
vendored
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||||
|
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||||
|
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||||
|
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||||
|
│ │
|
||||||
|
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||||
|
│ any purpose with or without fee is hereby granted, provided that the │
|
||||||
|
│ above copyright notice and this permission notice appear in all copies. │
|
||||||
|
│ │
|
||||||
|
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||||
|
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||||
|
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||||
|
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||||
|
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||||
|
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||||
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/bits/bits.h"
|
||||||
|
#include "libc/macros.internal.h"
|
||||||
|
#include "libc/stdio/append.internal.h"
|
||||||
|
#include "third_party/mbedtls/iana.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns string of joined list of first 𝑘 client preferred ciphers.
|
||||||
|
* @return string that must be free'd, or null if none set
|
||||||
|
*/
|
||||||
|
nodiscard char *FormatSslClientCiphers(const mbedtls_ssl_context *ssl) {
|
||||||
|
int i;
|
||||||
|
char *b = 0;
|
||||||
|
for (i = 0; i < ARRAYLEN(ssl->client_ciphers); ++i) {
|
||||||
|
if (!ssl->client_ciphers[i]) break;
|
||||||
|
if (i) appendw(&b, READ16LE(", "));
|
||||||
|
appendf(&b, "%s[0x%04x]", GetCipherSuiteName(ssl->client_ciphers[i]),
|
||||||
|
ssl->client_ciphers[i]);
|
||||||
|
}
|
||||||
|
if (i == ARRAYLEN(ssl->client_ciphers)) {
|
||||||
|
appends(&b, ", ...");
|
||||||
|
}
|
||||||
|
return b;
|
||||||
|
}
|
714
third_party/mbedtls/getciphersuitename.c
vendored
714
third_party/mbedtls/getciphersuitename.c
vendored
File diff suppressed because it is too large
Load diff
2
third_party/mbedtls/iana.h
vendored
2
third_party/mbedtls/iana.h
vendored
|
@ -1,11 +1,13 @@
|
||||||
#ifndef COSMOPOLITAN_THIRD_PARTY_MBEDTLS_IANA_H_
|
#ifndef COSMOPOLITAN_THIRD_PARTY_MBEDTLS_IANA_H_
|
||||||
#define COSMOPOLITAN_THIRD_PARTY_MBEDTLS_IANA_H_
|
#define COSMOPOLITAN_THIRD_PARTY_MBEDTLS_IANA_H_
|
||||||
|
#include "third_party/mbedtls/ssl.h"
|
||||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||||
COSMOPOLITAN_C_START_
|
COSMOPOLITAN_C_START_
|
||||||
|
|
||||||
bool IsCipherSuiteGood(uint16_t);
|
bool IsCipherSuiteGood(uint16_t);
|
||||||
const char *GetCipherSuiteName(uint16_t);
|
const char *GetCipherSuiteName(uint16_t);
|
||||||
const char *GetAlertDescription(unsigned char);
|
const char *GetAlertDescription(unsigned char);
|
||||||
|
nodiscard char *FormatSslClientCiphers(const mbedtls_ssl_context *);
|
||||||
|
|
||||||
COSMOPOLITAN_C_END_
|
COSMOPOLITAN_C_END_
|
||||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||||
|
|
1
third_party/mbedtls/ssl.h
vendored
1
third_party/mbedtls/ssl.h
vendored
|
@ -1250,6 +1250,7 @@ struct mbedtls_ssl_context
|
||||||
* Possible values are #MBEDTLS_SSL_CID_ENABLED
|
* Possible values are #MBEDTLS_SSL_CID_ENABLED
|
||||||
* and #MBEDTLS_SSL_CID_DISABLED. */
|
* and #MBEDTLS_SSL_CID_DISABLED. */
|
||||||
#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */
|
#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */
|
||||||
|
uint16_t client_ciphers[16]; /* [jart] clarifies MBEDTLS_ERR_SSL_NO_USABLE_CIPHERSUITE */
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
23
third_party/mbedtls/ssl_srv.c
vendored
23
third_party/mbedtls/ssl_srv.c
vendored
|
@ -16,6 +16,8 @@
|
||||||
│ limitations under the License. │
|
│ limitations under the License. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/log/log.h"
|
#include "libc/log/log.h"
|
||||||
|
#include "libc/macros.internal.h"
|
||||||
|
#include "libc/str/str.h"
|
||||||
#include "third_party/mbedtls/common.h"
|
#include "third_party/mbedtls/common.h"
|
||||||
#include "third_party/mbedtls/debug.h"
|
#include "third_party/mbedtls/debug.h"
|
||||||
#include "third_party/mbedtls/ecp.h"
|
#include "third_party/mbedtls/ecp.h"
|
||||||
|
@ -1159,9 +1161,9 @@ static int ssl_ciphersuite_match( mbedtls_ssl_context *ssl, int suite_id,
|
||||||
#if defined(MBEDTLS_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO)
|
#if defined(MBEDTLS_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO)
|
||||||
static int ssl_parse_client_hello_v2( mbedtls_ssl_context *ssl )
|
static int ssl_parse_client_hello_v2( mbedtls_ssl_context *ssl )
|
||||||
{
|
{
|
||||||
int ret, got_common_suite;
|
|
||||||
unsigned int i, j;
|
|
||||||
size_t n;
|
size_t n;
|
||||||
|
unsigned int i, j;
|
||||||
|
int ret, got_common_suite;
|
||||||
unsigned int ciph_len, sess_len, chal_len;
|
unsigned int ciph_len, sess_len, chal_len;
|
||||||
unsigned char *buf, *p;
|
unsigned char *buf, *p;
|
||||||
const uint16_t *ciphersuites;
|
const uint16_t *ciphersuites;
|
||||||
|
@ -1357,6 +1359,13 @@ static int ssl_parse_client_hello_v2( mbedtls_ssl_context *ssl )
|
||||||
got_common_suite = 0;
|
got_common_suite = 0;
|
||||||
ciphersuites = ssl->conf->ciphersuite_list[ssl->minor_ver];
|
ciphersuites = ssl->conf->ciphersuite_list[ssl->minor_ver];
|
||||||
ciphersuite_info = NULL;
|
ciphersuite_info = NULL;
|
||||||
|
|
||||||
|
/* [jart] grab some client ciphers for error messages */
|
||||||
|
bzero(ssl->client_ciphers, sizeof(ssl->client_ciphers));
|
||||||
|
for( i = j = 0, p = buf + 6; j < ciph_len; j += 3, p += 3 )
|
||||||
|
if( !p[0] && i < ARRAYLEN( ssl->client_ciphers ) )
|
||||||
|
ssl->client_ciphers[i++] = p[1] << 8 | p[2];
|
||||||
|
|
||||||
#if defined(MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE)
|
#if defined(MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE)
|
||||||
for( j = 0, p = buf + 6; j < ciph_len; j += 3, p += 3 )
|
for( j = 0, p = buf + 6; j < ciph_len; j += 3, p += 3 )
|
||||||
for( i = 0; ciphersuites[i] != 0; i++ )
|
for( i = 0; ciphersuites[i] != 0; i++ )
|
||||||
|
@ -1365,9 +1374,7 @@ static int ssl_parse_client_hello_v2( mbedtls_ssl_context *ssl )
|
||||||
for( j = 0, p = buf + 6; j < ciph_len; j += 3, p += 3 )
|
for( j = 0, p = buf + 6; j < ciph_len; j += 3, p += 3 )
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
if( p[0] != 0 ||
|
if( p[0] || (p[1] << 8 | p[2]) != ciphersuites[i] )
|
||||||
p[1] != ( ( ciphersuites[i] >> 8 ) & 0xFF ) ||
|
|
||||||
p[2] != ( ( ciphersuites[i] ) & 0xFF ) )
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
got_common_suite = 1;
|
got_common_suite = 1;
|
||||||
|
@ -2198,6 +2205,12 @@ read_record_header:
|
||||||
return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
|
return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* [jart] grab some client ciphers for error messages */
|
||||||
|
bzero(ssl->client_ciphers, sizeof(ssl->client_ciphers));
|
||||||
|
for( i = j = 0, p = buf + ciph_offset + 2; j < ciph_len; j += 2, p += 2 )
|
||||||
|
if( i < ARRAYLEN( ssl->client_ciphers ) )
|
||||||
|
ssl->client_ciphers[i++] = p[0] << 8 | p[1];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Search for a matching ciphersuite
|
* Search for a matching ciphersuite
|
||||||
* (At the end because we need information from the EC-based extensions
|
* (At the end because we need information from the EC-based extensions
|
||||||
|
|
4
third_party/python/Modules/tlsmodule.c
vendored
4
third_party/python/Modules/tlsmodule.c
vendored
|
@ -62,7 +62,6 @@ struct Tls {
|
||||||
|
|
||||||
static PyObject *TlsError;
|
static PyObject *TlsError;
|
||||||
static PyTypeObject tls_type;
|
static PyTypeObject tls_type;
|
||||||
static mbedtls_x509_crt *roots;
|
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
SetTlsError(int rc)
|
SetTlsError(int rc)
|
||||||
|
@ -130,7 +129,7 @@ tls_new(int fd, const char *host, PyObject *todo)
|
||||||
MBEDTLS_SSL_TRANSPORT_STREAM,
|
MBEDTLS_SSL_TRANSPORT_STREAM,
|
||||||
MBEDTLS_SSL_PRESET_DEFAULT);
|
MBEDTLS_SSL_PRESET_DEFAULT);
|
||||||
mbedtls_ssl_conf_rng(&self->conf, mbedtls_ctr_drbg_random, &self->rng);
|
mbedtls_ssl_conf_rng(&self->conf, mbedtls_ctr_drbg_random, &self->rng);
|
||||||
mbedtls_ssl_conf_ca_chain(&self->conf, roots, 0);
|
mbedtls_ssl_conf_ca_chain(&self->conf, GetSslRoots(), 0);
|
||||||
/* mbedtls_ssl_conf_dbg(&self->conf, TlsDebug, 0); */
|
/* mbedtls_ssl_conf_dbg(&self->conf, TlsDebug, 0); */
|
||||||
/* mbedtls_debug_threshold = 5; */
|
/* mbedtls_debug_threshold = 5; */
|
||||||
if (host && *host) {
|
if (host && *host) {
|
||||||
|
@ -493,7 +492,6 @@ PyInit_tls(void)
|
||||||
TlsError = PyErr_NewException("tls.TlsError", NULL, NULL);
|
TlsError = PyErr_NewException("tls.TlsError", NULL, NULL);
|
||||||
Py_INCREF(TlsError);
|
Py_INCREF(TlsError);
|
||||||
PyModule_AddObject(m, "TlsError", TlsError);
|
PyModule_AddObject(m, "TlsError", TlsError);
|
||||||
roots = GetSslRoots();
|
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
#include "libc/limits.h"
|
#include "libc/limits.h"
|
||||||
#include "libc/log/check.h"
|
#include "libc/log/check.h"
|
||||||
#include "libc/log/color.internal.h"
|
#include "libc/log/color.internal.h"
|
||||||
|
#include "libc/log/internal.h"
|
||||||
#include "libc/log/log.h"
|
#include "libc/log/log.h"
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
#include "libc/math.h"
|
#include "libc/math.h"
|
||||||
|
@ -3114,7 +3115,7 @@ int main(int argc, char *argv[]) {
|
||||||
speed = 32;
|
speed = 32;
|
||||||
SetXmmSize(2);
|
SetXmmSize(2);
|
||||||
SetXmmDisp(kXmmHex);
|
SetXmmDisp(kXmmHex);
|
||||||
if ((colorize = cancolor())) {
|
if ((colorize = !__nocolor)) {
|
||||||
g_high.keyword = 155;
|
g_high.keyword = 155;
|
||||||
g_high.reg = 215;
|
g_high.reg = 215;
|
||||||
g_high.literal = 182;
|
g_high.literal = 182;
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include "libc/fmt/itoa.h"
|
#include "libc/fmt/itoa.h"
|
||||||
#include "libc/limits.h"
|
#include "libc/limits.h"
|
||||||
#include "libc/log/color.internal.h"
|
#include "libc/log/color.internal.h"
|
||||||
|
#include "libc/log/internal.h"
|
||||||
#include "libc/log/log.h"
|
#include "libc/log/log.h"
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
#include "libc/math.h"
|
#include "libc/math.h"
|
||||||
|
@ -680,8 +681,8 @@ void CleanupTerminal(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void StartInteractive(void) {
|
void StartInteractive(void) {
|
||||||
if (!interactive && !IsTerminalInarticulate() && isatty(fileno(stdin)) &&
|
if (!interactive && !__nocolor && isatty(fileno(stdin)) &&
|
||||||
isatty(fileno(stdout)) && cancolor()) {
|
isatty(fileno(stdout)) && !__nocolor) {
|
||||||
interactive = true;
|
interactive = true;
|
||||||
}
|
}
|
||||||
if (interactive) {
|
if (interactive) {
|
||||||
|
|
|
@ -141,7 +141,6 @@ bool wantfentry;
|
||||||
bool wantrecord;
|
bool wantrecord;
|
||||||
bool fulloutput;
|
bool fulloutput;
|
||||||
bool touchtarget;
|
bool touchtarget;
|
||||||
bool inarticulate;
|
|
||||||
bool wantnoredzone;
|
bool wantnoredzone;
|
||||||
bool stdoutmustclose;
|
bool stdoutmustclose;
|
||||||
bool no_sanitize_null;
|
bool no_sanitize_null;
|
||||||
|
@ -198,7 +197,7 @@ const char *const kSafeEnv[] = {
|
||||||
"PATH", // needed by clang
|
"PATH", // needed by clang
|
||||||
"PWD", // just seems plain needed
|
"PWD", // just seems plain needed
|
||||||
"STRACE", // useful for troubleshooting
|
"STRACE", // useful for troubleshooting
|
||||||
"TERM", // needed by IsTerminalInarticulate
|
"TERM", // needed to detect colors
|
||||||
"TMPDIR", // needed by compiler
|
"TMPDIR", // needed by compiler
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -268,19 +267,19 @@ void OnChld(int sig, siginfo_t *si, ucontext_t *ctx) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void PrintBold(void) {
|
void PrintBold(void) {
|
||||||
if (!inarticulate) {
|
if (!__nocolor) {
|
||||||
appends(&output, "\e[1m");
|
appends(&output, "\e[1m");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PrintRed(void) {
|
void PrintRed(void) {
|
||||||
if (!inarticulate) {
|
if (!__nocolor) {
|
||||||
appends(&output, "\e[91;1m");
|
appends(&output, "\e[91;1m");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PrintReset(void) {
|
void PrintReset(void) {
|
||||||
if (!inarticulate) {
|
if (!__nocolor) {
|
||||||
appends(&output, "\e[0m");
|
appends(&output, "\e[0m");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -806,11 +805,6 @@ int main(int argc, char *argv[]) {
|
||||||
ispkg = true;
|
ispkg = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* get information about stdout
|
|
||||||
*/
|
|
||||||
inarticulate = IsTerminalInarticulate();
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ingest arguments
|
* ingest arguments
|
||||||
*/
|
*/
|
||||||
|
@ -942,7 +936,7 @@ int main(int argc, char *argv[]) {
|
||||||
AddArg("-Wno-incompatible-pointer-types-discards-qualifiers");
|
AddArg("-Wno-incompatible-pointer-types-discards-qualifiers");
|
||||||
}
|
}
|
||||||
AddArg("-no-canonical-prefixes");
|
AddArg("-no-canonical-prefixes");
|
||||||
if (!inarticulate) {
|
if (!__nocolor) {
|
||||||
AddArg(firstnonnull(colorflag, "-fdiagnostics-color=always"));
|
AddArg(firstnonnull(colorflag, "-fdiagnostics-color=always"));
|
||||||
}
|
}
|
||||||
if (wantpg && !wantnopg) {
|
if (wantpg && !wantnopg) {
|
||||||
|
@ -1181,7 +1175,7 @@ int main(int argc, char *argv[]) {
|
||||||
if (fulloutput) {
|
if (fulloutput) {
|
||||||
ReportResources();
|
ReportResources();
|
||||||
}
|
}
|
||||||
if (!inarticulate && ischardev(2)) {
|
if (!__nocolor && ischardev(2)) {
|
||||||
/* clear line forward */
|
/* clear line forward */
|
||||||
appendw(&output, READ32LE("\e[K"));
|
appendw(&output, READ32LE("\e[K"));
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,8 +23,11 @@ local function WriteForm(url)
|
||||||
p {
|
p {
|
||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
}
|
}
|
||||||
p span {
|
dd {
|
||||||
display: block;
|
margin-top: 1em;
|
||||||
|
margin-bottom: 1em;
|
||||||
|
}
|
||||||
|
.hdr {
|
||||||
text-indent: -1em;
|
text-indent: -1em;
|
||||||
padding-left: 1em;
|
padding-left: 1em;
|
||||||
}
|
}
|
||||||
|
@ -53,13 +56,13 @@ local function main()
|
||||||
Write('<dt>Status\r\n')
|
Write('<dt>Status\r\n')
|
||||||
Write(string.format('<dd><p>%d %s\r\n', status, GetHttpReason(status)))
|
Write(string.format('<dd><p>%d %s\r\n', status, GetHttpReason(status)))
|
||||||
Write('<dt>Headers\r\n')
|
Write('<dt>Headers\r\n')
|
||||||
Write('<dd><p>\r\n')
|
Write('<dd>\r\n')
|
||||||
for k,v in pairs(headers) do
|
for k,v in pairs(headers) do
|
||||||
Write('<span><strong>')
|
Write('<div class="hdr"><strong>')
|
||||||
Write(EscapeHtml(k))
|
Write(EscapeHtml(k))
|
||||||
Write('</strong>: ')
|
Write('</strong>: ')
|
||||||
Write(EscapeHtml(v))
|
Write(EscapeHtml(v))
|
||||||
Write('</span>\r\n')
|
Write('</div>\r\n')
|
||||||
end
|
end
|
||||||
Write('<dt>Payload\r\n')
|
Write('<dt>Payload\r\n')
|
||||||
Write('<dd><pre>')
|
Write('<dd><pre>')
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#include "libc/calls/struct/rusage.h"
|
#include "libc/calls/struct/rusage.h"
|
||||||
#include "libc/calls/struct/sigaction.h"
|
#include "libc/calls/struct/sigaction.h"
|
||||||
#include "libc/calls/struct/stat.h"
|
#include "libc/calls/struct/stat.h"
|
||||||
|
#include "libc/dce.h"
|
||||||
#include "libc/dns/dns.h"
|
#include "libc/dns/dns.h"
|
||||||
#include "libc/dns/hoststxt.h"
|
#include "libc/dns/hoststxt.h"
|
||||||
#include "libc/dos.h"
|
#include "libc/dos.h"
|
||||||
|
@ -85,6 +86,7 @@
|
||||||
#include "libc/sysv/consts/sol.h"
|
#include "libc/sysv/consts/sol.h"
|
||||||
#include "libc/sysv/consts/tcp.h"
|
#include "libc/sysv/consts/tcp.h"
|
||||||
#include "libc/sysv/consts/w.h"
|
#include "libc/sysv/consts/w.h"
|
||||||
|
#include "libc/testlib/testlib.h"
|
||||||
#include "libc/time/time.h"
|
#include "libc/time/time.h"
|
||||||
#include "libc/x/x.h"
|
#include "libc/x/x.h"
|
||||||
#include "libc/zip.h"
|
#include "libc/zip.h"
|
||||||
|
@ -164,6 +166,15 @@ STATIC_STACK_SIZE(0x40000);
|
||||||
#define HeaderEqualCase(H, S) \
|
#define HeaderEqualCase(H, S) \
|
||||||
SlicesEqualCase(S, strlen(S), HeaderData(H), HeaderLength(H))
|
SlicesEqualCase(S, strlen(S), HeaderData(H), HeaderLength(H))
|
||||||
|
|
||||||
|
#define AssertLuaStackIsEmpty(L) \
|
||||||
|
do { \
|
||||||
|
if (lua_gettop(L)) { \
|
||||||
|
char *s = LuaFormatStack(L); \
|
||||||
|
WARNF("lua stack should be empty!\n%s", s); \
|
||||||
|
free(s); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
static const uint8_t kGzipHeader[] = {
|
static const uint8_t kGzipHeader[] = {
|
||||||
0x1F, // MAGNUM
|
0x1F, // MAGNUM
|
||||||
0x8B, // MAGNUM
|
0x8B, // MAGNUM
|
||||||
|
@ -379,9 +390,9 @@ static int messageshandled;
|
||||||
static int sslticketlifetime;
|
static int sslticketlifetime;
|
||||||
static uint32_t clientaddrsize;
|
static uint32_t clientaddrsize;
|
||||||
|
|
||||||
static lua_State *GL;
|
|
||||||
static size_t zsize;
|
static size_t zsize;
|
||||||
static char *outbuf;
|
static char *outbuf;
|
||||||
|
static lua_State *GL;
|
||||||
static char *content;
|
static char *content;
|
||||||
static uint8_t *zmap;
|
static uint8_t *zmap;
|
||||||
static uint8_t *zbase;
|
static uint8_t *zbase;
|
||||||
|
@ -406,11 +417,11 @@ static int64_t cacheseconds;
|
||||||
static const char *serverheader;
|
static const char *serverheader;
|
||||||
static struct Strings stagedirs;
|
static struct Strings stagedirs;
|
||||||
static struct Strings hidepaths;
|
static struct Strings hidepaths;
|
||||||
static mbedtls_x509_crt *cachain;
|
|
||||||
static const char *launchbrowser;
|
static const char *launchbrowser;
|
||||||
static const char *referrerpolicy;
|
static const char *referrerpolicy;
|
||||||
static ssize_t (*generator)(struct iovec[3]);
|
static ssize_t (*generator)(struct iovec[3]);
|
||||||
|
|
||||||
|
static struct Buffer inbuf_actual;
|
||||||
static struct Buffer inbuf;
|
static struct Buffer inbuf;
|
||||||
static struct Buffer oldin;
|
static struct Buffer oldin;
|
||||||
static struct Buffer hdrbuf;
|
static struct Buffer hdrbuf;
|
||||||
|
@ -443,6 +454,7 @@ static struct TlsBio g_bio;
|
||||||
static char slashpath[PATH_MAX];
|
static char slashpath[PATH_MAX];
|
||||||
static struct DeflateGenerator dg;
|
static struct DeflateGenerator dg;
|
||||||
|
|
||||||
|
static wontreturn void ExitWorker(void);
|
||||||
static char *Route(const char *, size_t, const char *, size_t);
|
static char *Route(const char *, size_t, const char *, size_t);
|
||||||
static char *RouteHost(const char *, size_t, const char *, size_t);
|
static char *RouteHost(const char *, size_t, const char *, size_t);
|
||||||
static char *RoutePath(const char *, size_t);
|
static char *RoutePath(const char *, size_t);
|
||||||
|
@ -485,6 +497,11 @@ static void OnHup(void) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void Free(void *p) {
|
||||||
|
free(*(void **)p);
|
||||||
|
*(void **)p = 0;
|
||||||
|
}
|
||||||
|
|
||||||
static long ParseInt(const char *s) {
|
static long ParseInt(const char *s) {
|
||||||
return strtol(s, 0, 0);
|
return strtol(s, 0, 0);
|
||||||
}
|
}
|
||||||
|
@ -605,7 +622,8 @@ static void InternCertificate(mbedtls_x509_crt *cert, mbedtls_x509_crt *prev) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (mbedtls_x509_time_is_past(&cert->valid_to)) {
|
if (mbedtls_x509_time_is_past(&cert->valid_to)) {
|
||||||
WARNF("(ssl) certificate %`'s is expired", gc(FormatX509Name(&cert->subject)));
|
WARNF("(ssl) certificate %`'s is expired",
|
||||||
|
gc(FormatX509Name(&cert->subject)));
|
||||||
} else if (mbedtls_x509_time_is_future(&cert->valid_from)) {
|
} else if (mbedtls_x509_time_is_future(&cert->valid_from)) {
|
||||||
WARNF("(ssl) certificate %`'s is from the future",
|
WARNF("(ssl) certificate %`'s is from the future",
|
||||||
gc(FormatX509Name(&cert->subject)));
|
gc(FormatX509Name(&cert->subject)));
|
||||||
|
@ -823,11 +841,9 @@ static inline void GetRemoteAddr(uint32_t *ip, uint16_t *port) {
|
||||||
if (HasHeader(kHttpXForwardedFor) &&
|
if (HasHeader(kHttpXForwardedFor) &&
|
||||||
(IsPrivateIp(*ip) || IsLoopbackIp(*ip))) {
|
(IsPrivateIp(*ip) || IsLoopbackIp(*ip))) {
|
||||||
if (ParseForwarded(HeaderData(kHttpXForwardedFor),
|
if (ParseForwarded(HeaderData(kHttpXForwardedFor),
|
||||||
HeaderLength(kHttpXForwardedFor),
|
HeaderLength(kHttpXForwardedFor), ip, port) == -1)
|
||||||
ip, port) == -1)
|
|
||||||
WARNF("invalid X-Forwarded-For value: %`'.*s",
|
WARNF("invalid X-Forwarded-For value: %`'.*s",
|
||||||
HeaderLength(kHttpXForwardedFor),
|
HeaderLength(kHttpXForwardedFor), HeaderData(kHttpXForwardedFor));
|
||||||
HeaderData(kHttpXForwardedFor));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1006,25 +1022,59 @@ static void Daemonize(void) {
|
||||||
ChangeUser();
|
ChangeUser();
|
||||||
}
|
}
|
||||||
|
|
||||||
static int LuaCallWithTrace(lua_State *L, int nargs, int nres) {
|
static nodiscard char *LuaFormatStack(lua_State *L) {
|
||||||
|
int i, top;
|
||||||
|
char *b = 0;
|
||||||
|
top = lua_gettop(L);
|
||||||
|
for (i = 1; i <= top; i++) {
|
||||||
|
if (i > 1) appendw(&b, '\n');
|
||||||
|
appendf(&b, "\t%d\t%s\t", i, luaL_typename(L, i));
|
||||||
|
switch (lua_type(L, i)) {
|
||||||
|
case LUA_TNUMBER:
|
||||||
|
appendf(&b, "%g", lua_tonumber(L, i));
|
||||||
|
break;
|
||||||
|
case LUA_TSTRING:
|
||||||
|
appends(&b, lua_tostring(L, i));
|
||||||
|
break;
|
||||||
|
case LUA_TBOOLEAN:
|
||||||
|
appends(&b, lua_toboolean(L, i) ? "true" : "false");
|
||||||
|
break;
|
||||||
|
case LUA_TNIL:
|
||||||
|
appends(&b, "nil");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
appendf(&b, "%p", lua_topointer(L, i));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
// calling convention for lua stack of L is:
|
||||||
|
// -3 is lua_newthread() called by caller
|
||||||
|
// -2 is function
|
||||||
|
// -1 is is argument (assuming nargs == 1)
|
||||||
|
// L will have this after the call
|
||||||
|
// -2 is lua_newthread() called by caller
|
||||||
|
// -1 is result (assuming nres == 1)
|
||||||
|
// @param L is main Lua interpreter
|
||||||
|
// @param C should be the result of lua_newthread()
|
||||||
|
// @note this needs to be reentrant
|
||||||
|
static int LuaCallWithTrace(lua_State *L, lua_State *C, int nargs, int nres) {
|
||||||
int nresults, status;
|
int nresults, status;
|
||||||
// create a coroutine to retrieve traceback on failure
|
|
||||||
lua_State *co = lua_newthread(L);
|
|
||||||
// pop the coroutine, so that the function is at the top
|
|
||||||
lua_pop(L, 1);
|
|
||||||
// move the function (and arguments) to the top of the coro stack
|
// move the function (and arguments) to the top of the coro stack
|
||||||
lua_xmove(L, co, nargs + 1);
|
lua_xmove(L, C, 1 + nargs);
|
||||||
// resume the coroutine thus executing the function
|
// resume the coroutine thus executing the function
|
||||||
status = lua_resume(co, L, nargs, &nresults);
|
status = lua_resume(C, L, nargs, &nresults);
|
||||||
if (status != LUA_OK && status != LUA_YIELD) {
|
if (status != LUA_OK && status != LUA_YIELD) {
|
||||||
// move the error message
|
// move the error message
|
||||||
lua_xmove(co, L, 1);
|
lua_xmove(C, L, 1);
|
||||||
// replace the error with the traceback on failure
|
// replace the error with the traceback on failure
|
||||||
luaL_traceback(L, co, lua_tostring(L, -1), 0);
|
luaL_traceback(L, C, lua_tostring(L, -1), 0);
|
||||||
lua_remove(L, -2); // remove the error message
|
lua_remove(L, -2); // remove the error message
|
||||||
} else {
|
} else {
|
||||||
// move results to the main stack
|
// move results to the main stack
|
||||||
lua_xmove(co, L, nresults);
|
lua_xmove(C, L, nresults);
|
||||||
// make sure the stack has enough space to grow
|
// make sure the stack has enough space to grow
|
||||||
luaL_checkstack(L, nres - nresults, NULL);
|
luaL_checkstack(L, nres - nresults, NULL);
|
||||||
// grow the stack in case returned fewer results
|
// grow the stack in case returned fewer results
|
||||||
|
@ -1036,21 +1086,21 @@ static int LuaCallWithTrace(lua_State *L, int nargs, int nres) {
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO(paul): Regression with /redbean.lua */
|
|
||||||
#define LuaCallWithTrace(L, N, Z) lua_pcall(L, N, Z, 0)
|
|
||||||
|
|
||||||
static void LogLuaError(char *hook, char *err) {
|
static void LogLuaError(char *hook, char *err) {
|
||||||
ERRORF("(lua) failed to run %s: %s", hook, err);
|
ERRORF("(lua) failed to run %s: %s", hook, err);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool LuaRunCode(const char *code) {
|
static bool LuaRunCode(const char *code) {
|
||||||
lua_State *L = GL;
|
lua_State *L = GL;
|
||||||
|
lua_State *C = lua_newthread(L);
|
||||||
int status = luaL_loadstring(L, code);
|
int status = luaL_loadstring(L, code);
|
||||||
if (status != LUA_OK || LuaCallWithTrace(L, 0, 0) != LUA_OK) {
|
if (status != LUA_OK || LuaCallWithTrace(L, C, 0, 0) != LUA_OK) {
|
||||||
LogLuaError("lua code", lua_tostring(L, -1));
|
LogLuaError("lua code", lua_tostring(L, -1));
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 2); // pop error and thread
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
lua_pop(L, 1); // pop thread
|
||||||
|
AssertLuaStackIsEmpty(L);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1059,6 +1109,7 @@ static bool LuaOnClientConnection(void) {
|
||||||
uint32_t ip, serverip;
|
uint32_t ip, serverip;
|
||||||
uint16_t port, serverport;
|
uint16_t port, serverport;
|
||||||
lua_State *L = GL;
|
lua_State *L = GL;
|
||||||
|
lua_State *C = lua_newthread(L);
|
||||||
lua_getglobal(L, "OnClientConnection");
|
lua_getglobal(L, "OnClientConnection");
|
||||||
GetClientAddr(&ip, &port);
|
GetClientAddr(&ip, &port);
|
||||||
GetServerAddr(&serverip, &serverport);
|
GetServerAddr(&serverip, &serverport);
|
||||||
|
@ -1066,13 +1117,15 @@ static bool LuaOnClientConnection(void) {
|
||||||
lua_pushinteger(L, port);
|
lua_pushinteger(L, port);
|
||||||
lua_pushinteger(L, serverip);
|
lua_pushinteger(L, serverip);
|
||||||
lua_pushinteger(L, serverport);
|
lua_pushinteger(L, serverport);
|
||||||
if (LuaCallWithTrace(L, 4, 1) == LUA_OK) {
|
if (LuaCallWithTrace(L, C, 4, 1) == LUA_OK) {
|
||||||
dropit = lua_toboolean(L, -1);
|
dropit = lua_toboolean(L, -1);
|
||||||
} else {
|
} else {
|
||||||
LogLuaError("OnClientConnection", lua_tostring(L, -1));
|
LogLuaError("OnClientConnection", lua_tostring(L, -1));
|
||||||
|
lua_pop(L, 1); // pop error
|
||||||
dropit = false;
|
dropit = false;
|
||||||
}
|
}
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1); // pop thread
|
||||||
|
AssertLuaStackIsEmpty(L);
|
||||||
return dropit;
|
return dropit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1080,6 +1133,7 @@ static void LuaOnProcessCreate(int pid) {
|
||||||
uint32_t ip, serverip;
|
uint32_t ip, serverip;
|
||||||
uint16_t port, serverport;
|
uint16_t port, serverport;
|
||||||
lua_State *L = GL;
|
lua_State *L = GL;
|
||||||
|
lua_State *C = lua_newthread(L);
|
||||||
lua_getglobal(L, "OnProcessCreate");
|
lua_getglobal(L, "OnProcessCreate");
|
||||||
GetClientAddr(&ip, &port);
|
GetClientAddr(&ip, &port);
|
||||||
GetServerAddr(&serverip, &serverport);
|
GetServerAddr(&serverip, &serverport);
|
||||||
|
@ -1088,20 +1142,25 @@ static void LuaOnProcessCreate(int pid) {
|
||||||
lua_pushinteger(L, port);
|
lua_pushinteger(L, port);
|
||||||
lua_pushinteger(L, serverip);
|
lua_pushinteger(L, serverip);
|
||||||
lua_pushinteger(L, serverport);
|
lua_pushinteger(L, serverport);
|
||||||
if (LuaCallWithTrace(L, 5, 0) != LUA_OK) {
|
if (LuaCallWithTrace(L, C, 5, 0) != LUA_OK) {
|
||||||
LogLuaError("OnProcessCreate", lua_tostring(L, -1));
|
LogLuaError("OnProcessCreate", lua_tostring(L, -1));
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1); // pop error
|
||||||
}
|
}
|
||||||
|
lua_pop(L, 1); // pop thread
|
||||||
|
AssertLuaStackIsEmpty(L);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void LuaOnProcessDestroy(int pid) {
|
static void LuaOnProcessDestroy(int pid) {
|
||||||
lua_State *L = GL;
|
lua_State *L = GL;
|
||||||
|
lua_State *C = lua_newthread(L);
|
||||||
lua_getglobal(L, "OnProcessDestroy");
|
lua_getglobal(L, "OnProcessDestroy");
|
||||||
lua_pushinteger(L, pid);
|
lua_pushinteger(L, pid);
|
||||||
if (LuaCallWithTrace(L, 1, 0) != LUA_OK) {
|
if (LuaCallWithTrace(L, C, 1, 0) != LUA_OK) {
|
||||||
LogLuaError("OnProcessDestroy", lua_tostring(L, -1));
|
LogLuaError("OnProcessDestroy", lua_tostring(L, -1));
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1); // pop error
|
||||||
}
|
}
|
||||||
|
lua_pop(L, 1); // pop thread
|
||||||
|
AssertLuaStackIsEmpty(L);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool IsHookDefined(const char *s) {
|
static inline bool IsHookDefined(const char *s) {
|
||||||
|
@ -1117,11 +1176,14 @@ static inline bool IsHookDefined(const char *s) {
|
||||||
|
|
||||||
static void CallSimpleHook(const char *s) {
|
static void CallSimpleHook(const char *s) {
|
||||||
lua_State *L = GL;
|
lua_State *L = GL;
|
||||||
|
lua_State *C = lua_newthread(L);
|
||||||
lua_getglobal(L, s);
|
lua_getglobal(L, s);
|
||||||
if (LuaCallWithTrace(L, 0, 0) != LUA_OK) {
|
if (LuaCallWithTrace(L, C, 0, 0) != LUA_OK) {
|
||||||
LogLuaError(s, lua_tostring(L, -1));
|
LogLuaError(s, lua_tostring(L, -1));
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1); // pop error
|
||||||
}
|
}
|
||||||
|
lua_pop(L, 1); // pop thread
|
||||||
|
AssertLuaStackIsEmpty(L);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void CallSimpleHookIfDefined(const char *s) {
|
static void CallSimpleHookIfDefined(const char *s) {
|
||||||
|
@ -1384,7 +1446,7 @@ static void NotifyClose(void) {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void WipeKeySigningKeys(void) {
|
static void WipeSigningKeys(void) {
|
||||||
size_t i;
|
size_t i;
|
||||||
if (uniprocess) return;
|
if (uniprocess) return;
|
||||||
for (i = 0; i < certs.n; ++i) {
|
for (i = 0; i < certs.n; ++i) {
|
||||||
|
@ -1396,15 +1458,36 @@ static void WipeKeySigningKeys(void) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void PsksDestroy(void) {
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; i < psks.n; ++i) {
|
||||||
|
mbedtls_platform_zeroize(psks.p[i].key, psks.p[i].key_len);
|
||||||
|
free(psks.p[i].key);
|
||||||
|
free(psks.p[i].identity);
|
||||||
|
}
|
||||||
|
Free(&psks.p);
|
||||||
|
psks.n = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void CertsDestroy(void) {
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; i < certs.n; ++i) {
|
||||||
|
mbedtls_x509_crt_free(certs.p[i].cert);
|
||||||
|
free(certs.p[i].cert);
|
||||||
|
mbedtls_pk_free(certs.p[i].key);
|
||||||
|
free(certs.p[i].key);
|
||||||
|
}
|
||||||
|
Free(&certs.p);
|
||||||
|
certs.n = 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void WipeServingKeys(void) {
|
static void WipeServingKeys(void) {
|
||||||
size_t i;
|
size_t i;
|
||||||
if (uniprocess) return;
|
if (uniprocess) return;
|
||||||
/* TODO(jart): We need to figure out MbedTLS ownership semantics here. */
|
mbedtls_ssl_ticket_free(&ssltick);
|
||||||
/* mbedtls_ssl_ticket_free(&ssltick); */
|
mbedtls_ssl_key_cert_free(conf.key_cert), conf.key_cert = 0;
|
||||||
/* mbedtls_ssl_key_cert_free(conf.key_cert); */
|
CertsDestroy();
|
||||||
for (i = 0; i < psks.n; ++i) {
|
PsksDestroy();
|
||||||
mbedtls_platform_zeroize(psks.p[i].key, psks.p[i].key_len);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CertHasCommonName(const mbedtls_x509_crt *cert, const void *s, size_t n) {
|
bool CertHasCommonName(const mbedtls_x509_crt *cert, const void *s, size_t n) {
|
||||||
|
@ -1479,7 +1562,7 @@ static int TlsRoutePsk(void *ctx, mbedtls_ssl_context *ssl,
|
||||||
DEBUGF("(ssl) TlsRoutePsk(%`'.*s)", identity_len, identity);
|
DEBUGF("(ssl) TlsRoutePsk(%`'.*s)", identity_len, identity);
|
||||||
mbedtls_ssl_set_hs_psk(ssl, psks.p[i].key, psks.p[i].key_len);
|
mbedtls_ssl_set_hs_psk(ssl, psks.p[i].key, psks.p[i].key_len);
|
||||||
// keep track of selected psk to report its identity
|
// keep track of selected psk to report its identity
|
||||||
sslpskindex = i+1; // use index+1 to check against 0 (when not set)
|
sslpskindex = i + 1; // use index+1 to check against 0 (when not set)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1511,7 +1594,9 @@ static bool TlsSetup(void) {
|
||||||
VERBOSEF("(ssl) shaken %s %s %s%s %s", DescribeClient(),
|
VERBOSEF("(ssl) shaken %s %s %s%s %s", DescribeClient(),
|
||||||
mbedtls_ssl_get_ciphersuite(&ssl), mbedtls_ssl_get_version(&ssl),
|
mbedtls_ssl_get_ciphersuite(&ssl), mbedtls_ssl_get_version(&ssl),
|
||||||
ssl.session->compression ? " COMPRESSED" : "",
|
ssl.session->compression ? " COMPRESSED" : "",
|
||||||
ssl.curve ? ssl.curve->name : "");
|
ssl.curve ? ssl.curve->name : "uncurved");
|
||||||
|
DEBUGF("(ssl) client ciphersuite preference was %s",
|
||||||
|
gc(FormatSslClientCiphers(&ssl)));
|
||||||
return true;
|
return true;
|
||||||
} else if (r == MBEDTLS_ERR_SSL_WANT_READ) {
|
} else if (r == MBEDTLS_ERR_SSL_WANT_READ) {
|
||||||
LockInc(&shared->c.handshakeinterrupts);
|
LockInc(&shared->c.handshakeinterrupts);
|
||||||
|
@ -1534,15 +1619,18 @@ static bool TlsSetup(void) {
|
||||||
return false;
|
return false;
|
||||||
case MBEDTLS_ERR_SSL_NO_CIPHER_CHOSEN:
|
case MBEDTLS_ERR_SSL_NO_CIPHER_CHOSEN:
|
||||||
LockInc(&shared->c.sslnociphers);
|
LockInc(&shared->c.sslnociphers);
|
||||||
WARNF("(ssl) %s %s", DescribeClient(), "sslnociphers");
|
WARNF("(ssl) %s %s %s", DescribeClient(), "sslnociphers",
|
||||||
|
gc(FormatSslClientCiphers(&ssl)));
|
||||||
return false;
|
return false;
|
||||||
case MBEDTLS_ERR_SSL_NO_USABLE_CIPHERSUITE:
|
case MBEDTLS_ERR_SSL_NO_USABLE_CIPHERSUITE:
|
||||||
LockInc(&shared->c.sslcantciphers);
|
LockInc(&shared->c.sslcantciphers);
|
||||||
WARNF("(ssl) %s %s", DescribeClient(), "sslcantciphers");
|
WARNF("(ssl) %s %s %s", DescribeClient(), "sslcantciphers",
|
||||||
|
gc(FormatSslClientCiphers(&ssl)));
|
||||||
return false;
|
return false;
|
||||||
case MBEDTLS_ERR_SSL_BAD_HS_PROTOCOL_VERSION:
|
case MBEDTLS_ERR_SSL_BAD_HS_PROTOCOL_VERSION:
|
||||||
LockInc(&shared->c.sslnoversion);
|
LockInc(&shared->c.sslnoversion);
|
||||||
WARNF("(ssl) %s %s", DescribeClient(), "sslnoversion");
|
WARNF("(ssl) %s %s %s", DescribeClient(), "sslnoversion",
|
||||||
|
mbedtls_ssl_get_version(&ssl));
|
||||||
return false;
|
return false;
|
||||||
case MBEDTLS_ERR_SSL_INVALID_MAC:
|
case MBEDTLS_ERR_SSL_INVALID_MAC:
|
||||||
LockInc(&shared->c.sslshakemacs);
|
LockInc(&shared->c.sslshakemacs);
|
||||||
|
@ -1749,7 +1837,7 @@ static void LoadCertificates(void) {
|
||||||
AppendCert(rsa.cert, rsa.key);
|
AppendCert(rsa.cert, rsa.key);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
WipeKeySigningKeys();
|
WipeSigningKeys();
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool ClientAcceptsGzip(void) {
|
static bool ClientAcceptsGzip(void) {
|
||||||
|
@ -1801,15 +1889,10 @@ static inline unsigned Hash(const void *p, unsigned long n) {
|
||||||
return MAX(1, h);
|
return MAX(1, h);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Free(void *p) {
|
|
||||||
free(*(void **)p);
|
|
||||||
*(void **)p = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void FreeAssets(void) {
|
static void FreeAssets(void) {
|
||||||
size_t i;
|
size_t i;
|
||||||
for (i = 0; i < assets.n; ++i) {
|
for (i = 0; i < assets.n; ++i) {
|
||||||
free(assets.p[i].lastmodifiedstr);
|
Free(&assets.p[i].lastmodifiedstr);
|
||||||
}
|
}
|
||||||
Free(&assets.p);
|
Free(&assets.p);
|
||||||
assets.n = 0;
|
assets.n = 0;
|
||||||
|
@ -1818,7 +1901,7 @@ static void FreeAssets(void) {
|
||||||
static void FreeStrings(struct Strings *l) {
|
static void FreeStrings(struct Strings *l) {
|
||||||
size_t i;
|
size_t i;
|
||||||
for (i = 0; i < l->n; ++i) {
|
for (i = 0; i < l->n; ++i) {
|
||||||
free(l->p[i].s);
|
Free(&l->p[i].s);
|
||||||
}
|
}
|
||||||
Free(&l->p);
|
Free(&l->p);
|
||||||
l->n = 0;
|
l->n = 0;
|
||||||
|
@ -1830,6 +1913,7 @@ static void IndexAssets(void) {
|
||||||
struct timespec lm;
|
struct timespec lm;
|
||||||
uint32_t i, n, m, step, hash;
|
uint32_t i, n, m, step, hash;
|
||||||
DEBUGF("(zip) indexing assets (inode %#lx)", zst.st_ino);
|
DEBUGF("(zip) indexing assets (inode %#lx)", zst.st_ino);
|
||||||
|
FreeAssets();
|
||||||
CHECK_GE(HASH_LOAD_FACTOR, 2);
|
CHECK_GE(HASH_LOAD_FACTOR, 2);
|
||||||
CHECK(READ32LE(zcdir) == kZipCdir64HdrMagic ||
|
CHECK(READ32LE(zcdir) == kZipCdir64HdrMagic ||
|
||||||
READ32LE(zcdir) == kZipCdirHdrMagic);
|
READ32LE(zcdir) == kZipCdirHdrMagic);
|
||||||
|
@ -2214,7 +2298,7 @@ static char *ServeDefaultErrorPage(char *p, unsigned code, const char *reason,
|
||||||
<!doctype html>\r\n\
|
<!doctype html>\r\n\
|
||||||
<title>");
|
<title>");
|
||||||
appendf(&outbuf, "%d %s", code, reason);
|
appendf(&outbuf, "%d %s", code, reason);
|
||||||
appendf(&outbuf, "\
|
appends(&outbuf, "\
|
||||||
</title>\r\n\
|
</title>\r\n\
|
||||||
<style>\r\n\
|
<style>\r\n\
|
||||||
html { color: #111; font-family: sans-serif; }\r\n\
|
html { color: #111; font-family: sans-serif; }\r\n\
|
||||||
|
@ -2556,8 +2640,8 @@ static void LaunchBrowser(const char *path) {
|
||||||
if (!servers.n || !addr.s_addr) addr.s_addr = htonl(INADDR_LOOPBACK);
|
if (!servers.n || !addr.s_addr) addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||||
if (*path != '/') path = gc(xasprintf("/%s", path));
|
if (*path != '/') path = gc(xasprintf("/%s", path));
|
||||||
if ((prog = commandv(GetSystemUrlLauncherCommand(), gc(malloc(PATH_MAX))))) {
|
if ((prog = commandv(GetSystemUrlLauncherCommand(), gc(malloc(PATH_MAX))))) {
|
||||||
u = gc(xasprintf("http://%s:%d%s", inet_ntoa(addr),
|
u = gc(xasprintf("http://%s:%d%s", inet_ntoa(addr), port,
|
||||||
port, gc(EscapePath(path, -1, 0))));
|
gc(EscapePath(path, -1, 0))));
|
||||||
DEBUGF("(srvr) opening browser with command %`'s %s", prog, u);
|
DEBUGF("(srvr) opening browser with command %`'s %s", prog, u);
|
||||||
ignore.sa_flags = 0;
|
ignore.sa_flags = 0;
|
||||||
ignore.sa_handler = SIG_IGN;
|
ignore.sa_handler = SIG_IGN;
|
||||||
|
@ -2861,19 +2945,23 @@ static bool IsLoopbackClient() {
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *LuaOnHttpRequest(void) {
|
static char *LuaOnHttpRequest(void) {
|
||||||
|
char *error;
|
||||||
lua_State *L = GL;
|
lua_State *L = GL;
|
||||||
|
lua_State *C = lua_newthread(L);
|
||||||
effectivepath.p = url.path.p;
|
effectivepath.p = url.path.p;
|
||||||
effectivepath.n = url.path.n;
|
effectivepath.n = url.path.n;
|
||||||
lua_getglobal(L, "OnHttpRequest");
|
lua_getglobal(L, "OnHttpRequest");
|
||||||
if (LuaCallWithTrace(L, 0, 0) == LUA_OK) {
|
if (LuaCallWithTrace(L, C, 0, 0) == LUA_OK) {
|
||||||
|
lua_pop(L, 1); // pop thread
|
||||||
|
AssertLuaStackIsEmpty(L);
|
||||||
return CommitOutput(GetLuaResponse());
|
return CommitOutput(GetLuaResponse());
|
||||||
} else {
|
} else {
|
||||||
char *error;
|
|
||||||
LogLuaError("OnHttpRequest", lua_tostring(L, -1));
|
LogLuaError("OnHttpRequest", lua_tostring(L, -1));
|
||||||
error =
|
error =
|
||||||
ServeErrorWithDetail(500, "Internal Server Error",
|
ServeErrorWithDetail(500, "Internal Server Error",
|
||||||
IsLoopbackClient() ? lua_tostring(L, -1) : NULL);
|
IsLoopbackClient() ? lua_tostring(L, -1) : NULL);
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 2); // pop error and thread
|
||||||
|
AssertLuaStackIsEmpty(L);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2882,6 +2970,7 @@ static char *ServeLua(struct Asset *a, const char *s, size_t n) {
|
||||||
char *code;
|
char *code;
|
||||||
size_t codelen;
|
size_t codelen;
|
||||||
lua_State *L = GL;
|
lua_State *L = GL;
|
||||||
|
lua_State *C = lua_newthread(L);
|
||||||
LockInc(&shared->c.dynamicrequests);
|
LockInc(&shared->c.dynamicrequests);
|
||||||
effectivepath.p = s;
|
effectivepath.p = s;
|
||||||
effectivepath.n = n;
|
effectivepath.n = n;
|
||||||
|
@ -2889,7 +2978,8 @@ static char *ServeLua(struct Asset *a, const char *s, size_t n) {
|
||||||
int status =
|
int status =
|
||||||
luaL_loadbuffer(L, code, codelen,
|
luaL_loadbuffer(L, code, codelen,
|
||||||
FreeLater(xasprintf("@%s", FreeLater(strndup(s, n)))));
|
FreeLater(xasprintf("@%s", FreeLater(strndup(s, n)))));
|
||||||
if (status == LUA_OK && LuaCallWithTrace(L, 0, 0) == LUA_OK) {
|
if (status == LUA_OK && LuaCallWithTrace(L, C, 0, 0) == LUA_OK) {
|
||||||
|
lua_pop(L, 1); // pop thread
|
||||||
return CommitOutput(GetLuaResponse());
|
return CommitOutput(GetLuaResponse());
|
||||||
} else {
|
} else {
|
||||||
char *error;
|
char *error;
|
||||||
|
@ -2897,7 +2987,7 @@ static char *ServeLua(struct Asset *a, const char *s, size_t n) {
|
||||||
error =
|
error =
|
||||||
ServeErrorWithDetail(500, "Internal Server Error",
|
ServeErrorWithDetail(500, "Internal Server Error",
|
||||||
IsLoopbackClient() ? lua_tostring(L, -1) : NULL);
|
IsLoopbackClient() ? lua_tostring(L, -1) : NULL);
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 2); // pop error and thread
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3143,10 +3233,11 @@ static int LuaSetStatus(lua_State *L) {
|
||||||
|
|
||||||
static int LuaGetStatus(lua_State *L) {
|
static int LuaGetStatus(lua_State *L) {
|
||||||
OnlyCallDuringRequest(L, "GetStatus");
|
OnlyCallDuringRequest(L, "GetStatus");
|
||||||
if (!luaheaderp)
|
if (!luaheaderp) {
|
||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
else
|
} else {
|
||||||
lua_pushinteger(L, statuscode);
|
lua_pushinteger(L, statuscode);
|
||||||
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3157,9 +3248,9 @@ static int LuaGetSslIdentity(lua_State *L) {
|
||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
} else {
|
} else {
|
||||||
if (sslpskindex) {
|
if (sslpskindex) {
|
||||||
CHECK((sslpskindex-1) >= 0 && (sslpskindex-1) < psks.n);
|
CHECK((sslpskindex - 1) >= 0 && (sslpskindex - 1) < psks.n);
|
||||||
lua_pushlstring(L, psks.p[sslpskindex-1].identity,
|
lua_pushlstring(L, psks.p[sslpskindex - 1].identity,
|
||||||
psks.p[sslpskindex-1].identity_len);
|
psks.p[sslpskindex - 1].identity_len);
|
||||||
} else {
|
} else {
|
||||||
cert = mbedtls_ssl_get_peer_cert(&ssl);
|
cert = mbedtls_ssl_get_peer_cert(&ssl);
|
||||||
lua_pushstring(L, cert ? gc(FormatX509Name(&cert->subject)) : "");
|
lua_pushstring(L, cert ? gc(FormatX509Name(&cert->subject)) : "");
|
||||||
|
@ -3168,7 +3259,6 @@ static int LuaGetSslIdentity(lua_State *L) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int LuaServeError(lua_State *L) {
|
static int LuaServeError(lua_State *L) {
|
||||||
return LuaRespond(L, ServeError);
|
return LuaRespond(L, ServeError);
|
||||||
}
|
}
|
||||||
|
@ -3211,7 +3301,7 @@ static void GetDosLocalTime(int64_t utcunixts, uint16_t *out_time,
|
||||||
}
|
}
|
||||||
|
|
||||||
static void StoreAsset(char *path, size_t pathlen, char *data, size_t datalen,
|
static void StoreAsset(char *path, size_t pathlen, char *data, size_t datalen,
|
||||||
int mode) {
|
int mode) {
|
||||||
int64_t ft;
|
int64_t ft;
|
||||||
int i;
|
int i;
|
||||||
uint32_t crc;
|
uint32_t crc;
|
||||||
|
@ -3306,9 +3396,9 @@ static void StoreAsset(char *path, size_t pathlen, char *data, size_t datalen,
|
||||||
v[4].iov_len = a->cf - oldcdiroffset;
|
v[4].iov_len = a->cf - oldcdiroffset;
|
||||||
// and then the rest of the central directory
|
// and then the rest of the central directory
|
||||||
v[5].iov_base = zbase + oldcdiroffset +
|
v[5].iov_base = zbase + oldcdiroffset +
|
||||||
(v[4].iov_len + ZIP_CFILE_HDRSIZE(zbase + a->cf));
|
(v[4].iov_len + ZIP_CFILE_HDRSIZE(zbase + a->cf));
|
||||||
v[5].iov_len = oldcdirsize -
|
v[5].iov_len =
|
||||||
(v[4].iov_len + ZIP_CFILE_HDRSIZE(zbase + a->cf));
|
oldcdirsize - (v[4].iov_len + ZIP_CFILE_HDRSIZE(zbase + a->cf));
|
||||||
} else {
|
} else {
|
||||||
v[4].iov_base = zbase + oldcdiroffset;
|
v[4].iov_base = zbase + oldcdiroffset;
|
||||||
v[4].iov_len = oldcdirsize;
|
v[4].iov_len = oldcdirsize;
|
||||||
|
@ -3567,9 +3657,9 @@ static int LuaFetch(lua_State *L) {
|
||||||
int t, ret, sock, methodidx;
|
int t, ret, sock, methodidx;
|
||||||
char *host, *port;
|
char *host, *port;
|
||||||
struct TlsBio *bio;
|
struct TlsBio *bio;
|
||||||
struct Buffer inbuf;
|
|
||||||
struct addrinfo *addr;
|
struct addrinfo *addr;
|
||||||
struct HttpMessage msg;
|
struct Buffer inbuf; // shadowing intentional
|
||||||
|
struct HttpMessage msg; // shadowing intentional
|
||||||
struct HttpUnchunker u;
|
struct HttpUnchunker u;
|
||||||
const char *urlarg, *request, *body, *method;
|
const char *urlarg, *request, *body, *method;
|
||||||
char *conlenhdr = "";
|
char *conlenhdr = "";
|
||||||
|
@ -3697,11 +3787,14 @@ static int LuaFetch(lua_State *L) {
|
||||||
ip >> 8, ip, ntohs(((struct sockaddr_in *)addr->ai_addr)->sin_port));
|
ip >> 8, ip, ntohs(((struct sockaddr_in *)addr->ai_addr)->sin_port));
|
||||||
CHECK_NE(-1, (sock = GoodSocket(addr->ai_family, addr->ai_socktype,
|
CHECK_NE(-1, (sock = GoodSocket(addr->ai_family, addr->ai_socktype,
|
||||||
addr->ai_protocol, false, &timeout)));
|
addr->ai_protocol, false, &timeout)));
|
||||||
if (connect(sock, addr->ai_addr, addr->ai_addrlen) == -1) {
|
rc = connect(sock, addr->ai_addr, addr->ai_addrlen);
|
||||||
|
freeaddrinfo(addr), addr = 0;
|
||||||
|
if (rc == -1) {
|
||||||
close(sock);
|
close(sock);
|
||||||
luaL_error(L, "connect(%s:%s) error: %s", host, port, strerror(errno));
|
luaL_error(L, "connect(%s:%s) error: %s", host, port, strerror(errno));
|
||||||
unreachable;
|
unreachable;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (usessl) {
|
if (usessl) {
|
||||||
if (sslcliused) {
|
if (sslcliused) {
|
||||||
mbedtls_ssl_session_reset(&sslcli);
|
mbedtls_ssl_session_reset(&sslcli);
|
||||||
|
@ -3728,6 +3821,7 @@ static int LuaFetch(lua_State *L) {
|
||||||
default:
|
default:
|
||||||
close(sock);
|
close(sock);
|
||||||
LuaThrowTlsError(L, "handshake", ret);
|
LuaThrowTlsError(L, "handshake", ret);
|
||||||
|
unreachable;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LockInc(&shared->c.sslhandshakes);
|
LockInc(&shared->c.sslhandshakes);
|
||||||
|
@ -3746,6 +3840,7 @@ static int LuaFetch(lua_State *L) {
|
||||||
if (ret == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED) goto VerifyFailed;
|
if (ret == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED) goto VerifyFailed;
|
||||||
close(sock);
|
close(sock);
|
||||||
LuaThrowTlsError(L, "write", ret);
|
LuaThrowTlsError(L, "write", ret);
|
||||||
|
unreachable;
|
||||||
}
|
}
|
||||||
} else if (write(sock, request, requestlen) != requestlen) {
|
} else if (write(sock, request, requestlen) != requestlen) {
|
||||||
close(sock);
|
close(sock);
|
||||||
|
@ -3778,6 +3873,7 @@ static int LuaFetch(lua_State *L) {
|
||||||
free(inbuf.p);
|
free(inbuf.p);
|
||||||
DestroyHttpMessage(&msg);
|
DestroyHttpMessage(&msg);
|
||||||
LuaThrowTlsError(L, "read", rc);
|
LuaThrowTlsError(L, "read", rc);
|
||||||
|
unreachable;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if ((rc = read(sock, inbuf.p + inbuf.n, inbuf.c - inbuf.n)) == -1) {
|
} else if ((rc = read(sock, inbuf.p + inbuf.n, inbuf.c - inbuf.n)) == -1) {
|
||||||
|
@ -3925,9 +4021,9 @@ Finished:
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
TransportError:
|
TransportError:
|
||||||
close(sock);
|
|
||||||
free(inbuf.p);
|
|
||||||
DestroyHttpMessage(&msg);
|
DestroyHttpMessage(&msg);
|
||||||
|
free(inbuf.p);
|
||||||
|
close(sock);
|
||||||
luaL_error(L, "transport error");
|
luaL_error(L, "transport error");
|
||||||
unreachable;
|
unreachable;
|
||||||
VerifyFailed:
|
VerifyFailed:
|
||||||
|
@ -3936,6 +4032,7 @@ VerifyFailed:
|
||||||
LuaThrowTlsError(
|
LuaThrowTlsError(
|
||||||
L, gc(DescribeSslVerifyFailure(sslcli.session_negotiate->verify_result)),
|
L, gc(DescribeSslVerifyFailure(sslcli.session_negotiate->verify_result)),
|
||||||
ret);
|
ret);
|
||||||
|
unreachable;
|
||||||
#undef ssl
|
#undef ssl
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4739,7 +4836,8 @@ static int LuaGetHttpReason(lua_State *L) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int EncodeJsonData(lua_State *L, char **buf, int level, char *numformat) {
|
static int EncodeJsonData(lua_State *L, char **buf, int level,
|
||||||
|
char *numformat) {
|
||||||
size_t idx = -1;
|
size_t idx = -1;
|
||||||
size_t tbllen, buflen;
|
size_t tbllen, buflen;
|
||||||
bool isarray;
|
bool isarray;
|
||||||
|
@ -4756,20 +4854,20 @@ static int EncodeJsonData(lua_State *L, char **buf, int level, char *numformat)
|
||||||
} else if (LUA_TTABLE == t) {
|
} else if (LUA_TTABLE == t) {
|
||||||
tbllen = lua_rawlen(L, idx);
|
tbllen = lua_rawlen(L, idx);
|
||||||
// encode tables with numeric indices and empty tables as arrays
|
// encode tables with numeric indices and empty tables as arrays
|
||||||
isarray = tbllen > 0 || // integer keys present
|
isarray = tbllen > 0 || // integer keys present
|
||||||
(lua_pushnil(L), lua_next(L, -2) == 0) || // no non-integer keys
|
(lua_pushnil(L), lua_next(L, -2) == 0) || // no non-integer keys
|
||||||
(lua_pop(L, 2), false); // pop key/value pushed by lua_next
|
(lua_pop(L, 2), false); // pop key/value pushed by lua_next
|
||||||
appendw(buf, isarray ? '[' : '{');
|
appendw(buf, isarray ? '[' : '{');
|
||||||
if (isarray) {
|
if (isarray) {
|
||||||
for (int i = 1; i <= tbllen; i++) {
|
for (int i = 1; i <= tbllen; i++) {
|
||||||
if (i > 1) appendw(buf, ',');
|
if (i > 1) appendw(buf, ',');
|
||||||
lua_rawgeti(L, -1, i); // table/-2, value/-1
|
lua_rawgeti(L, -1, i); // table/-2, value/-1
|
||||||
EncodeJsonData(L, buf, level-1, numformat);
|
EncodeJsonData(L, buf, level - 1, numformat);
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
int i = 1;
|
int i = 1;
|
||||||
lua_pushnil(L); // push the first key
|
lua_pushnil(L); // push the first key
|
||||||
while (lua_next(L, -2) != 0) {
|
while (lua_next(L, -2) != 0) {
|
||||||
if (!lua_isstring(L, -2))
|
if (!lua_isstring(L, -2))
|
||||||
return luaL_argerror(L, 1, "expected number or string as key value");
|
return luaL_argerror(L, 1, "expected number or string as key value");
|
||||||
|
@ -4779,14 +4877,15 @@ static int EncodeJsonData(lua_State *L, char **buf, int level, char *numformat)
|
||||||
appends(buf, gc(EscapeJsStringLiteral(lua_tostring(L, -2), -1, 0)));
|
appends(buf, gc(EscapeJsStringLiteral(lua_tostring(L, -2), -1, 0)));
|
||||||
} else {
|
} else {
|
||||||
// we'd still prefer to use lua_tostring on a numeric index, but can't
|
// we'd still prefer to use lua_tostring on a numeric index, but can't
|
||||||
// use it in-place, as it breaks lua_next (changes numeric key to a string)
|
// use it in-place, as it breaks lua_next (changes numeric key to a
|
||||||
lua_pushvalue(L, -2); // table/-4, key/-3, value/-2, key/-1
|
// string)
|
||||||
appends(buf, lua_tostring(L, idx)); // use the copy
|
lua_pushvalue(L, -2); // table/-4, key/-3, value/-2, key/-1
|
||||||
lua_remove(L, -1); // remove copied key: table/-3, key/-2, value/-1
|
appends(buf, lua_tostring(L, idx)); // use the copy
|
||||||
|
lua_remove(L, -1); // remove copied key: table/-3, key/-2, value/-1
|
||||||
}
|
}
|
||||||
appendw(buf, '"' | ':' << 010);
|
appendw(buf, '"' | ':' << 010);
|
||||||
EncodeJsonData(L, buf, level-1, numformat);
|
EncodeJsonData(L, buf, level - 1, numformat);
|
||||||
lua_pop(L, 1); // table/-2, key/-1
|
lua_pop(L, 1); // table/-2, key/-1
|
||||||
}
|
}
|
||||||
// stack: table/-1, as the key was popped by lua_next
|
// stack: table/-1, as the key was popped by lua_next
|
||||||
}
|
}
|
||||||
|
@ -4802,13 +4901,13 @@ static int EncodeJsonData(lua_State *L, char **buf, int level, char *numformat)
|
||||||
static void EscapeLuaString(char *s, size_t len, char **buf) {
|
static void EscapeLuaString(char *s, size_t len, char **buf) {
|
||||||
appendw(buf, '"');
|
appendw(buf, '"');
|
||||||
for (size_t i = 0; i < len; i++) {
|
for (size_t i = 0; i < len; i++) {
|
||||||
if (s[i] == '\\' || s[i] == '\"' || s[i] == '\n' ||
|
if (s[i] == '\\' || s[i] == '\"' || s[i] == '\n' || s[i] == '\0' ||
|
||||||
s[i] == '\0' || s[i] == '\r') {
|
s[i] == '\r') {
|
||||||
appendw(buf, '\\' | 'x' << 010 |
|
appendw(buf, '\\' | 'x' << 010 |
|
||||||
"0123456789abcdef"[(s[i] & 0xF0) >> 4] << 020 |
|
"0123456789abcdef"[(s[i] & 0xF0) >> 4] << 020 |
|
||||||
"0123456789abcdef"[(s[i] & 0x0F) >> 0] << 030);
|
"0123456789abcdef"[(s[i] & 0x0F) >> 0] << 030);
|
||||||
} else {
|
} else {
|
||||||
appendd(buf, s+i, 1);
|
appendd(buf, s + i, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
appendw(buf, '"');
|
appendw(buf, '"');
|
||||||
|
@ -4831,7 +4930,7 @@ static int EncodeLuaData(lua_State *L, char **buf, int level, char *numformat) {
|
||||||
} else if (LUA_TTABLE == t) {
|
} else if (LUA_TTABLE == t) {
|
||||||
appendw(buf, '{');
|
appendw(buf, '{');
|
||||||
int i = 0;
|
int i = 0;
|
||||||
lua_pushnil(L); // push the first key
|
lua_pushnil(L); // push the first key
|
||||||
while (lua_next(L, -2) != 0) {
|
while (lua_next(L, -2) != 0) {
|
||||||
ktype = lua_type(L, -2);
|
ktype = lua_type(L, -2);
|
||||||
if (ktype == LUA_TTABLE)
|
if (ktype == LUA_TTABLE)
|
||||||
|
@ -4839,13 +4938,13 @@ static int EncodeLuaData(lua_State *L, char **buf, int level, char *numformat) {
|
||||||
if (i++ > 0) appendd(buf, ",", 1);
|
if (i++ > 0) appendd(buf, ",", 1);
|
||||||
if (ktype != LUA_TNUMBER || floor(lua_tonumber(L, -2)) != i) {
|
if (ktype != LUA_TNUMBER || floor(lua_tonumber(L, -2)) != i) {
|
||||||
appendw(buf, '[');
|
appendw(buf, '[');
|
||||||
lua_pushvalue(L, -2); // table/-4, key/-3, value/-2, key/-1
|
lua_pushvalue(L, -2); // table/-4, key/-3, value/-2, key/-1
|
||||||
EncodeLuaData(L, buf, level, numformat);
|
EncodeLuaData(L, buf, level, numformat);
|
||||||
lua_remove(L, -1); // remove copied key: table/-3, key/-2, value/-1
|
lua_remove(L, -1); // remove copied key: table/-3, key/-2, value/-1
|
||||||
appendw(buf, ']' | '=' << 010);
|
appendw(buf, ']' | '=' << 010);
|
||||||
}
|
}
|
||||||
EncodeLuaData(L, buf, level-1, numformat);
|
EncodeLuaData(L, buf, level - 1, numformat);
|
||||||
lua_pop(L, 1); // table/-2, key/-1
|
lua_pop(L, 1); // table/-2, key/-1
|
||||||
}
|
}
|
||||||
// stack: table/-1, as the key was popped by lua_next
|
// stack: table/-1, as the key was popped by lua_next
|
||||||
appendw(buf, '}');
|
appendw(buf, '}');
|
||||||
|
@ -4857,25 +4956,25 @@ static int EncodeLuaData(lua_State *L, char **buf, int level, char *numformat) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int LuaEncodeSmth(lua_State *L, int Encoder(lua_State *, char **, int, char *)) {
|
static int LuaEncodeSmth(lua_State *L,
|
||||||
|
int Encoder(lua_State *, char **, int, char *)) {
|
||||||
int useoutput = false;
|
int useoutput = false;
|
||||||
int maxdepth = 64;
|
int maxdepth = 64;
|
||||||
char *numformat = "%.14g";
|
char *numformat = "%.14g";
|
||||||
char *p = 0;
|
char *p = 0;
|
||||||
|
|
||||||
if (lua_istable(L, 2)) {
|
if (lua_istable(L, 2)) {
|
||||||
lua_settop(L, 2); // discard any extra arguments
|
lua_settop(L, 2); // discard any extra arguments
|
||||||
lua_getfield(L, 2, "useoutput");
|
lua_getfield(L, 2, "useoutput");
|
||||||
// ignore useoutput outside of request handling
|
// ignore useoutput outside of request handling
|
||||||
if (ishandlingrequest && lua_isboolean(L, -1)) useoutput = lua_toboolean(L, -1);
|
if (ishandlingrequest && lua_isboolean(L, -1))
|
||||||
|
useoutput = lua_toboolean(L, -1);
|
||||||
lua_getfield(L, 2, "maxdepth");
|
lua_getfield(L, 2, "maxdepth");
|
||||||
maxdepth = luaL_optinteger(L, -1, maxdepth);
|
maxdepth = luaL_optinteger(L, -1, maxdepth);
|
||||||
lua_getfield(L, 2, "numformat");
|
lua_getfield(L, 2, "numformat");
|
||||||
numformat = luaL_optstring(L, -1, numformat);
|
numformat = luaL_optstring(L, -1, numformat);
|
||||||
}
|
}
|
||||||
lua_settop(L, 1); // keep the passed argument on top
|
lua_settop(L, 1); // keep the passed argument on top
|
||||||
Encoder(L, useoutput ? &outbuf : &p, maxdepth, numformat);
|
Encoder(L, useoutput ? &outbuf : &p, maxdepth, numformat);
|
||||||
|
|
||||||
if (useoutput) {
|
if (useoutput) {
|
||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
} else {
|
} else {
|
||||||
|
@ -5035,7 +5134,7 @@ static int LuaProgramUniprocess(lua_State *L) {
|
||||||
return luaL_argerror(L, 1, "invalid uniprocess mode; boolean expected");
|
return luaL_argerror(L, 1, "invalid uniprocess mode; boolean expected");
|
||||||
|
|
||||||
lua_pushboolean(L, uniprocess);
|
lua_pushboolean(L, uniprocess);
|
||||||
if (!IsWindows()) { // uniprocess can't be disabled on Windows yet
|
if (!IsWindows()) { // uniprocess can't be disabled on Windows yet
|
||||||
if (lua_isboolean(L, 1)) uniprocess = lua_toboolean(L, 1);
|
if (lua_isboolean(L, 1)) uniprocess = lua_toboolean(L, 1);
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -5546,16 +5645,18 @@ static bool LuaRunAsset(const char *path, bool mandatory) {
|
||||||
if ((a = GetAsset(path, pathlen))) {
|
if ((a = GetAsset(path, pathlen))) {
|
||||||
if ((code = FreeLater(LoadAsset(a, &codelen)))) {
|
if ((code = FreeLater(LoadAsset(a, &codelen)))) {
|
||||||
lua_State *L = GL;
|
lua_State *L = GL;
|
||||||
|
lua_State *C = lua_newthread(L);
|
||||||
effectivepath.p = path;
|
effectivepath.p = path;
|
||||||
effectivepath.n = pathlen;
|
effectivepath.n = pathlen;
|
||||||
DEBUGF("(lua) LuaRunAsset(%`'s)", path);
|
DEBUGF("(lua) LuaRunAsset(%`'s)", path);
|
||||||
status =
|
status =
|
||||||
luaL_loadbuffer(L, code, codelen, FreeLater(xasprintf("@%s", path)));
|
luaL_loadbuffer(L, code, codelen, FreeLater(xasprintf("@%s", path)));
|
||||||
if (status != LUA_OK || LuaCallWithTrace(L, 0, 0) != LUA_OK) {
|
if (status != LUA_OK || LuaCallWithTrace(L, C, 0, 0) != LUA_OK) {
|
||||||
LogLuaError("lua code", lua_tostring(L, -1));
|
LogLuaError("lua code", lua_tostring(L, -1));
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1); // pop error
|
||||||
if (mandatory) exit(1);
|
if (mandatory) exit(1);
|
||||||
}
|
}
|
||||||
|
lua_pop(L, 1); // pop thread
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return !!a;
|
return !!a;
|
||||||
|
@ -5801,6 +5902,7 @@ static void LuaDestroy(void) {
|
||||||
#ifndef STATIC
|
#ifndef STATIC
|
||||||
lua_State *L = GL;
|
lua_State *L = GL;
|
||||||
lua_close(L);
|
lua_close(L);
|
||||||
|
free(g_lua_path_default);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6417,7 +6519,7 @@ static char *SetStatus(unsigned code, const char *reason) {
|
||||||
if (code == 308) code = 301;
|
if (code == 308) code = 301;
|
||||||
}
|
}
|
||||||
statuscode = code;
|
statuscode = code;
|
||||||
hascontenttype = false; // reset, as the headers are reset
|
hascontenttype = false; // reset, as the headers are reset
|
||||||
stpcpy(hdrbuf.p, "HTTP/1.0 000 ");
|
stpcpy(hdrbuf.p, "HTTP/1.0 000 ");
|
||||||
hdrbuf.p[7] += msg.version & 1;
|
hdrbuf.p[7] += msg.version & 1;
|
||||||
hdrbuf.p[9] += code / 100;
|
hdrbuf.p[9] += code / 100;
|
||||||
|
@ -6783,7 +6885,7 @@ static void HandleConnection(size_t i) {
|
||||||
if (hasonworkerstop) {
|
if (hasonworkerstop) {
|
||||||
CallSimpleHook("OnWorkerStop");
|
CallSimpleHook("OnWorkerStop");
|
||||||
}
|
}
|
||||||
_exit(0);
|
ExitWorker();
|
||||||
} else {
|
} else {
|
||||||
close(client);
|
close(client);
|
||||||
oldin.p = 0;
|
oldin.p = 0;
|
||||||
|
@ -6998,7 +7100,6 @@ static void TlsInit(void) {
|
||||||
if (!sslinitialized) {
|
if (!sslinitialized) {
|
||||||
InitializeRng(&rng);
|
InitializeRng(&rng);
|
||||||
InitializeRng(&rngcli);
|
InitializeRng(&rngcli);
|
||||||
cachain = GetSslRoots();
|
|
||||||
suite = suiteb ? MBEDTLS_SSL_PRESET_SUITEB : MBEDTLS_SSL_PRESET_SUITEC;
|
suite = suiteb ? MBEDTLS_SSL_PRESET_SUITEB : MBEDTLS_SSL_PRESET_SUITEC;
|
||||||
mbedtls_ssl_config_defaults(&conf, MBEDTLS_SSL_IS_SERVER,
|
mbedtls_ssl_config_defaults(&conf, MBEDTLS_SSL_IS_SERVER,
|
||||||
MBEDTLS_SSL_TRANSPORT_STREAM, suite);
|
MBEDTLS_SSL_TRANSPORT_STREAM, suite);
|
||||||
|
@ -7034,11 +7135,11 @@ static void TlsInit(void) {
|
||||||
mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &rng);
|
mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &rng);
|
||||||
mbedtls_ssl_conf_rng(&confcli, mbedtls_ctr_drbg_random, &rngcli);
|
mbedtls_ssl_conf_rng(&confcli, mbedtls_ctr_drbg_random, &rngcli);
|
||||||
if (sslclientverify) {
|
if (sslclientverify) {
|
||||||
mbedtls_ssl_conf_ca_chain(&conf, cachain, 0);
|
mbedtls_ssl_conf_ca_chain(&conf, GetSslRoots(), 0);
|
||||||
mbedtls_ssl_conf_authmode(&conf, MBEDTLS_SSL_VERIFY_REQUIRED);
|
mbedtls_ssl_conf_authmode(&conf, MBEDTLS_SSL_VERIFY_REQUIRED);
|
||||||
}
|
}
|
||||||
if (sslfetchverify) {
|
if (sslfetchverify) {
|
||||||
mbedtls_ssl_conf_ca_chain(&confcli, cachain, 0);
|
mbedtls_ssl_conf_ca_chain(&confcli, GetSslRoots(), 0);
|
||||||
mbedtls_ssl_conf_authmode(&confcli, MBEDTLS_SSL_VERIFY_REQUIRED);
|
mbedtls_ssl_conf_authmode(&confcli, MBEDTLS_SSL_VERIFY_REQUIRED);
|
||||||
} else {
|
} else {
|
||||||
mbedtls_ssl_conf_authmode(&confcli, MBEDTLS_SSL_VERIFY_NONE);
|
mbedtls_ssl_conf_authmode(&confcli, MBEDTLS_SSL_VERIFY_NONE);
|
||||||
|
@ -7054,41 +7155,30 @@ static void TlsInit(void) {
|
||||||
|
|
||||||
static void TlsDestroy(void) {
|
static void TlsDestroy(void) {
|
||||||
#ifndef UNSECURE
|
#ifndef UNSECURE
|
||||||
size_t i;
|
|
||||||
for (i = 0; i < psks.n; ++i) {
|
|
||||||
mbedtls_platform_zeroize(psks.p[i].key, psks.p[i].key_len);
|
|
||||||
free(psks.p[i].key);
|
|
||||||
free(psks.p[i].identity);
|
|
||||||
}
|
|
||||||
mbedtls_ssl_free(&ssl);
|
mbedtls_ssl_free(&ssl);
|
||||||
mbedtls_ssl_free(&sslcli);
|
mbedtls_ssl_free(&sslcli);
|
||||||
mbedtls_ctr_drbg_free(&rng);
|
mbedtls_ctr_drbg_free(&rng);
|
||||||
mbedtls_x509_crt_free(cachain);
|
|
||||||
mbedtls_ctr_drbg_free(&rngcli);
|
mbedtls_ctr_drbg_free(&rngcli);
|
||||||
mbedtls_ssl_config_free(&conf);
|
mbedtls_ssl_config_free(&conf);
|
||||||
mbedtls_ssl_config_free(&confcli);
|
mbedtls_ssl_config_free(&confcli);
|
||||||
mbedtls_ssl_ticket_free(&ssltick);
|
mbedtls_ssl_ticket_free(&ssltick);
|
||||||
/* TODO(jart): We need to learn more about ownership of this memory. */
|
CertsDestroy();
|
||||||
/* for (i = 0; i < certs.n; ++i) { */
|
PsksDestroy();
|
||||||
/* mbedtls_x509_crt_free(certs.p[i].cert); */
|
|
||||||
/* mbedtls_pk_free(certs.p[i].key); */
|
|
||||||
/* } */
|
|
||||||
Free(&suites.p), suites.n = 0;
|
Free(&suites.p), suites.n = 0;
|
||||||
Free(&certs.p), certs.n = 0;
|
|
||||||
Free(&ports.p), ports.n = 0;
|
|
||||||
Free(&psks.p), psks.n = 0;
|
|
||||||
Free(&ips.p), ips.n = 0;
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void MemDestroy(void) {
|
static void MemDestroy(void) {
|
||||||
FreeAssets();
|
FreeAssets();
|
||||||
CollectGarbage();
|
CollectGarbage();
|
||||||
Free(&unmaplist.p), unmaplist.n = 0;
|
inbuf.p = 0, inbuf.n = 0, inbuf.c = 0;
|
||||||
Free(&freelist.p), freelist.n = 0;
|
Free(&inbuf_actual.p), inbuf_actual.n = inbuf_actual.c = 0;
|
||||||
|
Free(&unmaplist.p), unmaplist.n = unmaplist.c = 0;
|
||||||
|
Free(&freelist.p), freelist.n = freelist.c = 0;
|
||||||
|
Free(&hdrbuf.p), hdrbuf.n = hdrbuf.c = 0;
|
||||||
Free(&servers.p), servers.n = 0;
|
Free(&servers.p), servers.n = 0;
|
||||||
Free(&hdrbuf.p), hdrbuf.n = 0;
|
Free(&ports.p), ports.n = 0;
|
||||||
Free(&inbuf.p), inbuf.n = 0;
|
Free(&ips.p), ips.n = 0;
|
||||||
Free(&outbuf);
|
Free(&outbuf);
|
||||||
FreeStrings(&stagedirs);
|
FreeStrings(&stagedirs);
|
||||||
FreeStrings(&hidepaths);
|
FreeStrings(&hidepaths);
|
||||||
|
@ -7101,6 +7191,16 @@ static void MemDestroy(void) {
|
||||||
Free(&polls);
|
Free(&polls);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static wontreturn void ExitWorker(void) {
|
||||||
|
if (IsModeDbg()) {
|
||||||
|
LuaDestroy();
|
||||||
|
TlsDestroy();
|
||||||
|
MemDestroy();
|
||||||
|
CheckForMemoryLeaks();
|
||||||
|
}
|
||||||
|
_Exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
static void GetOpts(int argc, char *argv[]) {
|
static void GetOpts(int argc, char *argv[]) {
|
||||||
int opt;
|
int opt;
|
||||||
bool storeasset = false;
|
bool storeasset = false;
|
||||||
|
@ -7191,8 +7291,9 @@ void RedBean(int argc, char *argv[]) {
|
||||||
CollectGarbage();
|
CollectGarbage();
|
||||||
hdrbuf.n = 4 * 1024;
|
hdrbuf.n = 4 * 1024;
|
||||||
hdrbuf.p = xmalloc(hdrbuf.n);
|
hdrbuf.p = xmalloc(hdrbuf.n);
|
||||||
inbuf.n = maxpayloadsize;
|
inbuf_actual.n = maxpayloadsize;
|
||||||
inbuf.p = xmalloc(inbuf.n);
|
inbuf_actual.p = xmalloc(inbuf_actual.n);
|
||||||
|
inbuf = inbuf_actual;
|
||||||
isinitialized = true;
|
isinitialized = true;
|
||||||
CallSimpleHookIfDefined("OnServerStart");
|
CallSimpleHookIfDefined("OnServerStart");
|
||||||
HandleEvents();
|
HandleEvents();
|
||||||
|
@ -7212,5 +7313,8 @@ int main(int argc, char *argv[]) {
|
||||||
showcrashreports();
|
showcrashreports();
|
||||||
}
|
}
|
||||||
RedBean(argc, argv);
|
RedBean(argc, argv);
|
||||||
|
if (IsModeDbg()) {
|
||||||
|
CheckForMemoryLeaks();
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue