Merge branch 'master' of https://github.com/jart/cosmopolitan into FEATURE/ioctl_SIOCGIFCONF_IPHLPAPI

This commit is contained in:
Fabrizio Bertocci 2021-06-23 14:10:54 +02:00
commit 662b889f81
589 changed files with 327000 additions and 5345 deletions

View file

@ -136,8 +136,10 @@ include third_party/third_party.mk
include libc/testlib/testlib.mk
include tool/viz/lib/vizlib.mk
include third_party/lua/lua.mk
include third_party/sqlite3/sqlite3.mk
include third_party/quickjs/quickjs.mk
include third_party/lz4cli/lz4cli.mk
include third_party/infozip/infozip.mk
include tool/build/lib/buildlib.mk
include third_party/chibicc/chibicc.mk
include third_party/chibicc/test/test.mk

View file

@ -22,8 +22,8 @@ If you're doing your development work on Linux or BSD then you need just
five files to get started. Here's what you do on Linux:
```sh
wget https://justine.lol/cosmopolitan/cosmopolitan-amalgamation-0.3.zip
unzip cosmopolitan-amalgamation-0.3.zip
wget https://justine.lol/cosmopolitan/cosmopolitan-amalgamation-1.0.zip
unzip cosmopolitan-amalgamation-1.0.zip
printf 'main() { printf("hello world\\n"); }\n' >hello.c
gcc -g -Os -static -nostdlib -nostdinc -fno-pie -no-pie -mno-red-zone \
-fno-omit-frame-pointer -pg -mnop-mcount \
@ -38,23 +38,42 @@ first run, so it can be fast and efficient for subsequent executions.
```sh
./hello.com
bash -c './hello.com' # zsh/fish workaround (we upstreamed a patch)
bash -c './hello.com' # zsh/fish workaround (we upstreamed patches)
```
So if you intend to copy the binary to Windows or Mac then please do
that before you run it, not after.
If you're developing on Windows or MacOS then you need to download an
### MacOS
If you're developing on MacOS you can install the GNU compiler
collection for x86_64-elf via homebrew:
```sh
brew install x86_64-elf-gcc
```
Then in the above scripts just replace `gcc` and `objcopy` with
`x86_64-elf-gcc` and `x86_64-elf-objcopy` to compile your APE binary.
### Windows
If you're developing on Windows then you need to download an
x86_64-pc-linux-gnu toolchain beforehand. See the [Compiling on
Windows](https://justine.lol/cosmopolitan/windows-compiling.html)
tutorial. It's needed because the ELF object format is what makes
universal binaries possible.
Cosmopolitan can also be compiled from source on any Linux distro.
## Source Builds
Cosmopolitan can be compiled from source on any Linux distro. GNU make
needs to be installed beforehand. This is a freestanding hermetic
repository that bootstraps using a vendored static gcc9 executable.
No further dependencies are required.
```sh
wget https://justine.lol/cosmopolitan/cosmopolitan-0.3.tar.gz
tar xf cosmopolitan-0.3.tar.gz # see releases page
wget https://justine.lol/cosmopolitan/cosmopolitan-1.0.tar.gz
tar xf cosmopolitan-1.0.tar.gz # see releases page
cd cosmopolitan
make -j16
o//examples/hello.com

View file

@ -1476,7 +1476,22 @@ kernel: movabs $ape_stack_vaddr,%rsp
test %rax,%rax
jz 1f
movb $METAL,(%rax)
1: xor %eax,%eax
1: push $0
mov %rsp,%rbp
mov .Lenv0(%rip),%rax
mov %rax,(%rbp) # envp[0][0]
push $0 # argv[0][0]
push $0 # auxv[1][1]
push $0 # auxv[1][0]
push %rbp # auxv[0][1]
push $31 # auxv[0][0] AT_EXECFN
push $0 # envp[1]
push $.Lenv0 # envp[0]
push $0 # argv[1]
push %rbp # argv[0]
push $1 # argc
xor %ebp,%ebp
xor %eax,%eax
xor %ecx,%ecx
xor %edx,%edx
xor %edi,%edi
@ -1485,20 +1500,10 @@ kernel: movabs $ape_stack_vaddr,%rsp
xor %r9d,%r9d
xor %r10d,%r10d
xor %r11d,%r11d
push $0 # auxv[1][1]
push $0 # auxv[1][0]
push $.Larg0 # auxv[0][1]
push $31 # auxv[0][0] AT_EXECFN
push $0 # envp[1]
push $.Lenv0 # envp[0]
push $0 # argv[1]
push $.Larg0 # argv[0]
push $1 # argc
jmp _start
.endfn kernel
.rodata
.Larg0: .asciz "ape.com"
.Lenv0: .asciz "METAL=1"
.previous

Binary file not shown.

View file

@ -1,4 +1,4 @@
#!/usr/bin/env bash
#!/bin/sh
#-*-mode:sh;indent-tabs-mode:nil;tab-width:2;coding:utf-8-*-┐
#───vi: set net ft=sh ts=2 sts=2 fenc=utf-8 :vi─────────────┘
#

View file

@ -20,7 +20,6 @@
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/af.h"
#include "libc/sysv/consts/ai.h"
#include "libc/sysv/consts/ipproto.h"
#include "libc/sysv/consts/shut.h"
#include "libc/sysv/consts/sock.h"

View file

@ -8,11 +8,13 @@
*/
#endif
#include "libc/calls/calls.h"
#include "libc/dns/dns.h"
#include "libc/fmt/conv.h"
#include "libc/log/log.h"
#include "libc/macros.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/sock/sock.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/af.h"
#include "libc/sysv/consts/ipproto.h"
@ -21,6 +23,7 @@
#include "libc/sysv/consts/so.h"
#include "libc/sysv/consts/sock.h"
#include "libc/sysv/consts/sol.h"
#include "third_party/getopt/getopt.h"
/**
* @fileoverview netcat clone
@ -28,23 +31,62 @@
* Implemented because BusyBox's netcat doesn't detect remote close and
* lingers in the CLOSE_WAIT wait possibly due to file descriptor leaks
*
* Once upon time we called this command "Telnet"
* Here's an example usage:
*
* make -j8 o//examples/nc.com
* printf 'GET /\r\n\r\n' | o//examples/nc.com justine.lol 80
*
* Once upon time we called this command "telnet"
*/
int main(int argc, char *argv[]) {
ssize_t rc;
size_t i, got;
char buf[1500];
int err, toto, sock;
bool halfclose = true;
const char *host, *port;
int opt, err, toto, sock;
struct addrinfo *ai = NULL;
struct linger linger = {true, 1};
struct sockaddr_in addr = {AF_INET};
struct pollfd fds[2] = {{-1, POLLIN}, {-1, POLLIN}};
struct addrinfo hint = {AI_NUMERICSERV, AF_INET, SOCK_STREAM, IPPROTO_TCP};
if (argc != 3) exit(1);
inet_pton(AF_INET, argv[1], &addr.sin_addr);
addr.sin_port = htons(atoi(argv[2]));
while ((opt = getopt(argc, argv, "hH")) != -1) {
switch (opt) {
case 'H':
halfclose = false;
break;
case 'h':
fputs("Usage: ", stdout);
fputs(argv[0], stdout);
fputs(" [-hH] IP PORT\n", stdout);
exit(0);
default:
fprintf(stderr, "bad option %d\n", opt);
exit(1);
}
}
if (argc - optind != 2) {
fputs("missing args\n", stderr);
exit(1);
}
host = argv[optind + 0];
port = argv[optind + 1];
if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
switch ((rc = getaddrinfo(host, port, &hint, &ai))) {
case EAI_SUCCESS:
break;
case EAI_SYSTEM:
perror("getaddrinfo");
exit(1);
default:
fputs("EAI_", stderr);
fputs(gai_strerror(rc), stderr);
fputs("\n", stderr);
exit(1);
}
if ((sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol)) == -1) {
perror("socket");
exit(1);
}
@ -54,7 +96,7 @@ int main(int argc, char *argv[]) {
exit(1);
}
if (connect(sock, &addr, sizeof(addr)) == -1) {
if (connect(sock, ai->ai_addr, ai->ai_addrlen) == -1) {
perror("connect");
exit(1);
}
@ -75,7 +117,9 @@ int main(int argc, char *argv[]) {
exit(1);
}
if (!(got = rc)) {
shutdown(sock, SHUT_WR);
if (halfclose) {
shutdown(sock, SHUT_WR);
}
fds[0].fd = -1;
}
for (i = 0; i < got; i += rc) {
@ -108,5 +152,6 @@ int main(int argc, char *argv[]) {
exit(1);
}
freeaddrinfo(ai);
return 0;
}

View file

@ -7,15 +7,15 @@ COSMOPOLITAN_C_START_
unsigned long popcnt(unsigned long) pureconst;
#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
#define popcnt(X) \
(__builtin_constant_p(X) ? __builtin_popcountll(X) : ({ \
unsigned long Res, Pop = (X); \
if (X86_HAVE(POPCNT)) { \
asm("popcnt\t%1,%0" : "=r"(Res) : "r"(Pop) : "cc"); \
} else { \
Res = (popcnt)(Pop); \
} \
Res; \
#define popcnt(X) \
(__builtin_constant_p(X) ? __builtin_popcountll(X) : ({ \
unsigned long PoP = (X); \
if (X86_HAVE(POPCNT)) { \
asm("popcnt\t%0,%0" : "+r"(PoP) : /* no inputs */ : "cc"); \
} else { \
PoP = (popcnt)(PoP); \
} \
PoP; \
}))
#endif /* GNUC && !ANSI */

View file

@ -137,8 +137,8 @@ int mlockall(int);
int munlock(const void *, size_t);
int munlockall(void);
int nice(int);
int open(const char *, int, ...) nodiscard;
int openanon(char *, unsigned) nodiscard;
int open(const char *, int, ...);
int openanon(char *, unsigned);
int openat(int, const char *, int, ...);
int pause(void);
int personality(uint64_t);
@ -176,7 +176,7 @@ int stat(const char *, struct stat *);
int symlink(const char *, const char *);
int symlinkat(const char *, int, const char *);
int sync_file_range(int, int64_t, int64_t, unsigned);
int sysinfo(struct sysinfo *) paramsnonnull();
int sysinfo(struct sysinfo *);
int touch(const char *, uint32_t);
int truncate(const char *, uint64_t);
int ttyname_r(int, char *, size_t);

View file

@ -18,45 +18,113 @@
*/
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/struct/flock.h"
#include "libc/macros.internal.h"
#include "libc/nt/enum/accessmask.h"
#include "libc/nt/enum/fileflagandattributes.h"
#include "libc/nt/enum/filelockflags.h"
#include "libc/nt/enum/filesharemode.h"
#include "libc/nt/enum/formatmessageflags.h"
#include "libc/nt/errors.h"
#include "libc/nt/files.h"
#include "libc/nt/process.h"
#include "libc/nt/runtime.h"
#include "libc/nt/struct/byhandlefileinformation.h"
#include "libc/nt/struct/overlapped.h"
#include "libc/nt/synchronization.h"
#include "libc/sysv/consts/f.h"
#include "libc/sysv/consts/fd.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/errfuns.h"
textwindows int sys_fcntl_nt(int fd, int cmd, unsigned arg) {
static textwindows int sys_fcntl_nt_lock(struct Fd *f, int cmd, uintptr_t arg) {
struct flock *l;
uint32_t flags, err;
struct NtOverlapped ov;
int64_t pos, off, len, size;
struct NtByHandleFileInformation info;
if (!GetFileInformationByHandle(f->handle, &info)) return __winerr();
if (!SetFilePointerEx(f->handle, 0, &pos, SEEK_CUR)) return __winerr();
l = (struct flock *)arg;
len = l->l_len;
off = l->l_start;
size = (uint64_t)info.nFileSizeHigh << 32 | info.nFileSizeLow;
switch (l->l_whence) {
case SEEK_SET:
break;
case SEEK_CUR:
off = pos + off;
break;
case SEEK_END:
off = size - off;
break;
default:
return einval();
}
if (!len) len = size - off;
if (off < 0 || len < 0) return einval();
offset2overlap(off, &ov);
if (l->l_type == F_RDLCK || l->l_type == F_WRLCK) {
flags = 0;
if (cmd == F_SETLK) flags |= kNtLockfileFailImmediately;
/* TODO: How can we make SQLite locks on Windows to work? */
/* if (l->l_type == F_WRLCK) flags |= kNtLockfileExclusiveLock; */
if (LockFileEx(f->handle, flags, 0, len, len >> 32, &ov)) {
return 0;
} else {
err = GetLastError();
if (err == kNtErrorLockViolation) err = EAGAIN;
errno = err;
return -1;
}
} else if (l->l_type == F_UNLCK) {
if (UnlockFileEx(f->handle, 0, len, len >> 32, &ov)) {
return 0;
} else {
err = GetLastError();
if (err == kNtErrorNotLocked) {
return 0;
} else {
errno = err;
return -1;
}
}
} else {
return einval();
}
}
textwindows int sys_fcntl_nt(int fd, int cmd, uintptr_t arg) {
uint32_t flags;
if (__isfdkind(fd, kFdFile) || __isfdkind(fd, kFdSocket)) {
switch (cmd) {
case F_GETFL:
return g_fds.p[fd].flags & (O_ACCMODE | O_APPEND | O_ASYNC | O_DIRECT |
O_NOATIME | O_NONBLOCK);
case F_SETFL:
/*
* - O_APPEND doesn't appear to be tunable at cursory glance
* - O_NONBLOCK might require we start doing all i/o in threads
* - O_DSYNC / O_RSYNC / O_SYNC maybe if we fsync() everything
*/
return einval();
case F_GETFD:
if (g_fds.p[fd].flags & O_CLOEXEC) {
return FD_CLOEXEC;
} else {
return 0;
}
case F_SETFD:
if (arg & FD_CLOEXEC) {
g_fds.p[fd].flags |= O_CLOEXEC;
return FD_CLOEXEC;
} else {
g_fds.p[fd].flags &= ~O_CLOEXEC;
return 0;
}
default:
return einval();
if (cmd == F_GETFL) {
return g_fds.p[fd].flags & (O_ACCMODE | O_APPEND | O_ASYNC | O_DIRECT |
O_NOATIME | O_NONBLOCK);
} else if (cmd == F_SETFL) {
/*
* - O_APPEND doesn't appear to be tunable at cursory glance
* - O_NONBLOCK might require we start doing all i/o in threads
* - O_DSYNC / O_RSYNC / O_SYNC maybe if we fsync() everything
*/
return einval();
} else if (cmd == F_GETFD) {
if (g_fds.p[fd].flags & O_CLOEXEC) {
return FD_CLOEXEC;
} else {
return 0;
}
} else if (cmd == F_SETFD) {
if (arg & FD_CLOEXEC) {
g_fds.p[fd].flags |= O_CLOEXEC;
return FD_CLOEXEC;
} else {
g_fds.p[fd].flags &= ~O_CLOEXEC;
return 0;
}
} else if (cmd == F_SETLK || cmd == F_SETLKW) {
return sys_fcntl_nt_lock(g_fds.p + fd, cmd, arg);
} else {
return einval();
}
} else {
return ebadf();

View file

@ -1,7 +1,7 @@
/*-*- 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
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
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
@ -16,30 +16,16 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
#include "libc/calls/internal.h"
#include "libc/calls/struct/flock.h"
#include "libc/sysv/consts/f.h"
// Finds leading bits in 𝑥.
//
// uint32 𝑥 bsf(𝑥) tzcnt(𝑥) ffs(𝑥) bsr(𝑥) lzcnt(𝑥)
// 0x00000000 wut 32 0 wut 32
// 0x00000001 0 0 1 0 31
// 0x80000001 0 0 1 31 0
// 0x80000000 31 31 32 31 0
// 0x00000010 4 4 5 4 27
// 0x08000010 4 4 5 27 4
// 0x08000000 27 27 28 27 4
// 0xffffffff 0 0 1 31 0
//
// @param rdi is 64-bit unsigned 𝑥 value
// @return rax number in range [0,64) or 64 if 𝑥 is 0
// @see also treasure trove of nearly identical functions
lzcntl: .leafprologue
.profilable
mov $31,%eax
mov $-1,%edx
bsr %rdi,%rcx
cmovz %edx,%ecx
sub %ecx,%eax
.endfn lzcntl,globl
.alias lzcntl,lzcntll
.source __FILE__
int sys_fcntl(int fd, int cmd, uintptr_t arg) {
int rc;
bool islock;
islock = cmd == F_SETLK || cmd == F_SETLKW || cmd == F_GETLK;
if (islock) cosmo2flock(arg);
rc = __sys_fcntl(fd, cmd, arg);
if (islock) flock2cosmo(arg);
return rc;
}

View file

@ -25,6 +25,15 @@
*
* CHECK_NE(-1, fcntl(fd, F_SETFD, FD_CLOEXEC));
*
* This function implements POSIX Advisory Locks, e.g.
*
* CHECK_NE(-1, fcntl(zfd, F_SETLKW, &(struct flock){F_WRLCK}));
* // ...
* CHECK_NE(-1, fcntl(zfd, F_SETLK, &(struct flock){F_UNLCK}));
*
* Please be warned that locks currently do nothing on Windows since
* figuring out how to polyfill them correctly is a work in progress.
*
* @param cmd can be F_{GET,SET}{FD,FL}, etc.
* @param arg can be FD_CLOEXEC, etc. depending
* @return 0 on success, or -1 w/ errno
@ -32,9 +41,9 @@
*/
int fcntl(int fd, int cmd, ...) {
va_list va;
unsigned arg;
uintptr_t arg;
va_start(va, cmd);
arg = va_arg(va, unsigned);
arg = va_arg(va, uintptr_t);
va_end(va);
if (!IsWindows()) {
return sys_fcntl(fd, cmd, arg);

View file

@ -28,7 +28,7 @@
int __fixupnewfd(int fd, int flags) {
if (fd != -1) {
if (flags & O_CLOEXEC) {
sys_fcntl(fd, F_SETFD, FD_CLOEXEC);
__sys_fcntl(fd, F_SETFD, FD_CLOEXEC);
}
}
return fd;

View file

@ -23,6 +23,8 @@
/**
* Acquires lock on file.
*
* Please note multiple file descriptors means multiple locks.
*
* @param op can have LOCK_{SH,EX,NB,UN} for shared, exclusive,
* non-blocking, and unlocking
* @return 0 on success, or -1 w/ errno

View file

@ -20,6 +20,7 @@
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/sysv/errfuns.h"
#include "libc/zipos/zipos.internal.h"
@ -28,6 +29,7 @@
* @asyncsignalsafe
*/
int fstat(int fd, struct stat *st) {
if (IsAsan() && (!st || !__asan_is_valid(st, sizeof(*st)))) return efault();
if (__isfdkind(fd, kFdZip)) {
return weaken(__zipos_fstat)(
(struct ZiposHandle *)(intptr_t)g_fds.p[fd].handle, st);

View file

@ -20,7 +20,9 @@
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/errno.h"
#include "libc/intrin/asan.internal.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/errfuns.h"
#include "libc/zipos/zipos.internal.h"
/**
@ -36,6 +38,7 @@
*/
int fstatat(int dirfd, const char *path, struct stat *st, uint32_t flags) {
struct ZiposUri zipname;
if (IsAsan() && (!st || !__asan_is_valid(st, sizeof(*st)))) return efault();
if (weaken(__zipos_stat) && weaken(__zipos_parseuri)(path, &zipname) != -1) {
return weaken(__zipos_stat)(&zipname, st);
} else if (!IsWindows()) {

View file

@ -34,7 +34,7 @@ char *sys_getcwd_xnu(char *res, size_t size) {
if ((fd = sys_openat(AT_FDCWD, ".", O_RDONLY | O_DIRECTORY, 0)) != -1) {
if (sys_fstat(fd, &st[0]) != -1) {
if (st[0].st_dev && st[0].st_ino) {
if (sys_fcntl(fd, XNU_F_GETPATH, buf) != -1) {
if (__sys_fcntl(fd, XNU_F_GETPATH, (uintptr_t)buf) != -1) {
if (sys_fstatat(AT_FDCWD, buf, &st[1], 0) != -1) {
if (st[0].st_dev == st[1].st_dev && st[0].st_ino == st[1].st_ino) {
if (memccpy(res, buf, '\0', size)) {

View file

@ -22,7 +22,7 @@
* Returns parent process id.
* @asyncsignalsafe
*/
int32_t getppid(void) {
int getppid(void) {
if (!IsWindows()) {
if (!IsNetbsd()) {
return sys_getppid();

View file

@ -109,6 +109,7 @@ char *sys_getcwd(char *, u64) hidden;
char *sys_getcwd_xnu(char *, u64) hidden;
i32 __sys_dup3(i32, i32, i32) hidden;
i32 __sys_execve(const char *, char *const[], char *const[]) hidden;
i32 __sys_fcntl(i32, i32, u64) hidden;
i32 __sys_fstat(i32, struct stat *) hidden;
i32 __sys_fstatat(i32, const char *, struct stat *, i32) hidden;
i32 __sys_getrusage(i32, struct rusage *) hidden;
@ -131,7 +132,7 @@ i32 sys_fchmod(i32, u32) hidden;
i32 sys_fchmodat(i32, const char *, u32, u32) hidden;
i32 sys_fchown(i64, u32, u32) hidden;
i32 sys_fchownat(i32, const char *, u32, u32, u32) hidden;
i32 sys_fcntl(i32, i32, ...) hidden;
i32 sys_fcntl(i32, i32, u64) hidden;
i32 sys_fdatasync(i32) hidden;
i32 sys_flock(i32, i32) hidden;
i32 sys_fstat(i32, struct stat *) hidden;
@ -229,6 +230,8 @@ int gethostname_nt(char *, size_t) hidden;
size_t __iovec_size(const struct iovec *, size_t) hidden;
void __rusage2linux(struct rusage *) hidden;
ssize_t WritevUninterruptible(int, struct iovec *, int);
void flock2cosmo(uintptr_t);
void cosmo2flock(uintptr_t);
/*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § syscalls » windows nt » veneers
@ -245,7 +248,7 @@ int sys_execve_nt(const char *, char *const[], char *const[]) hidden;
int sys_faccessat_nt(int, const char *, int, uint32_t) hidden;
int sys_fadvise_nt(int, u64, u64, int) hidden;
int sys_fchdir_nt(int) hidden;
int sys_fcntl_nt(int, int, unsigned) hidden;
int sys_fcntl_nt(int, int, uintptr_t) hidden;
int sys_fdatasync_nt(int) hidden;
int sys_flock_nt(int, int) hidden;
int sys_fork_nt(void) hidden;

164
libc/calls/metaflock.c Normal file
View file

@ -0,0 +1,164 @@
/*-*- 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/calls/internal.h"
#include "libc/calls/struct/flock.h"
union metaflock {
struct flock cosmo;
struct flock_linux {
int16_t l_type;
int16_t l_whence;
int64_t l_start;
int64_t l_len;
int32_t l_pid;
} linux;
struct flock_xnu {
int64_t l_start;
int64_t l_len;
int32_t l_pid;
int16_t l_type;
int16_t l_whence;
} xnu;
struct flock_freebsd {
int64_t l_start;
int64_t l_len;
int32_t l_pid;
int16_t l_type;
int16_t l_whence;
int32_t l_sysid;
} freebsd;
struct flock_openbsd {
int64_t l_start;
int64_t l_len;
int32_t l_pid;
int16_t l_type;
int16_t l_whence;
} openbsd;
struct flock_netbsd {
int64_t l_start;
int64_t l_len;
int32_t l_pid;
int16_t l_type;
int16_t l_whence;
} netbsd;
};
void flock2cosmo(uintptr_t memory) {
int64_t l_start;
int64_t l_len;
int32_t l_pid;
int16_t l_type;
int16_t l_whence;
int32_t l_sysid;
union metaflock *u;
u = (union metaflock *)memory;
if (IsLinux()) {
l_start = u->linux.l_start;
l_len = u->linux.l_len;
l_pid = u->linux.l_pid;
l_type = u->linux.l_type;
l_whence = u->linux.l_whence;
l_sysid = 0;
} else if (IsXnu()) {
l_start = u->xnu.l_start;
l_len = u->xnu.l_len;
l_pid = u->xnu.l_pid;
l_type = u->xnu.l_type;
l_whence = u->xnu.l_whence;
l_sysid = 0;
} else if (IsFreebsd()) {
l_start = u->freebsd.l_start;
l_len = u->freebsd.l_len;
l_pid = u->freebsd.l_pid;
l_type = u->freebsd.l_type;
l_whence = u->freebsd.l_whence;
l_sysid = u->freebsd.l_sysid;
} else if (IsOpenbsd()) {
l_start = u->openbsd.l_start;
l_len = u->openbsd.l_len;
l_pid = u->openbsd.l_pid;
l_type = u->openbsd.l_type;
l_whence = u->openbsd.l_whence;
l_sysid = 0;
} else if (IsNetbsd()) {
l_start = u->netbsd.l_start;
l_len = u->netbsd.l_len;
l_pid = u->netbsd.l_pid;
l_type = u->netbsd.l_type;
l_whence = u->netbsd.l_whence;
l_sysid = 0;
} else {
return;
}
u->cosmo.l_start = l_start;
u->cosmo.l_len = l_len;
u->cosmo.l_pid = l_pid;
u->cosmo.l_type = l_type;
u->cosmo.l_whence = l_whence;
u->cosmo.l_sysid = l_sysid;
}
void cosmo2flock(uintptr_t memory) {
int64_t l_start;
int64_t l_len;
int32_t l_pid;
int16_t l_type;
int16_t l_whence;
int32_t l_sysid;
union metaflock *u;
u = (union metaflock *)memory;
l_start = u->cosmo.l_start;
l_len = u->cosmo.l_len;
l_pid = u->cosmo.l_pid;
l_type = u->cosmo.l_type;
l_whence = u->cosmo.l_whence;
l_sysid = u->cosmo.l_sysid;
if (IsLinux()) {
u->linux.l_start = l_start;
u->linux.l_len = l_len;
u->linux.l_pid = l_pid;
u->linux.l_type = l_type;
u->linux.l_whence = l_whence;
} else if (IsXnu()) {
u->xnu.l_start = l_start;
u->xnu.l_len = l_len;
u->xnu.l_pid = l_pid;
u->xnu.l_type = l_type;
u->xnu.l_whence = l_whence;
} else if (IsFreebsd()) {
u->freebsd.l_start = l_start;
u->freebsd.l_len = l_len;
u->freebsd.l_pid = l_pid;
u->freebsd.l_type = l_type;
u->freebsd.l_whence = l_whence;
u->freebsd.l_sysid = l_sysid;
} else if (IsOpenbsd()) {
u->openbsd.l_start = l_start;
u->openbsd.l_len = l_len;
u->openbsd.l_pid = l_pid;
u->openbsd.l_type = l_type;
u->openbsd.l_whence = l_whence;
} else if (IsNetbsd()) {
u->netbsd.l_start = l_start;
u->netbsd.l_len = l_len;
u->netbsd.l_pid = l_pid;
u->netbsd.l_type = l_type;
u->netbsd.l_whence = l_whence;
}
}

View file

@ -36,7 +36,7 @@ int sys_openat(int dirfd, const char *file, int flags, unsigned mode) {
errno = err;
fd = __sys_openat(dirfd, file, flags & ~O_CLOEXEC, mode);
if (fd != -1 && (flags & O_CLOEXEC)) {
sys_fcntl(fd, F_SETFD, FD_CLOEXEC);
__sys_fcntl(fd, F_SETFD, FD_CLOEXEC);
}
}

View file

@ -23,6 +23,7 @@
#include "libc/calls/struct/iovec.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/asan.internal.h"
#include "libc/macros.internal.h"
#include "libc/sysv/consts/iov.h"
#include "libc/sysv/errfuns.h"
@ -45,6 +46,7 @@ ssize_t preadv(int fd, struct iovec *iov, int iovlen, int64_t off) {
if (fd < 0) return einval();
if (iovlen < 0) return einval();
if (IsAsan() && !__asan_is_valid_iov(iov, iovlen)) return efault();
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
return weaken(__zipos_read)(
(struct ZiposHandle *)(intptr_t)g_fds.p[fd].handle, iov, iovlen, off);

View file

@ -22,6 +22,7 @@
#include "libc/calls/struct/iovec.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/asan.internal.h"
#include "libc/macros.internal.h"
#include "libc/sysv/consts/iov.h"
#include "libc/sysv/errfuns.h"
@ -49,6 +50,7 @@ ssize_t pwritev(int fd, const struct iovec *iov, int iovlen, int64_t off) {
if (fd < 0) return einval();
if (iovlen < 0) return einval();
if (IsAsan() && !__asan_is_valid_iov(iov, iovlen)) return efault();
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
return weaken(__zipos_write)(
(struct ZiposHandle *)(intptr_t)g_fds.p[fd].handle, iov, iovlen, off);

View file

@ -20,6 +20,7 @@
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/struct/iovec.h"
#include "libc/intrin/asan.internal.h"
#include "libc/sock/internal.h"
#include "libc/sysv/errfuns.h"
#include "libc/zipos/zipos.internal.h"
@ -31,18 +32,21 @@
* @asyncsignalsafe
*/
ssize_t readv(int fd, const struct iovec *iov, int iovlen) {
if (fd < 0) return einval();
if (iovlen < 0) return einval();
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
return weaken(__zipos_read)(
(struct ZiposHandle *)(intptr_t)g_fds.p[fd].handle, iov, iovlen, -1);
} else if (!IsWindows() && !IsMetal()) {
return sys_readv(fd, iov, iovlen);
} else if (fd >= g_fds.n) {
return ebadf();
} else if (IsMetal()) {
return sys_readv_metal(g_fds.p + fd, iov, iovlen);
if (fd >= 0 && iovlen >= 0) {
if (IsAsan() && !__asan_is_valid_iov(iov, iovlen)) return efault();
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
return weaken(__zipos_read)(
(struct ZiposHandle *)(intptr_t)g_fds.p[fd].handle, iov, iovlen, -1);
} else if (!IsWindows() && !IsMetal()) {
return sys_readv(fd, iov, iovlen);
} else if (fd >= g_fds.n) {
return ebadf();
} else if (IsMetal()) {
return sys_readv_metal(g_fds.p + fd, iov, iovlen);
} else {
return sys_readv_nt(g_fds.p + fd, iov, iovlen);
}
} else {
return sys_readv_nt(g_fds.p + fd, iov, iovlen);
return einval();
}
}

View file

@ -2,12 +2,13 @@
#define COSMOPOLITAN_LIBC_CALLS_STRUCT_FLOCK_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
struct flock {
short l_type;
short l_whence;
int64_t l_start;
int64_t l_len;
int l_pid;
struct flock { /* cosmopolitan abi */
int16_t l_type; /* F_RDLCK, F_WRLCK, F_UNLCK */
int16_t l_whence; /* SEEK_SET, SEEK_CUR, SEEK_END */
int64_t l_start; /* starting offset */
int64_t l_len; /* 0 means until end of file */
int32_t l_pid; /* lock owner */
int32_t l_sysid; /* remote system id or zero for local */
};
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -21,11 +21,13 @@
#include "libc/calls/internal.h"
#include "libc/calls/struct/sysinfo.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/nt/accounting.h"
#include "libc/nt/runtime.h"
#include "libc/nt/struct/memorystatusex.h"
#include "libc/nt/systeminfo.h"
#include "libc/str/str.h"
#include "libc/sysv/errfuns.h"
/**
* Returns amount of system ram, cores, etc.
@ -34,6 +36,11 @@
*/
int sysinfo(struct sysinfo *info) {
int rc;
if (IsAsan()) {
if (info && !__asan_is_valid(info, sizeof(*info))) {
return efault();
}
}
memset(info, 0, sizeof(*info));
if (!IsWindows()) {
rc = sys_sysinfo(info);

View file

@ -18,7 +18,9 @@
*/
#include "libc/calls/internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/errfuns.h"
#include "libc/time/time.h"
/**
@ -30,6 +32,11 @@
* @see stat()
*/
int utimes(const char *path, const struct timeval tv[2]) {
if (IsAsan()) {
if (tv && !__asan_is_valid(tv, sizeof(*tv) * 2)) {
return efault();
}
}
if (!IsWindows()) {
/*
* we don't modernize utimes() into utimensat() because the

View file

@ -20,6 +20,8 @@
#include "libc/calls/internal.h"
#include "libc/calls/wait4.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/sysv/errfuns.h"
/**
* Waits for status to change on process.
@ -35,6 +37,16 @@
*/
int wait4(int pid, int *opt_out_wstatus, int options,
struct rusage *opt_out_rusage) {
if (IsAsan()) {
if (opt_out_wstatus &&
!__asan_is_valid(opt_out_wstatus, sizeof(*opt_out_wstatus))) {
return efault();
}
if (opt_out_rusage &&
!__asan_is_valid(opt_out_rusage, sizeof(*opt_out_rusage))) {
return efault();
}
}
if (!IsWindows()) {
return sys_wait4(pid, opt_out_wstatus, options, opt_out_rusage);
} else {

View file

@ -19,6 +19,7 @@
#include "libc/bits/weaken.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/intrin/asan.internal.h"
#include "libc/sock/internal.h"
#include "libc/sysv/errfuns.h"
#include "libc/zipos/zipos.internal.h"
@ -34,18 +35,21 @@
* @return number of bytes actually handed off, or -1 w/ errno
*/
ssize_t writev(int fd, const struct iovec *iov, int iovlen) {
if (fd < 0) return einval();
if (iovlen < 0) return einval();
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
return weaken(__zipos_write)(
(struct ZiposHandle *)(intptr_t)g_fds.p[fd].handle, iov, iovlen, -1);
} else if (!IsWindows() && !IsMetal()) {
return sys_writev(fd, iov, iovlen);
} else if (fd >= g_fds.n) {
return ebadf();
} else if (IsMetal()) {
return sys_writev_metal(g_fds.p + fd, iov, iovlen);
if (fd >= 0 && iovlen >= 0) {
if (IsAsan() && !__asan_is_valid_iov(iov, iovlen)) return efault();
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
return weaken(__zipos_write)(
(struct ZiposHandle *)(intptr_t)g_fds.p[fd].handle, iov, iovlen, -1);
} else if (!IsWindows() && !IsMetal()) {
return sys_writev(fd, iov, iovlen);
} else if (fd >= g_fds.n) {
return ebadf();
} else if (IsMetal()) {
return sys_writev_metal(g_fds.p + fd, iov, iovlen);
} else {
return sys_writev_nt(g_fds.p + fd, iov, iovlen);
}
} else {
return sys_writev_nt(g_fds.p + fd, iov, iovlen);
return einval();
}
}

View file

@ -57,6 +57,12 @@
#define IsOptimized() 0
#endif
#ifdef __FSANITIZE_ADDRESS__
#define IsAsan() 1
#else
#define IsAsan() 0
#endif
#if defined(__PIE__) || defined(__PIC__)
#define IsPositionIndependent() 1
#else

View file

@ -16,8 +16,8 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/bits/safemacros.internal.h"
#include "libc/dns/dns.h"
#include "libc/macros.internal.h"
#include "libc/str/str.h"
forceinline void FindDnsLabel(const char *A, size_t *i, size_t *n) {
@ -36,12 +36,15 @@ forceinline void FindDnsLabel(const char *A, size_t *i, size_t *n) {
/**
* Compares DNS hostnames in reverse lexicographical asciibetical order.
* @return <0, 0, or >0
* @see test/libc/dns/dnsnamecmp_test.c (the code that matters)
* @see test/libc/dns/comparednsnames_test.c (the code that matters)
*/
int dnsnamecmp(const char *A, const char *B) {
int CompareDnsNames(const char *A, const char *B) {
int res;
bool first;
size_t n, m, i, j;
if (A == B) return 0;
size_t n = strlen(A);
size_t m = strlen(B);
n = strlen(A);
m = strlen(B);
if (!n || !m || ((A[n - 1] == '.') ^ (B[m - 1] == '.'))) {
if (n && m && A[n - 1] == '.' && strchr(B, '.')) {
--m;
@ -51,9 +54,9 @@ int dnsnamecmp(const char *A, const char *B) {
return A[n ? n - 1 : 0] - B[m ? m - 1 : 0];
}
}
size_t i = n;
size_t j = m;
bool first = true;
i = n;
j = m;
first = true;
for (;;) {
FindDnsLabel(A, &i, &n);
FindDnsLabel(B, &j, &m);
@ -62,8 +65,7 @@ int dnsnamecmp(const char *A, const char *B) {
if (!i && j) return 1;
if (!j && i) return -1;
}
int res;
if ((res = strncasecmp(&A[i], &B[j], min(n - i + 1, m - j + 1)))) {
if ((res = strncasecmp(&A[i], &B[j], MIN(n - i + 1, m - j + 1)))) {
return res;
}
if (!i || !j) {

View file

@ -3,7 +3,9 @@
#include "libc/sock/sock.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
#define DNS_TYPE_A 1
#define DNS_TYPE_A 0x01
#define DNS_TYPE_PTR 0x0c
#define DNS_CLASS_IN 1
#define kMinSockaddr4Size \

View file

@ -1,5 +1,6 @@
#ifndef COSMOPOLITAN_LIBC_DNS_DNS_H_
#define COSMOPOLITAN_LIBC_DNS_DNS_H_
#include "libc/calls/weirdtypes.h"
#include "libc/dns/resolvconf.h"
#include "libc/sock/sock.h"
@ -27,6 +28,15 @@
#define EAI_INTR -104
#define EAI_NOTCANCELED -102
/* AI_* conforms to NT ABI */
#define AI_PASSIVE 1
#define AI_CANONNAME 2
#define AI_NUMERICHOST 4
#define AI_NUMERICSERV 8
#define AI_ALL 0x0100
#define AI_ADDRCONFIG 0x0400
#define AI_V4MAPPED 0x0800
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
@ -47,11 +57,15 @@ struct addrinfo {
int getaddrinfo(const char *, const char *, const struct addrinfo *,
struct addrinfo **) paramsnonnull((4));
int freeaddrinfo(struct addrinfo *);
int getnameinfo(const struct sockaddr *, socklen_t, char *, socklen_t, char *,
socklen_t, int);
const char *gai_strerror(int);
int dnsnamecmp(const char *, const char *) paramsnonnull();
int pascalifydnsname(uint8_t *, size_t, const char *) paramsnonnull();
int resolvedns(const struct ResolvConf *, int, const char *, struct sockaddr *,
int CompareDnsNames(const char *, const char *) paramsnonnull();
int PascalifyDnsName(uint8_t *, size_t, const char *) paramsnonnull();
int ResolveDns(const struct ResolvConf *, int, const char *, struct sockaddr *,
uint32_t) paramsnonnull();
int ResolveDnsReverse(const struct ResolvConf *resolvconf, int, const char *,
char *, size_t) paramsnonnull();
struct addrinfo *newaddrinfo(uint16_t);
COSMOPOLITAN_C_END_

View file

@ -21,43 +21,37 @@
#include "libc/sysv/errfuns.h"
/**
* Serializes DNS message header to wire.
* Serializes DNS message h to wire.
*
* @return number of bytes written (always 12) or -1 w/ errno
* @see pascalifydnsname()
*/
int serializednsheader(uint8_t *buf, size_t size,
const struct DnsHeader header) {
if (size < 12) return enospc();
buf[0x0] = header.id >> 010u;
buf[0x1] = header.id >> 000u;
buf[0x2] = header.bf1;
buf[0x3] = header.bf2;
buf[0x4] = header.qdcount >> 010u;
buf[0x5] = header.qdcount >> 000u;
buf[0x6] = header.ancount >> 010u;
buf[0x7] = header.ancount >> 000u;
buf[0x8] = header.nscount >> 010u;
buf[0x9] = header.nscount >> 000u;
buf[0xa] = header.arcount >> 010u;
buf[0xb] = header.arcount >> 000u;
return 12;
void SerializeDnsHeader(uint8_t p[restrict 12], const struct DnsHeader *h) {
p[0x0] = h->id >> 8;
p[0x1] = h->id;
p[0x2] = h->bf1;
p[0x3] = h->bf2;
p[0x4] = h->qdcount >> 8;
p[0x5] = h->qdcount;
p[0x6] = h->ancount >> 8;
p[0x7] = h->ancount;
p[0x8] = h->nscount >> 8;
p[0x9] = h->nscount;
p[0xa] = h->arcount >> 8;
p[0xb] = h->arcount;
}
/**
* Serializes DNS message header to wire.
* Serializes DNS message h to wire.
*
* @return number of bytes read (always 12) or -1 w/ errno
*/
int deserializednsheader(struct DnsHeader *header, const uint8_t *buf,
size_t size) {
if (size < 12) return ebadmsg();
header->id = READ16BE(buf + 0);
header->bf1 = buf[2];
header->bf2 = buf[3];
header->qdcount = READ16BE(buf + 4);
header->ancount = READ16BE(buf + 6);
header->nscount = READ16BE(buf + 8);
header->arcount = READ16BE(buf + 10);
return 12;
void DeserializeDnsHeader(struct DnsHeader *h, const uint8_t p[restrict 12]) {
h->id = READ16BE(p);
h->bf1 = p[2];
h->bf2 = p[3];
h->qdcount = READ16BE(p + 4);
h->ancount = READ16BE(p + 6);
h->nscount = READ16BE(p + 8);
h->arcount = READ16BE(p + 10);
}

View file

@ -13,8 +13,8 @@ struct DnsHeader {
uint16_t arcount; /* additional record count */
};
int serializednsheader(uint8_t *, size_t, const struct DnsHeader);
int deserializednsheader(struct DnsHeader *, const uint8_t *, size_t);
void SerializeDnsHeader(uint8_t[restrict 12], const struct DnsHeader *);
void DeserializeDnsHeader(struct DnsHeader *, const uint8_t[restrict 12]);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -9,7 +9,7 @@ struct DnsQuestion {
uint16_t qclass;
};
int serializednsquestion(uint8_t *, size_t, struct DnsQuestion);
int SerializeDnsQuestion(uint8_t *, size_t, const struct DnsQuestion *);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -22,13 +22,13 @@
/**
* Frees addresses returned by getaddrinfo().
*/
int freeaddrinfo(struct addrinfo *addrs) {
int freeaddrinfo(struct addrinfo *ai) {
struct addrinfo *next;
while (addrs) {
while (ai) {
/* we assume ai_addr and ai_canonname are shoehorned */
next = addrs->ai_next;
free(addrs);
addrs = next;
next = ai->ai_next;
free(ai);
ai = next;
}
return 0;
}

View file

@ -20,9 +20,9 @@
#include "libc/runtime/runtime.h"
/**
* Frees HOSTS.TXT data structure populated by parsehoststxt().
* Frees HOSTS.TXT data structure populated by ParseHostsTxt().
*/
void freehoststxt(struct HostsTxt **ht) {
void FreeHostsTxt(struct HostsTxt **ht) {
if (*ht) {
free_s(&(*ht)->entries.p);
free_s(&(*ht)->strings.p);

View file

@ -20,9 +20,9 @@
#include "libc/runtime/runtime.h"
/**
* Frees resolv.conf data structure populated by parseresolvconf().
* Frees resolv.conf data structure populated by ParseResolvConf().
*/
void freeresolvconf(struct ResolvConf **rvp) {
void FreeResolvConf(struct ResolvConf **rvp) {
if (*rvp) {
free_s(&(*rvp)->nameservers.p);
free_s(rvp);

View file

@ -26,7 +26,6 @@
#include "libc/sock/sock.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/af.h"
#include "libc/sysv/consts/ai.h"
#include "libc/sysv/consts/inaddr.h"
#include "libc/sysv/errfuns.h"
@ -68,13 +67,13 @@ int getaddrinfo(const char *name, const char *service,
} else if (hints && (hints->ai_flags & AI_NUMERICHOST) == AI_NUMERICHOST) {
freeaddrinfo(ai);
return EAI_NONAME;
} else if (resolvehoststxt(gethoststxt(), AF_INET, name, ai->ai_addr,
} else if (ResolveHostsTxt(GetHostsTxt(), AF_INET, name, ai->ai_addr,
sizeof(ai->ai_addr4), &canon) > 0) {
memcpy(ai->ai_canonname, canon, min(strlen(canon), DNS_NAME_MAX) + 1);
*res = ai;
return 0;
} else {
rc = resolvedns(getresolvconf(), AF_INET, name, ai->ai_addr,
rc = ResolveDns(GetResolvConf(), AF_INET, name, ai->ai_addr,
sizeof(ai->ai_addr4));
if (rc > 0) {
*res = ai;

View file

@ -53,7 +53,7 @@ static textwindows noinline char *getnthoststxtpath(char *pathbuf,
*
* @note yoinking realloc() ensures there's no size limits
*/
const struct HostsTxt *gethoststxt(void) {
const struct HostsTxt *GetHostsTxt(void) {
FILE *f;
const char *path;
char pathbuf[PATH_MAX];
@ -65,16 +65,16 @@ const struct HostsTxt *gethoststxt(void) {
init->ht.entries.p = init->entries;
init->ht.strings.n = pushpop(ARRAYLEN(init->strings));
init->ht.strings.p = init->strings;
__cxa_atexit(freehoststxt, &g_hoststxt, NULL);
__cxa_atexit(FreeHostsTxt, &g_hoststxt, NULL);
path = "/etc/hosts";
if (IsWindows()) {
path = firstnonnull(getnthoststxtpath(pathbuf, ARRAYLEN(pathbuf)), path);
}
if (!(f = fopen(path, "r")) || parsehoststxt(g_hoststxt, f) == -1) {
if (!(f = fopen(path, "r")) || ParseHostsTxt(g_hoststxt, f) == -1) {
/* TODO(jart): Elevate robustness. */
}
fclose(f);
sorthoststxt(g_hoststxt);
SortHostsTxt(g_hoststxt);
}
return g_hoststxt;
}

107
libc/dns/getnameinfo.c Normal file
View file

@ -0,0 +1,107 @@
/*-*- 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
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
*/
#include "libc/bits/safemacros.internal.h"
#include "libc/calls/calls.h"
#include "libc/dns/consts.h"
#include "libc/dns/dns.h"
#include "libc/dns/hoststxt.h"
#include "libc/dns/resolvconf.h"
#include "libc/fmt/conv.h"
#include "libc/fmt/fmt.h"
#include "libc/mem/mem.h"
#include "libc/sock/sock.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/af.h"
#include "libc/sysv/consts/inaddr.h"
#include "libc/sysv/errfuns.h"
/**
* Resolves name/service for socket address.
*
* @param addr
* @param addrlen
* @param name
* @param namelen
* @param service
* @param servicelen
* @param flags
*
* @return 0 on success or EAI_xxx value
*/
int getnameinfo(const struct sockaddr *addr, socklen_t addrlen, char *name,
socklen_t namelen, char *service, socklen_t servicelen,
int flags) {
char rdomain[1 + sizeof "255.255.255.255.in-addr.arpa"];
char info[512];
int rc, port;
uint8_t *ip;
unsigned int valid_flags;
valid_flags =
(NI_NAMEREQD | NI_NUMERICHOST | NI_NUMERICSERV | NI_NOFQDN | NI_DGRAM);
if (flags & ~(valid_flags)) return EAI_BADFLAGS;
if (!name && !service) return EAI_NONAME;
if (addr->sa_family != AF_INET || addrlen < sizeof(struct sockaddr_in))
return EAI_FAMILY;
ip = (uint8_t *)&(((struct sockaddr_in *)addr)->sin_addr);
sprintf(rdomain, "%d.%d.%d.%d.in-addr.arpa", ip[3], ip[2], ip[1], ip[0]);
info[0] = '\0';
if (name != NULL && namelen != 0) {
if ((flags & NI_NUMERICHOST) && (flags & NI_NAMEREQD)) return EAI_NONAME;
if ((flags & NI_NUMERICHOST) &&
inet_ntop(AF_INET, ip, info, sizeof(info)) == NULL)
return EAI_SYSTEM;
else if (!info[0] && ResolveHostsReverse(GetHostsTxt(), AF_INET, ip, info,
sizeof(info)) < 0)
return EAI_SYSTEM;
else if (!info[0] && ResolveDnsReverse(GetResolvConf(), AF_INET, rdomain,
info, sizeof(info)) < 0)
return EAI_SYSTEM;
else if (!info[0] && (flags & NI_NAMEREQD))
return EAI_NONAME;
else if (!info[0] && inet_ntop(AF_INET, ip, info, sizeof(info)) == NULL)
return EAI_SYSTEM;
if (strlen(info) + 1 > namelen) return EAI_OVERFLOW;
strcpy(name, info);
}
port = ntohs(((struct sockaddr_in *)addr)->sin_port);
info[0] = '\0';
if (service != NULL && servicelen != 0) {
itoa(port, info, 10);
/* TODO: reverse lookup on /etc/services to get name of service */
if (strlen(info) + 1 > servicelen) return EAI_OVERFLOW;
strcpy(service, info);
}
return 0;
}

View file

@ -38,41 +38,39 @@
* this function will append
* @return number of nameservers appended, or -1 w/ errno
*/
textwindows int getntnameservers(struct ResolvConf *resolv) {
textwindows int GetNtNameServers(struct ResolvConf *resolv) {
int rc;
char value8[128];
int64_t hkInterfaces;
struct sockaddr_in nameserver;
char16_t value[128], ifaceuuid[64];
uint32_t i, keycount, valuebytes, ifaceuuidlen;
char16_t value[128], uuid[64];
uint32_t i, keycount, valuebytes, uuidlen;
keycount = 0;
hkInterfaces = kNtInvalidHandleValue;
if (!RegOpenKeyEx(
kNtHkeyLocalMachine,
u"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces",
0, kNtKeyRead, &hkInterfaces) &&
!RegQueryInfoKey(hkInterfaces, NULL, NULL, NULL, &keycount, NULL, NULL,
NULL, NULL, NULL, NULL, NULL)) {
!RegQueryInfoKey(hkInterfaces, 0, 0, 0, &keycount, 0, 0, 0, 0, 0, 0, 0)) {
nameserver.sin_family = AF_INET;
nameserver.sin_port = htons(DNS_PORT);
rc = 0;
for (i = 0; i < keycount; ++i) {
ifaceuuidlen = sizeof(ifaceuuid);
if (!RegEnumKeyEx(hkInterfaces, i, ifaceuuid, &ifaceuuidlen, NULL, NULL,
NULL, NULL) &&
((!RegGetValue(hkInterfaces, ifaceuuid, u"DhcpIpAddress",
uuidlen = sizeof(uuid);
if (!RegEnumKeyEx(hkInterfaces, i, uuid, &uuidlen, 0, 0, 0, 0) &&
((!RegGetValue(hkInterfaces, uuid, u"DhcpIpAddress",
kNtRrfRtRegSz | kNtRrfRtRegMultiSz, NULL, value,
((valuebytes = sizeof(value)), &valuebytes)) &&
valuebytes > 2 * sizeof(char16_t)) ||
(!RegGetValue(hkInterfaces, ifaceuuid, u"IpAddress",
(!RegGetValue(hkInterfaces, uuid, u"IpAddress",
kNtRrfRtRegSz | kNtRrfRtRegMultiSz, NULL, value,
((valuebytes = sizeof(value)), &valuebytes)) &&
valuebytes > 2 * sizeof(char16_t))) &&
((!RegGetValue(hkInterfaces, ifaceuuid, u"DhcpNameServer",
((!RegGetValue(hkInterfaces, uuid, u"DhcpNameServer",
kNtRrfRtRegSz | kNtRrfRtRegMultiSz, NULL, value,
((valuebytes = sizeof(value)), &valuebytes)) &&
valuebytes > 2 * sizeof(char16_t)) ||
(!RegGetValue(hkInterfaces, ifaceuuid, u"NameServer",
(!RegGetValue(hkInterfaces, uuid, u"NameServer",
kNtRrfRtRegSz | kNtRrfRtRegMultiSz, NULL, value,
((valuebytes = sizeof(value)), &valuebytes)) &&
valuebytes > 2 * sizeof(char16_t)))) {

View file

@ -34,7 +34,7 @@ static struct ResolvConfInitialStaticMemory {
/**
* Returns singleton with DNS server address.
*/
const struct ResolvConf *getresolvconf(void) {
const struct ResolvConf *GetResolvConf(void) {
int rc;
FILE *f;
struct ResolvConfInitialStaticMemory *init;
@ -43,16 +43,16 @@ const struct ResolvConf *getresolvconf(void) {
g_resolvconf = &init->rv;
pushmov(&init->rv.nameservers.n, ARRAYLEN(init->nameservers));
init->rv.nameservers.p = init->nameservers;
__cxa_atexit(freeresolvconf, &g_resolvconf, NULL);
__cxa_atexit(FreeResolvConf, &g_resolvconf, NULL);
if (!IsWindows()) {
if ((f = fopen("/etc/resolv.conf", "r"))) {
rc = parseresolvconf(g_resolvconf, f);
rc = ParseResolvConf(g_resolvconf, f);
} else {
rc = -1;
}
fclose(f);
} else {
rc = getntnameservers(g_resolvconf);
rc = GetNtNameServers(g_resolvconf);
}
if (rc == -1 && !IsTiny()) {
/* TODO(jart): Elevate robustness. */

View file

@ -1,26 +1,23 @@
#ifndef COSMOPOLITAN_LIBC_DNS_HOSTSTXT_H_
#define COSMOPOLITAN_LIBC_DNS_HOSTSTXT_H_
#include "libc/sock/sock.h"
#include "libc/stdio/stdio.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
struct FILE;
struct sockaddr;
struct HostsTxtEntry {
unsigned char ip[4]; /* inet_ntop(AF_INET, he->ip, buf, size) */
uint32_t name; /* &ht->strings.p[he->name] */
uint32_t canon; /* &ht->strings.p[he->canon] */
uint8_t ip[4]; /* inet_ntop(AF_INET, he->ip, buf, size) */
uint32_t name; /* &ht->strings.p[he->name] */
uint32_t canon; /* &ht->strings.p[he->canon] */
};
struct HostsTxtEntries {
size_t i;
size_t n;
size_t i, n;
struct HostsTxtEntry *p;
};
struct HostsTxtStrings {
size_t i;
size_t n;
size_t i, n;
char *p;
};
@ -29,13 +26,15 @@ struct HostsTxt {
struct HostsTxtStrings strings;
};
const struct HostsTxt *gethoststxt(void) returnsnonnull;
void freehoststxt(struct HostsTxt **) paramsnonnull();
int parsehoststxt(struct HostsTxt *, struct FILE *) paramsnonnull();
void sorthoststxt(struct HostsTxt *) paramsnonnull();
int resolvehoststxt(const struct HostsTxt *, int, const char *,
const struct HostsTxt *GetHostsTxt(void) returnsnonnull;
void FreeHostsTxt(struct HostsTxt **) paramsnonnull();
int ParseHostsTxt(struct HostsTxt *, FILE *) paramsnonnull();
void SortHostsTxt(struct HostsTxt *) paramsnonnull();
int ResolveHostsTxt(const struct HostsTxt *, int, const char *,
struct sockaddr *, uint32_t, const char **)
paramsnonnull((1, 3));
int ResolveHostsReverse(const struct HostsTxt *, int, const uint8_t *, char *,
size_t) paramsnonnull((1, 3));
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -43,7 +43,7 @@
* @return 0 on success, or -1 w/ errno
* @see hoststxtsort() which is the logical next step
*/
int parsehoststxt(struct HostsTxt *ht, FILE *f) {
int ParseHostsTxt(struct HostsTxt *ht, FILE *f) {
char *line;
size_t linesize;
struct HostsTxtEntry entry;

View file

@ -41,7 +41,7 @@
* @param f is an open stream with file content
* @return number of nameservers appended, or -1 w/ errno
*/
int parseresolvconf(struct ResolvConf *resolv, struct FILE *f) {
int ParseResolvConf(struct ResolvConf *resolv, struct FILE *f) {
/* TODO(jart): options ndots:5 */
int rc;
char *line;
@ -49,7 +49,7 @@ int parseresolvconf(struct ResolvConf *resolv, struct FILE *f) {
struct sockaddr_in nameserver;
char *directive, *value, *tok, *comment;
rc = 0;
line = NULL;
line = 0;
linesize = 0;
nameserver.sin_family = AF_INET;
nameserver.sin_port = htons(DNS_PORT);

View file

@ -30,7 +30,7 @@
* @param name is a dotted NUL-terminated hostname string
* @return bytes written (excluding NUL) or -1 w/ errno
*/
int pascalifydnsname(uint8_t *buf, size_t size, const char *name) {
int PascalifyDnsName(uint8_t *buf, size_t size, const char *name) {
size_t i, j, k, namelen;
if ((namelen = strlen(name)) > DNS_NAME_MAX) return enametoolong();
i = 0;

View file

@ -14,10 +14,10 @@ struct ResolvConf {
struct Nameservers nameservers;
};
const struct ResolvConf *getresolvconf(void) returnsnonnull;
int parseresolvconf(struct ResolvConf *, struct FILE *) paramsnonnull();
void freeresolvconf(struct ResolvConf **) paramsnonnull();
int getntnameservers(struct ResolvConf *) paramsnonnull();
const struct ResolvConf *GetResolvConf(void) returnsnonnull;
int ParseResolvConf(struct ResolvConf *, struct FILE *) paramsnonnull();
void FreeResolvConf(struct ResolvConf **) paramsnonnull();
int GetNtNameServers(struct ResolvConf *) paramsnonnull();
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -38,7 +38,7 @@
/**
* Queries Domain Name System for address associated with name.
*
* @param resolvconf can be getresolvconf()
* @param resolvconf can be GetResolvConf()
* @param af can be AF_INET, AF_UNSPEC
* @param name can be a local or fully-qualified hostname
* @param addr should point to a struct sockaddr_in; if this function
@ -47,65 +47,62 @@
* @return number of matches found, or -1 w/ errno
* @error EAFNOSUPPORT. ENETDOWN, ENAMETOOLONG, EBADMSG
*/
int resolvedns(const struct ResolvConf *resolvconf, int af, const char *name,
int ResolveDns(const struct ResolvConf *resolvconf, int af, const char *name,
struct sockaddr *addr, uint32_t addrsize) {
size_t msgsize;
int res, fd, rc, rc2;
struct sockaddr_in *addr4;
struct DnsQuestion question;
int rc, fd, n;
struct DnsQuestion q;
struct DnsHeader h, h2;
struct sockaddr_in *a4;
uint8_t *p, *pe, msg[512];
uint16_t rtype, rclass, rdlength;
uint8_t *p, *pe, *outmsg, *inmsg;
struct DnsHeader header, response;
if (af != AF_INET && af != AF_UNSPEC) return eafnosupport();
if (!resolvconf->nameservers.i) return 0;
memset(&header, 0, sizeof(header));
header.id = rand32();
header.bf1 = 1; /* recursion desired */
header.qdcount = 1;
question.qname = name;
question.qtype = DNS_TYPE_A;
question.qclass = DNS_CLASS_IN;
res = -1;
if ((outmsg = malloc(kMsgMax)) && (inmsg = malloc(kMsgMax)) &&
(rc = serializednsheader(outmsg, kMsgMax, header)) != -1 &&
(rc2 = serializednsquestion(outmsg + rc, kMsgMax - rc, question)) != -1) {
msgsize = rc + rc2;
if ((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) != -1 &&
sendto(fd, outmsg, msgsize, 0, (void *)&resolvconf->nameservers.p[0],
sizeof(resolvconf->nameservers.p[0])) == msgsize) {
if ((rc = recv(fd, inmsg, kMsgMax, 0)) != -1 &&
(rc2 = deserializednsheader(&response, inmsg, rc)) != -1 &&
response.id == header.id) {
res = 0;
if (response.ancount) {
p = inmsg + rc2;
pe = inmsg + rc;
while (p < pe && response.qdcount) {
p += strnlen((char *)p, pe - p) + 1 + 4;
response.qdcount--;
memset(&h, 0, sizeof(h));
rc = ebadmsg();
h.id = rand32();
h.bf1 = 1; /* recursion desired */
h.qdcount = 1;
q.qname = name;
q.qtype = DNS_TYPE_A;
q.qclass = DNS_CLASS_IN;
memset(msg, 0, sizeof(msg));
SerializeDnsHeader(msg, &h);
if ((n = SerializeDnsQuestion(msg + 12, 500, &q)) == -1) return -1;
if ((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) return -1;
if (sendto(fd, msg, 12 + n, 0, resolvconf->nameservers.p,
sizeof(*resolvconf->nameservers.p)) == 12 + n &&
(n = read(fd, msg, 512)) >= 12) {
DeserializeDnsHeader(&h2, msg);
if (h2.id == h.id) {
rc = 0;
if (h2.ancount) {
p = msg + 12;
pe = msg + n;
while (p < pe && h2.qdcount) {
p += strnlen((char *)p, pe - p) + 1 + 4;
h2.qdcount--;
}
if (p + 1 < pe) {
if ((p[0] & 0b11000000) == 0b11000000) { /* name pointer */
p += 2;
} else {
p += strnlen((char *)p, pe - p) + 1;
}
if (p + 1 < pe) {
if ((p[0] & 0b11000000) == 0b11000000) { /* name pointer */
p += 2;
} else {
p += strnlen((char *)p, pe - p) + 1;
}
if (p + 2 + 2 + 4 + 2 < pe) {
rtype = READ16BE(p), p += 2;
rclass = READ16BE(p), p += 2;
/* ttl */ p += 4;
rdlength = READ16BE(p), p += 2;
if (p + rdlength <= pe && rdlength == 4 &&
(rtype == DNS_TYPE_A && rclass == DNS_CLASS_IN)) {
res = 1;
if (addrsize) {
if (addrsize >= kMinSockaddr4Size) {
addr4 = (struct sockaddr_in *)addr;
addr4->sin_family = AF_INET;
memcpy(&addr4->sin_addr.s_addr, p, 4);
} else {
res = einval();
}
if (p + 2 + 2 + 4 + 2 < pe) {
rtype = READ16BE(p), p += 2;
rclass = READ16BE(p), p += 2;
/* ttl */ p += 4;
rdlength = READ16BE(p), p += 2;
if (p + rdlength <= pe && rdlength == 4 &&
(rtype == DNS_TYPE_A && rclass == DNS_CLASS_IN)) {
rc = 1;
if (addrsize) {
if (addrsize >= kMinSockaddr4Size) {
a4 = (struct sockaddr_in *)addr;
a4->sin_family = AF_INET;
memcpy(&a4->sin_addr.s_addr, p, 4);
} else {
rc = einval();
}
}
}
@ -113,8 +110,7 @@ int resolvedns(const struct ResolvConf *resolvconf, int af, const char *name,
}
}
}
res |= close(fd);
}
free(outmsg);
return res;
close(fd);
return rc;
}

View file

@ -0,0 +1,132 @@
/*-*- 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
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
*/
#include "libc/bits/bits.h"
#include "libc/calls/calls.h"
#include "libc/dns/consts.h"
#include "libc/dns/dns.h"
#include "libc/dns/dnsheader.h"
#include "libc/dns/dnsquestion.h"
#include "libc/dns/resolvconf.h"
#include "libc/mem/mem.h"
#include "libc/rand/rand.h"
#include "libc/runtime/runtime.h"
#include "libc/sock/sock.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/af.h"
#include "libc/sysv/consts/ipproto.h"
#include "libc/sysv/consts/sock.h"
#include "libc/sysv/errfuns.h"
#define kMsgMax 512
/**
* Performs reverse DNS lookup with IP address.
*
* @param resolvconf can be GetResolvConf()
* @param af can be AF_INET, AF_UNSPEC
* @param name is a reversed IP address string ending with .in-addr.arpa
* @param buf to store the obtained hostname if any
* @param bufsize is size of buf
*
* @return 0 on success, or -1 w/ errno
* @error EAFNOSUPPORT, ENETDOWN, ENAMETOOLONG, EBADMSG
*/
int ResolveDnsReverse(const struct ResolvConf *resolvconf, int af,
const char *name, char *buf, size_t bufsize) {
int rc, fd, n;
struct DnsQuestion q;
struct DnsHeader h, h2;
uint8_t *p, *pe, msg[512];
uint16_t rtype, rclass, rdlength;
if (af != AF_INET && af != AF_UNSPEC) return eafnosupport();
if (!resolvconf->nameservers.i) return 0;
memset(&h, 0, sizeof(h));
rc = ebadmsg();
h.id = rand32();
h.bf1 = 1; /* recursion desired */
h.qdcount = 1;
q.qname = name;
q.qtype = DNS_TYPE_PTR;
q.qclass = DNS_CLASS_IN;
memset(msg, 0, sizeof(msg));
SerializeDnsHeader(msg, &h);
if ((n = SerializeDnsQuestion(msg + 12, 500, &q)) == -1) return -1;
if ((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) return -1;
if (sendto(fd, msg, 12 + n, 0, resolvconf->nameservers.p,
sizeof(*resolvconf->nameservers.p)) == 12 + n &&
(n = read(fd, msg, 512)) >= 12) {
DeserializeDnsHeader(&h2, msg);
if (h2.id == h.id) {
rc = 0;
if (h2.ancount) {
p = msg + 12;
pe = msg + n;
while (p < pe && h2.qdcount) {
p += strnlen((char *)p, pe - p) + 1 + 4;
h2.qdcount--;
}
if (p + 1 < pe) {
if ((p[0] & 0b11000000) == 0b11000000) { /* name pointer */
p += 2;
} else {
p += strnlen((char *)p, pe - p) + 1;
}
if (p + 2 + 2 + 4 + 2 < pe) {
rtype = READ16BE(p), p += 2;
rclass = READ16BE(p), p += 2;
/* ttl */ p += 4;
rdlength = READ16BE(p), p += 2;
if (p + rdlength <= pe && rtype == DNS_TYPE_PTR &&
rclass == DNS_CLASS_IN) {
if (strnlen((char *)p, pe - p) + 1 > bufsize)
rc = -1;
else {
/* domain name starts with a letter */
for (; !isalnum((char)(*p)) && p < pe; p++) rdlength--;
for (char *tmp = (char *)p; rdlength > 0 && *tmp != '\0';
tmp++) {
/* each label is alphanumeric or hyphen
* any other character is assumed separator */
if (!isalnum(*tmp) && *tmp != '-') *tmp = '.';
rdlength--;
}
strcpy(buf, (char *)p);
}
} else
rc = -1;
}
}
}
}
}
close(fd);
return rc;
}

View file

@ -0,0 +1,45 @@
#include "libc/alg/alg.h"
#include "libc/dns/consts.h"
#include "libc/dns/dns.h"
#include "libc/dns/hoststxt.h"
#include "libc/sock/sock.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/af.h"
#include "libc/sysv/errfuns.h"
/**
* Finds name associated with address in HOSTS.TXT table.
*
* @param ht can be GetHostsTxt()
* @param af can be AF_INET
* @param ip is IP address in binary (sin_addr)
* @param buf is buffer to store the name
* @param bufsize is length of buf
*
* @return 1 if found, 0 if not found, or -1 w/ errno
* @error EAFNOSUPPORT
*/
int ResolveHostsReverse(const struct HostsTxt *ht, int af, const uint8_t *ip,
char *buf, size_t bufsize) {
struct HostsTxtEntry *entry = NULL;
uint32_t v1, v2;
if (af != AF_INET && af != AF_UNSPEC) return eafnosupport();
if (!ht->entries.p || !buf || bufsize == 0) return -1;
v1 = *((uint32_t *)ip);
for (size_t j = 0; j < ht->entries.i; j++) {
v2 = *((uint32_t *)ht->entries.p[j].ip);
if (v1 == v2) {
entry = &(ht->entries.p[j]);
break;
}
}
if (entry) {
strncpy(buf, &ht->strings.p[entry->name], bufsize);
return 1;
}
return 0;
}

View file

@ -27,16 +27,16 @@
static int hoststxtgetcmp(const char *node, const struct HostsTxtEntry *entry,
const char *strings) {
return dnsnamecmp(node, &strings[entry->name]);
return CompareDnsNames(node, &strings[entry->name]);
}
/**
* Finds address associated with name in HOSTS.TXT table.
*
* This function performs binary search, so sorthoststxt() must be
* This function performs binary search, so SortHostsTxt() must be
* called on the table beforehand.
*
* @param ht can be gethoststxt()
* @param ht can be GetHostsTxt()
* @param af can be AF_INET, AF_UNSPEC
* @param name can be a local or fully-qualified hostname
* @param addr should point to a struct sockaddr_in; if this function
@ -46,7 +46,7 @@ static int hoststxtgetcmp(const char *node, const struct HostsTxtEntry *entry,
* @return number of matches found, or -1 w/ errno
* @error EAFNOSUPPORT
*/
int resolvehoststxt(const struct HostsTxt *ht, int af, const char *name,
int ResolveHostsTxt(const struct HostsTxt *ht, int af, const char *name,
struct sockaddr *addr, uint32_t addrsize,
const char **canon) {
struct sockaddr_in *addr4;

View file

@ -26,11 +26,14 @@
* @return number of bytes written
* @see pascalifydnsname()
*/
int serializednsquestion(uint8_t *buf, size_t size, struct DnsQuestion dq) {
int SerializeDnsQuestion(uint8_t *buf, size_t size,
const struct DnsQuestion *dq) {
int wrote;
if ((wrote = pascalifydnsname(buf, size, dq.qname)) == -1) return -1;
if ((wrote = PascalifyDnsName(buf, size, dq->qname)) == -1) return -1;
if (wrote + 1 + 4 > size) return enospc();
buf[wrote + 1] = dq.qtype >> 010, buf[wrote + 2] = dq.qtype >> 000;
buf[wrote + 3] = dq.qclass >> 010, buf[wrote + 4] = dq.qclass >> 000;
buf[wrote + 1] = dq->qtype >> 8;
buf[wrote + 2] = dq->qtype;
buf[wrote + 3] = dq->qclass >> 8;
buf[wrote + 4] = dq->qclass;
return wrote + 5;
}

View file

@ -22,25 +22,26 @@
/**
* Compares hostnames in HOSTS.TXT table.
* @see dnsnamecmp(), parsehoststxt()
* @see CompareDnsNames(), ParseHostsTxt()
*/
static int cmphoststxt(const struct HostsTxtEntry *e1,
const struct HostsTxtEntry *e2, const char *strings) {
if (e1 == e2) return 0;
return dnsnamecmp(&strings[e1->name], &strings[e2->name]);
return CompareDnsNames(&strings[e1->name], &strings[e2->name]);
}
/**
* Sorts entries in HOSTS.TXT table.
*
* This function enables resolvehoststxt() to be called so hard-coded
* This function enables ResolveHostsTxt() to be called so hard-coded
* hostname lookups take logarithmic time; you can blackhole all the
* spam you want, in your /etc/hosts file.
*
* The sorted order, defined by dnsnamecmp(), also makes it possible to
* efficiently search for subdomains, once the initial sort is done.
* The sorted order, defined by CompareDnsNames(), also makes it
* possible to efficiently search for subdomains, once the initial sort
* is done.
*/
void sorthoststxt(struct HostsTxt *ht) {
void SortHostsTxt(struct HostsTxt *ht) {
if (ht->entries.p) {
qsort_r(ht->entries.p, ht->entries.i, sizeof(*ht->entries.p),
(void *)cmphoststxt, ht->strings.p);

9
libc/dos.h Normal file
View file

@ -0,0 +1,9 @@
#ifndef COSMOPOLITAN_LIBC_DOS_H_
#define COSMOPOLITAN_LIBC_DOS_H_
#define DOS_DATE(YEAR, MONTH_IDX1, DAY_IDX1) \
(((YEAR)-1980) << 9 | (MONTH_IDX1) << 5 | (DAY_IDX1))
#define DOS_TIME(HOUR, MINUTE, SECOND) \
((HOUR) << 11 | (MINUTE) << 5 | (SECOND) >> 1)
#endif /* COSMOPOLITAN_LIBC_DOS_H_ */

View file

@ -308,7 +308,7 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
/* evaluate specifier */
qchar = '"';
log2base = 0;
alphabet = "0123456789abcdef";
alphabet = "0123456789abcdefpx";
switch ((d = *format++)) {
case 'p':
flags |= FLAGS_HASH;
@ -316,7 +316,7 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
signbit = 63;
goto FormatNumber;
case 'X':
alphabet = "0123456789ABCDEF";
alphabet = "0123456789ABCDEFPX";
/* fallthrough */
case 'x':
log2base = 4;
@ -548,8 +548,7 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
} else {
PUT('+');
}
for (c = 2, k = 10; 10 * k <= decpt; c++, k *= 10) {
}
for (c = 2, k = 10; 10 * k <= decpt; c++) k *= 10;
for (;;) {
i1 = decpt / k;
PUT(i1 + '0');
@ -612,7 +611,7 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
if (pun.d && prec < 13) {
pun.u[1] |= 0x100000;
if (prec < 5) {
ui = 1 << ((5 - prec) * 4 - 1);
ui = 1u << ((5 - prec) * 4 - 1);
if (pun.u[1] & ui) {
if (pun.u[1] & ((ui - 1) | (ui << 1)) || pun.u[0]) {
pun.u[1] += ui;
@ -631,7 +630,7 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
}
} else {
i1 = (13 - prec) * 4;
ui = 1 << (i1 - 1);
ui = 1u << (i1 - 1);
if (pun.u[0] & ui && pun.u[0] & ((ui - 1) | (ui << 1))) {
pun.u[0] += ui;
if (!(pun.u[0] >> i1)) goto BumpIt;
@ -640,12 +639,13 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
}
} else {
if ((ui = pun.u[0])) {
for (prec = 6; (ui = (ui << 4) & 0xffffffff); ++prec) {
}
ui = __builtin_ctz(ui);
prec = 6 + ((32 - ROUNDDOWN(ui, 4)) >> 2) - 1;
} else if ((ui = pun.u[1] & 0xfffff)) {
ui = __builtin_ctz(ui);
prec = (20 - ROUNDDOWN(ui, 4)) >> 2;
} else {
for (prec = 0, ui = pun.u[1] & 0xfffff; ui;
++prec, ui = (ui << 4) & 0xfffff) {
}
prec = 0;
}
}
bw = 1;
@ -656,7 +656,7 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
i1 /= 10;
}
}
if ((sgn = pun.u[1] & 0x80000000)) {
if (pun.u[1] & 0x80000000) {
pun.u[1] &= 0x7fffffff;
if (pun.d || sign) sign = '-';
}
@ -685,18 +685,9 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
PUT(alphabet[17]);
PUT(c);
if (prec > 0 || alt) PUT('.');
if (prec > 0) {
if ((i1 = prec) > 5) i1 = 5;
prec -= i1;
do {
PUT(alphabet[(pun.u[1] >> 16) & 0xf]);
pun.u[1] <<= 4;
} while (--i1 > 0);
while (prec > 0) {
--prec;
PUT(alphabet[(pun.u[0] >> 28) & 0xf]);
pun.u[0] <<= 4;
}
while (prec-- > 0) {
PUT(alphabet[(pun.q >> 48) & 0xf]);
pun.q <<= 4;
}
PUT(alphabet[16]);
if (bex < 0) {
@ -705,8 +696,7 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
} else {
PUT('+');
}
for (c = 1; 10 * c <= bex; c *= 10) {
}
for (c = 1; 10 * c <= bex;) c *= 10;
for (;;) {
i1 = bex / c;
PUT('0' + i1);
@ -714,7 +704,7 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
bex -= i1 * c;
bex *= 10;
}
continue;
break;
case '%':
PUT('%');

View file

@ -68,11 +68,6 @@ o/$(MODE)/libc/fmt/filetimetotimeval.o: \
OVERRIDE_CFLAGS += \
-O3
o/$(MODE)/libc/fmt/itoa64radix10.greg.o \
o/$(MODE)/libc/fmt/itoa128radix10.greg.o: \
OVERRIDE_CFLAGS += \
-fwrapv
LIBC_FMT_LIBS = $(foreach x,$(LIBC_FMT_ARTIFACTS),$($(x)))
LIBC_FMT_SRCS = $(foreach x,$(LIBC_FMT_ARTIFACTS),$($(x)_SRCS))
LIBC_FMT_HDRS = $(foreach x,$(LIBC_FMT_ARTIFACTS),$($(x)_HDRS))

View file

@ -49,5 +49,5 @@ noinline size_t uint128toarray_radix10(uint128_t i, char *a) {
size_t int128toarray_radix10(int128_t i, char *a) {
if (i >= 0) return uint128toarray_radix10(i, a);
*a++ = '-';
return 1 + uint128toarray_radix10(-i, a);
return 1 + uint128toarray_radix10(-(uint128_t)i, a);
}

View file

@ -35,7 +35,7 @@ noinline size_t uint64toarray(uint64_t i, char *a, int r) {
size_t int64toarray(int64_t i, char *a, int r) {
if (i < 0) {
*a++ = '-';
i = -i;
i = -(uint64_t)i;
}
return uint64toarray(i, a, r);
}

View file

@ -27,14 +27,10 @@
* @return bytes written w/o nul
*/
noinline size_t uint64toarray_radix10(uint64_t i, char a[hasatleast 21]) {
size_t j;
j = 0;
size_t j = 0;
do {
struct {
uint64_t q, r;
} x = {i / 10, i % 10};
a[j++] = x.r + '0';
i = x.q;
a[j++] = i % 10 + '0';
i = i / 10;
} while (i > 0);
a[j] = '\0';
reverse(a, j);
@ -49,5 +45,5 @@ noinline size_t uint64toarray_radix10(uint64_t i, char a[hasatleast 21]) {
size_t int64toarray_radix10(int64_t i, char a[hasatleast 21]) {
if (i >= 0) return uint64toarray_radix10(i, a);
*a++ = '-';
return 1 + uint64toarray_radix10(-i, a);
return 1 + uint64toarray_radix10(-(uint64_t)i, a);
}

View file

@ -21,7 +21,7 @@
.macro .e e
.long \e - kErrorNames
.long 1f - kErrorNames
.section .rodata.str1.1
.rodata.str1.1
1: .string "\e"
.previous
.endm
@ -114,51 +114,5 @@ kErrorNames:
.e ENOTRECOVERABLE
.e ENONET
.e ERESTART
.e ECHRNG
.e EL2NSYNC
.e EL3HLT
.e EL3RST
.e ELNRNG
.e EUNATCH
.e ENOCSI
.e EL2HLT
.e EBADE
.e EBADR
.e EXFULL
.e ENOANO
.e EBADRQC
.e EBADSLT
.e ENOSTR
.e ENODATA
.e ENOSR
.e ENOPKG
.e ENOLINK
.e EADV
.e ESRMNT
.e ECOMM
.e EMULTIHOP
.e EDOTDOT
.e ENOTUNIQ
.e EBADFD
.e EREMCHG
.e ELIBACC
.e ELIBBAD
.e ELIBSCN
.e ELIBMAX
.e ELIBEXEC
.e ESTRPIPE
.e EUCLEAN
.e ENOTNAM
.e ENAVAIL
.e EISNAM
.e EREMOTEIO
.e ENOMEDIUM
.e EMEDIUMTYPE
.e ENOKEY
.e EKEYEXPIRED
.e EKEYREVOKED
.e EKEYREJECTED
.e ERFKILL
.e EHWPOISON
.long 0
.endobj kErrorNames,globl,hidden

View file

@ -584,6 +584,13 @@ typedef uint64_t uintmax_t;
#define noasan
#endif
#if (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 408 || \
__has_attribute(__no_sanitize_undefined__)
#define noubsan __attribute__((__no_sanitize_undefined__))
#else
#define noubsan
#endif
#ifndef unreachable
#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
#define unreachable __builtin_unreachable()

View file

@ -21,6 +21,7 @@
#include "libc/bits/likely.h"
#include "libc/bits/weaken.h"
#include "libc/calls/calls.h"
#include "libc/calls/struct/iovec.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/log/log.h"
@ -116,7 +117,7 @@ struct AsanMorgue {
static struct AsanMorgue __asan_morgue;
static uint64_t __asan_bsrl(uint64_t x) {
static inline int __asan_bsrl(uint64_t x) {
return __builtin_clzll(x) ^ 63;
}
@ -137,7 +138,7 @@ static size_t __asan_strlen(const char *s) {
static int __asan_strcmp(const char *l, const char *r) {
size_t i = 0;
while (l[i] == r[i] && r[i]) ++i;
return (l[i] & 0xff) - (r[i] & 0xff);
return (l[i] & 255) - (r[i] & 255);
}
static char *__asan_stpcpy(char *d, const char *s) {
@ -168,7 +169,7 @@ static void *__asan_memset(void *p, int c, size_t n) {
size_t i;
uint64_t x;
b = p;
x = 0x0101010101010101 * (c & 0xff);
x = 0x0101010101010101ul * (c & 255);
switch (n) {
case 0:
return p;
@ -293,73 +294,105 @@ static void *__asan_memcpy(void *dst, const void *src, size_t n) {
return dst;
}
static size_t __asan_int2hex(uint64_t x, char b[17], uint8_t k) {
int i;
char *p;
for (p = b; k > 0;) {
*p++ = "0123456789abcdef"[(x >> (k -= 4)) & 15];
}
*p = '\0';
return p - b;
static char *__asan_hexcpy(char *p, uint64_t x, uint8_t k) {
while (k) *p++ = "0123456789abcdef"[(x >> (k -= 4)) & 15];
return p;
}
static size_t __asan_uint2str(uint64_t i, char *a) {
size_t j;
j = 0;
static char *__asan_uint2str(char *p, uint64_t i) {
int j = 0;
do {
a[j++] = i % 10 + '0';
p[j++] = i % 10 + '0';
i /= 10;
} while (i > 0);
a[j] = '\0';
reverse(a, j);
return j;
reverse(p, j);
return p + j;
}
static size_t __asan_int2str(int64_t i, char *a) {
if (i >= 0) return __asan_uint2str(i, a);
*a++ = '-';
return 1 + __asan_uint2str(-i, a);
static char *__asan_intcpy(char *p, int64_t i) {
if (i >= 0) return __asan_uint2str(p, i);
*p++ = '-';
return __asan_uint2str(p, -i);
}
void __asan_poison(uintptr_t p, size_t n, int kind) {
int k;
char *s;
if (!n) return;
if (UNLIKELY(p & 7)) {
k = MIN(8 - (p & 7), n);
s = SHADOW(p);
if (*s == 0 || *s > (p & 7)) {
*s = p & 7;
}
n -= k;
p += k;
void __asan_poison(uintptr_t p, size_t n, int t) {
signed char k, *s;
k = p & 7;
s = (signed char *)((p >> 3) + 0x7fff8000);
if (UNLIKELY(k)) {
if (n && (!*s || *s > k) && 8 - k >= n) *s = k;
++s, n -= MIN(8 - k, n);
}
__asan_memset(SHADOW(p), kind, n >> 3);
__asan_memset(s, t, n >> 3);
if ((k = n & 7)) {
s = SHADOW(p + n);
if (*s < 0 || (*s > 0 && *s >= k)) {
*s = kind;
}
s += n >> 3;
if (*s < 0 || 0 < *s && *s <= k) *s = t;
}
}
void __asan_unpoison(uintptr_t p, size_t n) {
int k;
char *s;
if (!n) return;
if (UNLIKELY(p & 7)) {
k = MIN(8 - (p & 7), n);
s = SHADOW(p);
*s = 0;
n -= k;
p += k;
signed char k, *s;
k = p & 7;
s = (signed char *)((p >> 3) + 0x7fff8000);
if (UNLIKELY(k)) {
if (n) *s = 0;
++s, n -= MIN(8 - k, n);
}
__asan_memset(SHADOW(p), 0, n >> 3);
__asan_memset(s, 0, n >> 3);
if ((k = n & 7)) {
s = SHADOW(p + n);
if (*s && *s < k) {
*s = k;
s += n >> 3;
if (*s && *s < k) *s = k;
}
}
bool __asan_is_valid(const void *p, size_t n) {
signed char k, *s, *e;
if (n) {
k = (uintptr_t)p & 7;
s = (signed char *)(((uintptr_t)p >> 3) + 0x7fff8000);
if (UNLIKELY(k)) {
if (n && !(!*s || *s >= k + n)) return false;
++s, n -= MIN(8 - k, n);
}
e = s;
k = n & 7;
e += n >> 3;
for (; s + 8 <= e; s += 8) {
if ((uint64_t)(255 & s[0]) << 000 | (uint64_t)(255 & s[1]) << 010 |
(uint64_t)(255 & s[2]) << 020 | (uint64_t)(255 & s[3]) << 030 |
(uint64_t)(255 & s[4]) << 040 | (uint64_t)(255 & s[5]) << 050 |
(uint64_t)(255 & s[6]) << 060 | (uint64_t)(255 & s[7]) << 070) {
return false;
}
}
while (s < e) {
if (*s++) {
return false;
}
}
if (k) {
if (!(!*s || *s >= k)) {
return false;
}
}
}
return true;
}
bool __asan_is_valid_iov(const struct iovec *iov, int iovlen) {
int i;
size_t size;
if (iovlen >= 0 &&
!__builtin_mul_overflow(iovlen, sizeof(struct iovec), &size) &&
__asan_is_valid(iov, size)) {
for (i = 0; i < iovlen; ++i) {
if (!__asan_is_valid(iov[i].iov_base, iov[i].iov_len)) {
return false;
}
}
return true;
} else {
return false;
}
}
@ -376,7 +409,7 @@ static const char *__asan_dscribe_heap_poison(long c) {
}
}
static const char *__asan_describe_access_poison(char *p) {
static const char *__asan_describe_access_poison(signed char *p) {
int c = p[0];
if (1 <= c && c <= 7) c = p[1];
switch (c) {
@ -445,15 +478,10 @@ static ssize_t __asan_write_string(const char *s) {
return __asan_write(s, __asan_strlen(s));
}
static wontreturn void __asan_abort(void) {
if (weaken(__die)) weaken(__die)();
__asan_exit(134);
}
static wontreturn void __asan_die(const char *msg) {
__asan_write_string(msg);
if (weaken(__die)) weaken(__die)();
__asan_abort();
__asan_exit(134);
}
static char *__asan_report_start(char *p) {
@ -472,9 +500,9 @@ static wontreturn void __asan_report_heap_fault(void *addr, long c) {
p = __asan_report_start(buf);
p = __asan_stpcpy(p, __asan_dscribe_heap_poison(c));
p = __asan_stpcpy(p, " at 0x");
p = __asan_mempcpy(p, ibuf, __asan_int2hex((intptr_t)addr, ibuf, 48));
p = __asan_hexcpy(p, (intptr_t)addr, 48);
p = __asan_stpcpy(p, " shadow 0x");
p = __asan_mempcpy(p, ibuf, __asan_int2hex((intptr_t)SHADOW(addr), ibuf, 48));
p = __asan_hexcpy(p, (intptr_t)SHADOW(addr), 48);
p = __asan_stpcpy(p, "\r\n");
__asan_die(buf);
}
@ -485,20 +513,20 @@ static wontreturn void __asan_report_memory_fault(uint8_t *addr, int size,
p = __asan_report_start(buf);
p = __asan_stpcpy(p, __asan_describe_access_poison(SHADOW(addr)));
p = __asan_stpcpy(p, " ");
p = __asan_mempcpy(p, ibuf, __asan_int2str(size, ibuf));
p = __asan_intcpy(p, size);
p = __asan_stpcpy(p, "-byte ");
p = __asan_stpcpy(p, kind);
p = __asan_stpcpy(p, " at 0x");
p = __asan_mempcpy(p, ibuf, __asan_int2hex((intptr_t)addr, ibuf, 48));
p = __asan_hexcpy(p, (uintptr_t)addr, 48);
p = __asan_stpcpy(p, " shadow 0x");
p = __asan_mempcpy(p, ibuf, __asan_int2hex((intptr_t)SHADOW(addr), ibuf, 48));
p = __asan_hexcpy(p, (uintptr_t)SHADOW(addr), 48);
p = __asan_stpcpy(p, "\r\n");
__asan_die(buf);
}
const void *__asan_morgue_add(void *p) {
void *r;
unsigned i, j;
int i, j;
for (;;) {
i = __asan_morgue.i;
j = (i + 1) & (ARRAYLEN(__asan_morgue.p) - 1);
@ -511,8 +539,8 @@ const void *__asan_morgue_add(void *p) {
}
static void __asan_morgue_flush(void) {
int i;
void *p;
unsigned i;
for (i = 0; i < ARRAYLEN(__asan_morgue.p); ++i) {
p = __asan_morgue.p[i];
if (cmpxchg(__asan_morgue.p + i, p, NULL)) {
@ -532,15 +560,16 @@ static size_t __asan_heap_size(size_t n) {
}
static void *__asan_allocate(size_t a, size_t n, int underrun, int overrun) {
char *p;
size_t c;
char *p, *f;
if ((p = weaken(dlmemalign)(a, __asan_heap_size(n)))) {
c = weaken(dlmalloc_usable_size)(p);
__asan_unpoison((uintptr_t)p, n);
__asan_poison((uintptr_t)p - 16, 16, underrun); /* see dlmalloc design */
__asan_poison((uintptr_t)p + n, c - n, overrun);
__asan_memset(p, 0xF9, n);
WRITE64BE(p + c - sizeof(n), n);
f = p + c - 8;
WRITE64BE(f, n);
}
return p;
}
@ -548,7 +577,7 @@ static void *__asan_allocate(size_t a, size_t n, int underrun, int overrun) {
static size_t __asan_malloc_usable_size(const void *p) {
size_t c, n;
if ((c = weaken(dlmalloc_usable_size)(p)) >= 8) {
if ((n = READ64BE((char *)p + c - sizeof(n))) <= c) {
if ((n = READ64BE((char *)p + c - 8)) <= c) {
return n;
} else {
__asan_report_heap_fault(p, n);
@ -561,9 +590,9 @@ static size_t __asan_malloc_usable_size(const void *p) {
static void __asan_deallocate(char *p, long kind) {
size_t c, n;
if ((c = weaken(dlmalloc_usable_size)(p)) >= 8) {
if ((n = READ64BE((char *)p + c - sizeof(n))) <= c) {
WRITE64BE((char *)p + c - sizeof(n), kind);
__asan_poison((uintptr_t)p, n, kind);
if ((n = READ64BE(p + c - 8)) <= c) {
WRITE64BE(p + c - 8, kind);
__asan_poison((uintptr_t)p, c - 8, kind);
if (weaken(dlfree)) {
weaken(dlfree)(__asan_morgue_add(p));
}
@ -588,43 +617,47 @@ static void *__asan_malloc(size_t size) {
return __asan_memalign(16, size);
}
static void *__asan_calloc(size_t nelem, size_t elsize) {
static void *__asan_calloc(size_t n, size_t m) {
char *p;
size_t n;
if (__builtin_mul_overflow(nelem, elsize, &n)) n = -1;
if (__builtin_mul_overflow(n, m, &n)) n = -1;
if ((p = __asan_malloc(n))) __asan_memset(p, 0, n);
return p;
}
static void *__asan_realloc(void *p, size_t n) {
char *p2;
char *q, *f;
size_t c, m;
if (p) {
if (n) {
if ((c = weaken(dlmalloc_usable_size)(p)) < 8)
if ((c = weaken(dlmalloc_usable_size)(p)) >= 8) {
f = (char *)p + c - 8;
if ((m = READ64BE(f)) <= c) {
if (n <= m) { /* shrink */
__asan_poison((uintptr_t)p + n, m - n, kAsanHeapOverrun);
WRITE64BE(f, n);
q = p;
} else if (n <= c - 8) { /* small growth */
__asan_unpoison((uintptr_t)p + m, n - m);
WRITE64BE(f, n);
q = p;
} else if ((q = __asan_malloc(n))) { /* exponential growth */
__asan_memcpy(q, p, m);
__asan_deallocate(p, kAsanRelocated);
}
} else {
__asan_report_heap_fault(p, m);
}
} else {
__asan_report_heap_fault(p, 0);
if ((m = READ64BE((char *)p + c - sizeof(n))) > c)
__asan_report_heap_fault(p, m);
if (n <= m) { /* shrink */
__asan_poison((uintptr_t)p + n, m - n, kAsanHeapOverrun);
WRITE64BE((char *)p + c - sizeof(n), n);
p2 = p;
} else if (n <= c - 8) { /* small growth */
__asan_unpoison((uintptr_t)p + m, n - m);
WRITE64BE((char *)p + c - sizeof(n), n);
p2 = p;
} else if ((p2 = __asan_malloc(n))) { /* exponential growth */
__asan_memcpy(p2, p, m);
__asan_deallocate(p, kAsanRelocated);
}
} else {
__asan_free(p);
p2 = NULL;
q = NULL;
}
} else {
p2 = __asan_malloc(n);
q = __asan_malloc(n);
}
return p2;
return q;
}
static void *__asan_valloc(size_t n) {

View file

@ -1,5 +1,6 @@
#ifndef COSMOPOLITAN_LIBC_INTRIN_ASAN_H_
#define COSMOPOLITAN_LIBC_INTRIN_ASAN_H_
#include "libc/calls/struct/iovec.h"
#define kAsanScale 3
#define kAsanMagic 0x7fff8000
@ -17,10 +18,12 @@
#define kAsanUnscoped -12
#define kAsanUnmapped -13
#define SHADOW(x) ((char *)(((uintptr_t)(x) >> kAsanScale) + kAsanMagic))
#define SHADOW(x) ((signed char *)(((uintptr_t)(x) >> kAsanScale) + kAsanMagic))
void __asan_map_shadow(uintptr_t, size_t);
void __asan_poison(uintptr_t, size_t, int);
void __asan_unpoison(uintptr_t, size_t);
bool __asan_is_valid(const void *, size_t);
bool __asan_is_valid_iov(const struct iovec *, int);
#endif /* COSMOPOLITAN_LIBC_INTRIN_ASAN_H_ */

View file

@ -41,13 +41,11 @@ $(LIBC_INTRIN_A).pkg: \
$(LIBC_INTRIN_A_OBJS) \
$(foreach x,$(LIBC_INTRIN_A_DIRECTDEPS),$($(x)_A).pkg)
$(LIBC_INTRIN_A_OBJS): \
OVERRIDE_CFLAGS += \
$(NO_MAGIC) \
-O3
o/$(MODE)/libc/intrin/asan.o: \
o/$(MODE)/libc/intrin/asan.o \
o/$(MODE)/libc/intrin/ubsan.o: \
OVERRIDE_CFLAGS += \
-fno-sanitize=all \
-fno-stack-protector \
-mgeneral-regs-only \
-O2

View file

@ -28,7 +28,7 @@ void(pabsd)(uint32_t a[4], const int32_t b[4]) {
unsigned i;
uint32_t r[4];
for (i = 0; i < 4; ++i) {
r[i] = ABS(b[i]);
r[i] = b[i] >= 0 ? b[i] : -(uint32_t)b[i];
}
memcpy(a, r, 16);
}

View file

@ -27,9 +27,11 @@
* @param 𝑐 [r/o] supplies second input vector
* @mayalias
*/
void(paddd)(int32_t a[4], const int32_t b[4], const int32_t c[4]) {
void(paddd)(uint32_t a[4], const uint32_t b[4], const uint32_t c[4]) {
unsigned i;
int32_t r[4];
for (i = 0; i < 4; ++i) r[i] = b[i] + c[i];
uint32_t r[4];
for (i = 0; i < 4; ++i) {
r[i] = b[i] + c[i];
}
memcpy(a, r, 16);
}

View file

@ -4,7 +4,7 @@
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
void paddd(int32_t[4], const int32_t[4], const int32_t[4]);
void paddd(uint32_t[4], const uint32_t[4], const uint32_t[4]);
#define paddd(A, B, C) \
INTRIN_SSEVEX_X_X_X_(paddd, SSE2, "paddd", INTRIN_COMMUTATIVE, A, B, C)

View file

@ -27,9 +27,9 @@
* @param 𝑐 [r/o] supplies second input vector
* @mayalias
*/
void(paddq)(int64_t a[2], const int64_t b[2], const int64_t c[2]) {
void(paddq)(uint64_t a[2], const uint64_t b[2], const uint64_t c[2]) {
unsigned i;
int64_t r[2];
uint64_t r[2];
for (i = 0; i < 2; ++i) r[i] = b[i] + c[i];
memcpy(a, r, 16);
}

View file

@ -4,7 +4,7 @@
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
void paddq(int64_t[2], const int64_t[2], const int64_t[2]);
void paddq(uint64_t[2], const uint64_t[2], const uint64_t[2]);
#define paddq(A, B, C) \
INTRIN_SSEVEX_X_X_X_(paddq, SSE2, "paddq", INTRIN_COMMUTATIVE, A, B, C)

View file

@ -28,7 +28,7 @@
* @note goes fast w/ ssse3 (intel c. 2004, amd c. 2011)
* @mayalias
*/
void(phaddd)(int32_t a[4], const int32_t b[4], const int32_t c[4]) {
void(phaddd)(uint32_t a[4], const uint32_t b[4], const uint32_t c[4]) {
int32_t t[4];
t[0] = b[0] + b[1];
t[1] = b[2] + b[3];

View file

@ -4,7 +4,7 @@
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
void phaddd(int32_t[4], const int32_t[4], const int32_t[4]);
void phaddd(uint32_t[4], const uint32_t[4], const uint32_t[4]);
#define phaddd(A, B, C) \
INTRIN_SSEVEX_X_X_X_(phaddd, SSSE3, "phaddd", INTRIN_NONCOMMUTATIVE, A, B, C)

View file

@ -28,8 +28,8 @@
* @note goes fast w/ ssse3
* @mayalias
*/
void(phsubd)(int32_t a[4], const int32_t b[4], const int32_t c[4]) {
int32_t t[4];
void(phsubd)(uint32_t a[4], const uint32_t b[4], const uint32_t c[4]) {
uint32_t t[4];
t[0] = b[0] - b[1];
t[1] = b[2] - b[3];
t[2] = c[0] - c[1];

View file

@ -4,7 +4,7 @@
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
void phsubd(int32_t[4], const int32_t[4], const int32_t[4]);
void phsubd(uint32_t[4], const uint32_t[4], const uint32_t[4]);
#define phsubd(A, B, C) \
INTRIN_SSEVEX_X_X_X_(phsubd, SSSE3, "phsubd", INTRIN_NONCOMMUTATIVE, A, B, C)

View file

@ -29,9 +29,13 @@
*/
void(pmulhuw)(uint16_t a[8], const uint16_t b[8], const uint16_t c[8]) {
unsigned i;
uint32_t x;
uint16_t r[8];
for (i = 0; i < 8; ++i) {
r[i] = ((b[i] * c[i]) & 0xffff0000) >> 16;
x = b[i];
x *= c[i];
x >>= 16;
r[i] = x;
}
memcpy(a, r, 16);
}

View file

@ -20,7 +20,7 @@
#include "libc/str/str.h"
/**
* Multiplies 32-bit signed integers.
* Multiplies 32-bit integers.
*
* @param 𝑎 [w/o] receives result
* @param 𝑏 [r/o] supplies first input vector
@ -28,9 +28,9 @@
* @see pmuludq()
* @mayalias
*/
void(pmulld)(int32_t a[4], const int32_t b[4], const int32_t c[4]) {
void(pmulld)(uint32_t a[4], const uint32_t b[4], const uint32_t c[4]) {
unsigned i;
int32_t r[4];
uint32_t r[4];
for (i = 0; i < 4; ++i) {
r[i] = b[i] * c[i];
}

View file

@ -4,7 +4,7 @@
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
void pmulld(int32_t[4], const int32_t[4], const int32_t[4]);
void pmulld(uint32_t[4], const uint32_t[4], const uint32_t[4]);
#define pmulld(A, B, C) \
INTRIN_SSEVEX_X_X_X_(pmulld, SSE4_1, "pmulld", INTRIN_COMMUTATIVE, A, B, C)

View file

@ -29,7 +29,7 @@ void(psignd)(int32_t a[4], const int32_t b[4], const int32_t c[4]) {
if (!c[i]) {
a[i] = 0;
} else if (c[i] < 0) {
a[i] = -b[i];
a[i] = -(uint32_t)b[i];
} else {
a[i] = b[i];
}

View file

@ -26,8 +26,8 @@
* @mayalias
*/
void(pslld)(uint32_t a[4], const uint32_t b[4], unsigned char c) {
unsigned i;
if (c <= 31) {
unsigned i;
for (i = 0; i < 4; ++i) {
a[i] = b[i] << c;
}

View file

@ -20,7 +20,7 @@
#include "libc/str/str.h"
/**
* Shifts vector right by n bytes w/ zero-fill.
* Shifts vector left by n bytes w/ zero-fill.
*
* @param a is input vector
* @param b receives output
@ -28,7 +28,9 @@
*/
void(pslldq)(uint8_t b[16], const uint8_t a[16], unsigned long n) {
unsigned i;
uint8_t t[16];
if (n > 16) n = 16;
memmove(b + n, a, 16 - n);
memset(b, 0, n);
for (i = 0; i < n; ++i) t[i] = 0;
for (i = 0; i < 16 - n; ++i) t[n + i] = a[i];
memcpy(b, t, 16);
}

View file

@ -17,6 +17,7 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/intrin/psllw.h"
#include "libc/str/str.h"
/**
* Multiplies shorts by two power.
@ -25,13 +26,11 @@
*/
void(psllwv)(uint16_t a[8], const uint16_t b[8], const uint64_t c[2]) {
unsigned i;
if (c[0] > 15) {
for (i = 0; i < 8; ++i) {
a[i] = 0;
}
} else {
if (c[0] < 16) {
for (i = 0; i < 8; ++i) {
a[i] = b[i] << c[0];
}
} else {
memset(a, 0, 16);
}
}

View file

@ -26,14 +26,9 @@
* @mayalias
*/
void(psrad)(int32_t a[4], const int32_t b[4], unsigned char k) {
unsigned i, x, m;
unsigned i;
if (k > 31) k = 31;
for (i = 0; i < 4; ++i) {
m = 0;
x = b[i];
if (x & 0x80000000) m = ~(0xffffffffu >> k);
x >>= k;
x |= m;
a[i] = x;
a[i] = b[i] >> k;
}
}

View file

@ -25,15 +25,10 @@
* @mayalias
*/
void(psradv)(int32_t a[4], const int32_t b[4], const uint64_t c[2]) {
unsigned i;
unsigned char k;
unsigned i, x, m;
k = c[0] > 31 ? 31 : c[0];
for (i = 0; i < 4; ++i) {
m = 0;
x = b[i];
if (x & 0x80000000u) m = ~(0xffffffffu >> k);
x >>= k;
x |= m;
a[i] = x & 0xffffffffu;
a[i] = b[i] >> k;
}
}

View file

@ -26,14 +26,9 @@
* @mayalias
*/
void(psraw)(int16_t a[8], const int16_t b[8], unsigned char k) {
unsigned i, x, m;
unsigned i;
if (k > 15) k = 15;
for (i = 0; i < 8; ++i) {
m = 0;
x = b[i];
if (x & 0x8000) m = ~(0xffff >> k);
x >>= k;
x |= m;
a[i] = x;
a[i] = b[i] >> k;
}
}

View file

@ -25,15 +25,10 @@
* @mayalias
*/
void(psrawv)(int16_t a[8], const int16_t b[8], const uint64_t c[2]) {
unsigned i;
unsigned char k;
unsigned i, x, m;
k = c[0] > 15 ? 15 : c[0];
for (i = 0; i < 8; ++i) {
m = 0;
x = b[i];
if (x & 0x8000) m = ~(0xffffu >> k);
x >>= k;
x |= m;
a[i] = x & 0xffffu;
a[i] = b[i] >> k;
}
}

View file

@ -27,9 +27,9 @@
* @param 𝑐 [r/o] supplies second input vector
* @mayalias
*/
void(psubd)(int32_t a[4], const int32_t b[4], const int32_t c[4]) {
void(psubd)(uint32_t a[4], const uint32_t b[4], const uint32_t c[4]) {
unsigned i;
int32_t r[4];
uint32_t r[4];
for (i = 0; i < 4; ++i) {
r[i] = b[i] - c[i];
}

View file

@ -4,7 +4,7 @@
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
void psubd(int32_t[4], const int32_t[4], const int32_t[4]);
void psubd(uint32_t[4], const uint32_t[4], const uint32_t[4]);
#define psubd(A, B, C) \
INTRIN_SSEVEX_X_X_X_(psubd, SSE2, "psubd", INTRIN_NONCOMMUTATIVE, A, B, C)

View file

@ -27,9 +27,9 @@
* @param 𝑐 [r/o] supplies second input vector
* @mayalias
*/
void(psubq)(int64_t a[2], const int64_t b[2], const int64_t c[2]) {
void(psubq)(uint64_t a[2], const uint64_t b[2], const uint64_t c[2]) {
unsigned i;
int64_t r[2];
uint64_t r[2];
for (i = 0; i < 2; ++i) {
r[i] = b[i] - c[i];
}

View file

@ -4,7 +4,7 @@
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
void psubq(int64_t[2], const int64_t[2], const int64_t[2]);
void psubq(uint64_t[2], const uint64_t[2], const uint64_t[2]);
#define psubq(A, B, C) \
INTRIN_SSEVEX_X_X_X_(psubq, SSE2, "psubq", INTRIN_NONCOMMUTATIVE, A, B, C)

View file

@ -19,6 +19,16 @@
#include "libc/macros.internal.h"
.source __FILE__
.macro .acall fn:req
xor %eax,%eax
mov $1,%r10b
cmpxchg %r10b,__asan_noreentry(%rip)
jnz 2f
call \fn
decb __asan_noreentry(%rip)
2: nop
.endm
.rodata.cst4
__asan_option_detect_stack_use_after_return:
.long 0
@ -32,181 +42,362 @@ __asan_noreentry:
.previous
__asan_report_load1:
push $1
jmp OnReportLoad
push %rbp
mov %rsp,%rbp
.profilable
mov $1,%esi
.acall __asan_report_load
pop %rbp
ret
.endfn __asan_report_load1,globl
__asan_report_load2:
push $2
jmp OnReportLoad
push %rbp
mov %rsp,%rbp
.profilable
mov $2,%esi
.acall __asan_report_load
pop %rbp
ret
.endfn __asan_report_load2,globl
__asan_report_load4:
push $4
jmp OnReportLoad
push %rbp
mov %rsp,%rbp
.profilable
mov $4,%esi
.acall __asan_report_load
pop %rbp
ret
.endfn __asan_report_load4,globl
__asan_report_load8:
push $8
jmp OnReportLoad
push %rbp
mov %rsp,%rbp
.profilable
mov $8,%esi
.acall __asan_report_load
pop %rbp
ret
.endfn __asan_report_load8,globl
__asan_report_load16:
push $16
jmp OnReportLoad
push %rbp
mov %rsp,%rbp
.profilable
mov $16,%esi
.acall __asan_report_load
pop %rbp
ret
.endfn __asan_report_load16,globl
__asan_report_load32:
push $32
// 𝑠𝑙𝑖𝑑𝑒
push %rbp
mov %rsp,%rbp
.profilable
mov $32,%esi
.acall __asan_report_load
pop %rbp
ret
.endfn __asan_report_load32,globl
OnReportLoad:
pop %rsi
// 𝑠𝑙𝑖𝑑𝑒
.endfn OnReportLoad
__asan_report_load_n:
lea __asan_report_load(%rip),%r11
jmp __asan_report_noreentry
push %rbp
mov %rsp,%rbp
.profilable
.acall __asan_report_load
pop %rbp
ret
.endfn __asan_report_load_n,globl
__asan_report_store1:
push $1
jmp ReportStore
.endfn __asan_report_store1,globl
__asan_report_store2:
push $2
jmp ReportStore
.endfn __asan_report_store2,globl
__asan_report_store4:
push $4
jmp ReportStore
.endfn __asan_report_store4,globl
__asan_report_store8:
push $8
jmp ReportStore
.endfn __asan_report_store8,globl
__asan_report_store16:
push $16
jmp ReportStore
.endfn __asan_report_store16,globl
__asan_report_store32:
push $32
// 𝑠𝑙𝑖𝑑𝑒
.endfn __asan_report_store32,globl
ReportStore:
pop %rsi
// 𝑠𝑙𝑖𝑑𝑒
.endfn ReportStore
__asan_report_store_n:
lea __asan_report_store(%rip),%r11
// 𝑠𝑙𝑖𝑑𝑒
.endfn __asan_report_store_n,globl
__asan_report_noreentry:
push %rbp
mov %rsp,%rbp
xor %eax,%eax
mov $1,%r10b
cmpxchg %r10b,__asan_noreentry(%rip)
jnz 2f
call *%r11
decb __asan_noreentry(%rip)
2: pop %rbp
.profilable
mov $1,%esi
.acall __asan_report_store
pop %rbp
ret
.endfn __asan_report_noreentry
.endfn __asan_report_store1,globl
__asan_report_store2:
push %rbp
mov %rsp,%rbp
.profilable
mov $2,%esi
.acall __asan_report_store
pop %rbp
ret
.endfn __asan_report_store2,globl
__asan_report_store4:
push %rbp
mov %rsp,%rbp
.profilable
mov $4,%esi
.acall __asan_report_store
pop %rbp
ret
.endfn __asan_report_store4,globl
__asan_report_store8:
push %rbp
mov %rsp,%rbp
.profilable
mov $8,%esi
.acall __asan_report_store
pop %rbp
ret
.endfn __asan_report_store8,globl
__asan_report_store16:
push %rbp
mov %rsp,%rbp
.profilable
mov $16,%esi
.acall __asan_report_store
pop %rbp
ret
.endfn __asan_report_store16,globl
__asan_report_store32:
push %rbp
mov %rsp,%rbp
.profilable
mov $32,%esi
.acall __asan_report_store
pop %rbp
ret
.endfn __asan_report_store32,globl
__asan_report_store_n:
push %rbp
mov %rsp,%rbp
.profilable
.acall __asan_report_store
pop %rbp
ret
.endfn __asan_report_store_n,globl
__asan_stack_free_0:
push $0
jmp OnStackFree
push %rbp
mov %rsp,%rbp
.profilable
mov $0,%edx
call __asan_stack_free
pop %rbp
ret
.endfn __asan_stack_free_0,globl
__asan_stack_free_1:
push $1
jmp OnStackFree
push %rbp
mov %rsp,%rbp
.profilable
mov $1,%edx
call __asan_stack_free
pop %rbp
ret
.endfn __asan_stack_free_1,globl
__asan_stack_free_2:
push $2
jmp OnStackFree
push %rbp
mov %rsp,%rbp
.profilable
mov $2,%edx
call __asan_stack_free
pop %rbp
ret
.endfn __asan_stack_free_2,globl
__asan_stack_free_3:
push $3
jmp OnStackFree
push %rbp
mov %rsp,%rbp
.profilable
mov $3,%edx
call __asan_stack_free
pop %rbp
ret
.endfn __asan_stack_free_3,globl
__asan_stack_free_4:
push $4
jmp OnStackFree
push %rbp
mov %rsp,%rbp
.profilable
mov $4,%edx
call __asan_stack_free
pop %rbp
ret
.endfn __asan_stack_free_4,globl
__asan_stack_free_5:
push $5
jmp OnStackFree
push %rbp
mov %rsp,%rbp
.profilable
mov $5,%edx
call __asan_stack_free
pop %rbp
ret
.endfn __asan_stack_free_5,globl
__asan_stack_free_6:
push $6
jmp OnStackFree
push %rbp
mov %rsp,%rbp
.profilable
mov $6,%edx
call __asan_stack_free
pop %rbp
ret
.endfn __asan_stack_free_6,globl
__asan_stack_free_7:
push $7
jmp OnStackFree
push %rbp
mov %rsp,%rbp
.profilable
mov $7,%edx
call __asan_stack_free
pop %rbp
ret
.endfn __asan_stack_free_7,globl
__asan_stack_free_8:
push $8
jmp OnStackFree
push %rbp
mov %rsp,%rbp
.profilable
mov $8,%edx
call __asan_stack_free
pop %rbp
ret
.endfn __asan_stack_free_8,globl
__asan_stack_free_9:
push $9
jmp OnStackFree
push %rbp
mov %rsp,%rbp
.profilable
mov $9,%edx
call __asan_stack_free
pop %rbp
ret
.endfn __asan_stack_free_9,globl
__asan_stack_free_10:
push $10
// 𝑠𝑙𝑖𝑑𝑒
push %rbp
mov %rsp,%rbp
.profilable
mov $10,%edx
call __asan_stack_free
pop %rbp
ret
.endfn __asan_stack_free_10,globl
OnStackFree:
pop %rdx
jmp __asan_stack_free
.endfn OnStackFree
__asan_stack_malloc_0:
push $0
jmp OnStackMalloc
push %rbp
mov %rsp,%rbp
.profilable
mov $0,%esi
call __asan_stack_malloc
pop %rbp
ret
.endfn __asan_stack_malloc_0,globl
__asan_stack_malloc_1:
push $1
jmp OnStackMalloc
push %rbp
mov %rsp,%rbp
.profilable
mov $1,%esi
call __asan_stack_malloc
pop %rbp
ret
.endfn __asan_stack_malloc_1,globl
__asan_stack_malloc_2:
push $2
jmp OnStackMalloc
push %rbp
mov %rsp,%rbp
.profilable
mov $2,%esi
call __asan_stack_malloc
pop %rbp
ret
.endfn __asan_stack_malloc_2,globl
__asan_stack_malloc_3:
push $3
jmp OnStackMalloc
push %rbp
mov %rsp,%rbp
.profilable
mov $3,%esi
call __asan_stack_malloc
pop %rbp
ret
.endfn __asan_stack_malloc_3,globl
__asan_stack_malloc_4:
push $4
jmp OnStackMalloc
push %rbp
mov %rsp,%rbp
.profilable
mov $4,%esi
call __asan_stack_malloc
pop %rbp
ret
.endfn __asan_stack_malloc_4,globl
__asan_stack_malloc_5:
push $5
jmp OnStackMalloc
push %rbp
mov %rsp,%rbp
.profilable
mov $5,%esi
call __asan_stack_malloc
pop %rbp
ret
.endfn __asan_stack_malloc_5,globl
__asan_stack_malloc_6:
push $6
jmp OnStackMalloc
push %rbp
mov %rsp,%rbp
.profilable
mov $6,%esi
call __asan_stack_malloc
pop %rbp
ret
.endfn __asan_stack_malloc_6,globl
__asan_stack_malloc_7:
push $7
jmp OnStackMalloc
push %rbp
mov %rsp,%rbp
.profilable
mov $7,%esi
call __asan_stack_malloc
pop %rbp
ret
.endfn __asan_stack_malloc_7,globl
__asan_stack_malloc_8:
push $8
jmp OnStackMalloc
push %rbp
mov %rsp,%rbp
.profilable
mov $8,%esi
call __asan_stack_malloc
pop %rbp
ret
.endfn __asan_stack_malloc_8,globl
__asan_stack_malloc_9:
push $9
jmp OnStackMalloc
push %rbp
mov %rsp,%rbp
.profilable
mov $9,%esi
call __asan_stack_malloc
pop %rbp
ret
.endfn __asan_stack_malloc_9,globl
__asan_stack_malloc_10:
push $10
// 𝑠𝑙𝑖𝑑𝑒
push %rbp
mov %rsp,%rbp
.profilable
mov $10,%esi
call __asan_stack_malloc
pop %rbp
ret
.endfn __asan_stack_malloc_10,globl
OnStackMalloc:
pop %rsi
jmp __asan_stack_malloc
.endfn OnStackMalloc
__asan_version_mismatch_check_v8:
ret
@ -242,26 +433,31 @@ __asan_load1:
mov %rsp,%rbp
ud2
.endfn __asan_load1,globl
__asan_load2:
push %rbp
mov %rsp,%rbp
ud2
.endfn __asan_load2,globl
__asan_load4:
push %rbp
mov %rsp,%rbp
ud2
.endfn __asan_load4,globl
__asan_load8:
push %rbp
mov %rsp,%rbp
ud2
.endfn __asan_load8,globl
__asan_load16:
push %rbp
mov %rsp,%rbp
ud2
.endfn __asan_load16,globl
__asan_load32:
push %rbp
mov %rsp,%rbp
@ -273,26 +469,31 @@ __asan_store1:
mov %rsp,%rbp
ud2
.endfn __asan_store1,globl
__asan_store2:
push %rbp
mov %rsp,%rbp
ud2
.endfn __asan_store2,globl
__asan_store4:
push %rbp
mov %rsp,%rbp
ud2
.endfn __asan_store4,globl
__asan_store8:
push %rbp
mov %rsp,%rbp
ud2
.endfn __asan_store8,globl
__asan_store16:
push %rbp
mov %rsp,%rbp
ud2
.endfn __asan_store16,globl
__asan_store32:
push %rbp
mov %rsp,%rbp

593
libc/intrin/ubsan.c Normal file
View file

@ -0,0 +1,593 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/alg/reverse.internal.h"
#include "libc/bits/pushpop.h"
#include "libc/bits/weaken.h"
#include "libc/calls/calls.h"
#include "libc/fmt/fmt.h"
#include "libc/log/internal.h"
#include "libc/log/log.h"
#include "libc/nt/runtime.h"
#include "libc/runtime/internal.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/fileno.h"
#include "libc/sysv/consts/nr.h"
#define kUbsanKindInt 0
#define kUbsanKindFloat 1
#define kUbsanKindUnknown 0xffff
struct UbsanSourceLocation {
const char *file;
uint32_t line;
uint32_t column;
};
struct UbsanTypeDescriptor {
uint16_t kind; /* int,float,... */
uint16_t info; /* if int bit 0 if signed, remaining bits are log2(sizeof*8) */
char name[];
};
struct UbsanTypeMismatchInfo {
struct UbsanSourceLocation location;
struct UbsanTypeDescriptor *type;
uintptr_t alignment;
uint8_t type_check_kind;
};
struct UbsanTypeMismatchInfoClang {
struct UbsanSourceLocation location;
struct UbsanTypeDescriptor *type;
unsigned char log_alignment; /* https://reviews.llvm.org/D28244 */
uint8_t type_check_kind;
};
struct UbsanOutOfBoundsInfo {
struct UbsanSourceLocation location;
struct UbsanTypeDescriptor *array_type;
struct UbsanTypeDescriptor *index_type;
};
struct UbsanUnreachableData {
struct UbsanSourceLocation location;
};
struct UbsanVlaBoundData {
struct UbsanSourceLocation location;
struct UbsanTypeDescriptor *type;
};
struct UbsanNonnullArgData {
struct UbsanSourceLocation location;
struct UbsanSourceLocation attr_location;
};
struct UbsanCfiBadIcallData {
struct UbsanSourceLocation location;
struct UbsanTypeDescriptor *type;
};
struct UbsanNonnullReturnData {
struct UbsanSourceLocation location;
struct UbsanSourceLocation attr_location;
};
struct UbsanFunctionTypeMismatchData {
struct UbsanSourceLocation location;
struct UbsanTypeDescriptor *type;
};
struct UbsanInvalidValueData {
struct UbsanSourceLocation location;
struct UbsanTypeDescriptor *type;
};
struct UbsanOverflowData {
struct UbsanSourceLocation location;
struct UbsanTypeDescriptor *type;
};
struct UbsanFloatCastOverflowData {
#if __GNUC__ + 0 >= 6
struct UbsanSourceLocation location;
#endif
struct UbsanTypeDescriptor *from_type;
struct UbsanTypeDescriptor *to_type;
};
struct UbsanOutOfBoundsData {
struct UbsanSourceLocation location;
struct UbsanTypeDescriptor *arraytype;
struct UbsanTypeDescriptor *index_type;
};
struct UbsanShiftOutOfBoundsInfo {
struct UbsanSourceLocation location;
struct UbsanTypeDescriptor *lhs_type;
struct UbsanTypeDescriptor *rhs_type;
};
static const char kUbsanTypeCheckKinds[] = "\
load of\0\
store to\0\
reference binding to\0\
member access within\0\
member call on\0\
constructor call on\0\
downcast of\0\
downcast of\0\
upcast of\0\
cast to virtual base of\0\
\0";
static int __ubsan_bits(struct UbsanTypeDescriptor *t) {
return 1 << (t->info >> 1);
}
static bool __ubsan_signed(struct UbsanTypeDescriptor *t) {
return t->info & 1;
}
static bool __ubsan_negative(struct UbsanTypeDescriptor *t, uintptr_t x) {
return __ubsan_signed(t) && (intptr_t)x < 0;
}
static size_t __ubsan_strlen(const char *s) {
size_t n = 0;
while (*s++) ++n;
return n;
}
static char *__ubsan_stpcpy(char *d, const char *s) {
size_t i;
for (i = 0;; ++i) {
if (!(d[i] = s[i])) {
return d + i;
}
}
}
static char *__ubsan_poscpy(char *p, uintptr_t i) {
int j = 0;
do {
p[j++] = i % 10 + '0';
i /= 10;
} while (i > 0);
reverse(p, j);
return p + j;
}
static char *__ubsan_intcpy(char *p, intptr_t i) {
if (i >= 0) return __ubsan_poscpy(p, i);
*p++ = '-';
return __ubsan_poscpy(p, -i);
}
static char *__ubsan_hexcpy(char *p, uintptr_t x, int k) {
while (k) *p++ = "0123456789abcdef"[(x >> (k -= 4)) & 15];
return p;
}
static char *__ubsan_itpcpy(char *p, struct UbsanTypeDescriptor *t,
uintptr_t x) {
if (__ubsan_signed(t)) {
return __ubsan_intcpy(p, x);
} else {
return __ubsan_poscpy(p, x);
}
}
static const char *__ubsan_dubnul(const char *s, unsigned i) {
size_t n;
while (i--) {
if ((n = __ubsan_strlen(s))) {
s += n + 1;
} else {
return NULL;
}
}
return s;
}
static uintptr_t __ubsan_extend(struct UbsanTypeDescriptor *t, uintptr_t x) {
int w;
w = __ubsan_bits(t);
if (w < sizeof(x) * CHAR_BIT) {
x <<= sizeof(x) * CHAR_BIT - w;
if (__ubsan_signed(t)) {
x = (intptr_t)x >> w;
} else {
x >>= w;
}
}
return x;
}
static privileged noinline wontreturn void __ubsan_exit(int rc) {
if (!IsWindows()) {
asm volatile("syscall"
: /* no outputs */
: "a"(__NR_exit_group), "D"(rc)
: "memory");
unreachable;
} else {
ExitProcess(rc);
}
}
static privileged noinline ssize_t __ubsan_write(const void *data,
size_t size) {
ssize_t rc;
uint32_t wrote;
if (!IsWindows()) {
asm volatile("syscall"
: "=a"(rc)
: "0"(__NR_write), "D"(2), "S"(data), "d"(size)
: "rcx", "r11", "memory");
return rc;
} else {
if (WriteFile(GetStdHandle(kNtStdErrorHandle), data, size, &wrote, 0)) {
return wrote;
} else {
return -1;
}
}
}
static ssize_t __ubsan_write_string(const char *s) {
return __ubsan_write(s, __ubsan_strlen(s));
}
void __ubsan_abort(const struct UbsanSourceLocation *loc,
const char *description) {
char buf[1024], *p = buf;
p = __ubsan_stpcpy(p, "error: ");
p = __ubsan_stpcpy(p, loc->file), *p++ = ':';
p = __ubsan_intcpy(p, loc->line);
p = __ubsan_stpcpy(p, ": ");
p = __ubsan_stpcpy(p, description);
p = __ubsan_stpcpy(p, "\r\n");
__ubsan_write_string(buf);
if (weaken(__die)) weaken(__die)();
__ubsan_exit(134);
}
static const char *__ubsan_describe_shift(
struct UbsanShiftOutOfBoundsInfo *info, uintptr_t lhs, uintptr_t rhs) {
if (__ubsan_negative(info->rhs_type, rhs)) {
return "shift exponent is negative";
} else if (rhs >= __ubsan_bits(info->lhs_type)) {
return "shift exponent too large for type";
} else if (__ubsan_negative(info->lhs_type, lhs)) {
return "left shift of negative value";
} else if (__ubsan_signed(info->lhs_type)) {
return "signed left shift changed sign bit or overflowed";
} else {
return "wut shift out of bounds";
}
}
void __ubsan_handle_shift_out_of_bounds(struct UbsanShiftOutOfBoundsInfo *info,
uintptr_t lhs, uintptr_t rhs) {
char buf[512], *p = buf;
lhs = __ubsan_extend(info->lhs_type, lhs);
rhs = __ubsan_extend(info->rhs_type, rhs);
p = __ubsan_stpcpy(p, __ubsan_describe_shift(info, lhs, rhs)), *p++ = ' ';
p = __ubsan_itpcpy(p, info->lhs_type, lhs), *p++ = ' ';
p = __ubsan_stpcpy(p, info->lhs_type->name), *p++ = ' ';
p = __ubsan_itpcpy(p, info->rhs_type, rhs), *p++ = ' ';
p = __ubsan_stpcpy(p, info->rhs_type->name);
__ubsan_abort(&info->location, buf);
}
void __ubsan_handle_shift_out_of_bounds_abort(
struct UbsanShiftOutOfBoundsInfo *info, uintptr_t lhs, uintptr_t rhs) {
__ubsan_handle_shift_out_of_bounds(info, lhs, rhs);
}
void __ubsan_handle_out_of_bounds(struct UbsanOutOfBoundsInfo *info,
uintptr_t index) {
char buf[512], *p = buf;
p = __ubsan_stpcpy(p, info->index_type->name);
p = __ubsan_stpcpy(p, " index ");
p = __ubsan_itpcpy(p, info->index_type, index);
p = __ubsan_stpcpy(p, " into ");
p = __ubsan_stpcpy(p, info->array_type->name);
p = __ubsan_stpcpy(p, " out of bounds");
__ubsan_abort(&info->location, buf);
}
void __ubsan_handle_out_of_bounds_abort(struct UbsanOutOfBoundsInfo *info,
uintptr_t index) {
__ubsan_handle_out_of_bounds(info, index);
}
void __ubsan_handle_type_mismatch(struct UbsanTypeMismatchInfo *info,
uintptr_t pointer) {
const char *kind;
char buf[512], *p = buf;
if (!pointer) __ubsan_abort(&info->location, "null pointer access");
kind = __ubsan_dubnul(kUbsanTypeCheckKinds, info->type_check_kind);
if (info->alignment && (pointer & (info->alignment - 1))) {
p = __ubsan_stpcpy(p, "unaligned ");
p = __ubsan_stpcpy(p, kind), *p++ = ' ';
p = __ubsan_stpcpy(p, info->type->name), *p++ = ' ', *p++ = '@';
p = __ubsan_itpcpy(p, info->type, pointer);
p = __ubsan_stpcpy(p, " align ");
p = __ubsan_intcpy(p, info->alignment);
} else {
p = __ubsan_stpcpy(p, "insufficient size\r\n\t");
p = __ubsan_stpcpy(p, kind);
p = __ubsan_stpcpy(p, " address 0x");
p = __ubsan_hexcpy(p, pointer, sizeof(pointer) * CHAR_BIT);
p = __ubsan_stpcpy(p, " with insufficient space for object of type ");
p = __ubsan_stpcpy(p, info->type->name);
}
__ubsan_abort(&info->location, buf);
}
void __ubsan_handle_type_mismatch_abort(struct UbsanTypeMismatchInfo *info,
uintptr_t pointer) {
__ubsan_handle_type_mismatch(info, pointer);
}
void __ubsan_handle_type_mismatch_v1(
struct UbsanTypeMismatchInfoClang *type_mismatch, uintptr_t pointer) {
struct UbsanTypeMismatchInfo mm;
mm.location = type_mismatch->location;
mm.type = type_mismatch->type;
mm.alignment = 1u << type_mismatch->log_alignment;
mm.type_check_kind = type_mismatch->type_check_kind;
__ubsan_handle_type_mismatch(&mm, pointer);
}
void __ubsan_handle_type_mismatch_v1_abort(
struct UbsanTypeMismatchInfoClang *type_mismatch, uintptr_t pointer) {
__ubsan_handle_type_mismatch_v1(type_mismatch, pointer);
}
void __ubsan_handle_float_cast_overflow(void *data_raw, void *from_raw) {
struct UbsanFloatCastOverflowData *data =
(struct UbsanFloatCastOverflowData *)data_raw;
#if __GNUC__ + 0 >= 6
__ubsan_abort(&data->location, "float cast overflow");
#else
const struct UbsanSourceLocation kUnknownLocation = {
"<unknown file>",
pushpop(0),
pushpop(0),
};
__ubsan_abort(((void)data, &kUnknownLocation), "float cast overflow");
#endif
}
void __ubsan_handle_float_cast_overflow_abort(void *data_raw, void *from_raw) {
__ubsan_handle_float_cast_overflow(data_raw, from_raw);
}
void __ubsan_handle_add_overflow(const struct UbsanSourceLocation *loc) {
__ubsan_abort(loc, "add overflow");
}
void __ubsan_handle_add_overflow_abort(const struct UbsanSourceLocation *loc) {
__ubsan_handle_add_overflow(loc);
}
void __ubsan_handle_alignment_assumption(
const struct UbsanSourceLocation *loc) {
__ubsan_abort(loc, "alignment assumption");
}
void __ubsan_handle_alignment_assumption_abort(
const struct UbsanSourceLocation *loc) {
__ubsan_handle_alignment_assumption(loc);
}
void __ubsan_handle_builtin_unreachable(const struct UbsanSourceLocation *loc) {
__ubsan_abort(loc, "builtin unreachable");
}
void __ubsan_handle_builtin_unreachable_abort(
const struct UbsanSourceLocation *loc) {
__ubsan_handle_builtin_unreachable(loc);
}
void __ubsan_handle_cfi_bad_type(const struct UbsanSourceLocation *loc) {
__ubsan_abort(loc, "cfi bad type");
}
void __ubsan_handle_cfi_bad_type_abort(const struct UbsanSourceLocation *loc) {
__ubsan_handle_cfi_bad_type(loc);
}
void __ubsan_handle_cfi_check_fail(const struct UbsanSourceLocation *loc) {
__ubsan_abort(loc, "cfi check fail");
}
void __ubsan_handle_cfi_check_fail_abort(
const struct UbsanSourceLocation *loc) {
__ubsan_handle_cfi_check_fail(loc);
}
void __ubsan_handle_divrem_overflow(const struct UbsanSourceLocation *loc) {
__ubsan_abort(loc, "divrem overflow");
}
void __ubsan_handle_divrem_overflow_abort(
const struct UbsanSourceLocation *loc) {
__ubsan_handle_divrem_overflow(loc);
}
void __ubsan_handle_dynamic_type_cache_miss(
const struct UbsanSourceLocation *loc) {
__ubsan_abort(loc, "dynamic type cache miss");
}
void __ubsan_handle_dynamic_type_cache_miss_abort(
const struct UbsanSourceLocation *loc) {
__ubsan_handle_dynamic_type_cache_miss(loc);
}
void __ubsan_handle_function_type_mismatch(
const struct UbsanSourceLocation *loc) {
__ubsan_abort(loc, "function type mismatch");
}
void __ubsan_handle_function_type_mismatch_abort(
const struct UbsanSourceLocation *loc) {
__ubsan_handle_function_type_mismatch(loc);
}
void __ubsan_handle_implicit_conversion(const struct UbsanSourceLocation *loc) {
__ubsan_abort(loc, "implicit conversion");
}
void __ubsan_handle_implicit_conversion_abort(
const struct UbsanSourceLocation *loc) {
__ubsan_handle_implicit_conversion(loc);
}
void __ubsan_handle_invalid_builtin(const struct UbsanSourceLocation *loc) {
__ubsan_abort(loc, "invalid builtin");
}
void __ubsan_handle_invalid_builtin_abort(
const struct UbsanSourceLocation *loc) {
__ubsan_handle_invalid_builtin(loc);
}
void __ubsan_handle_load_invalid_value(const struct UbsanSourceLocation *loc) {
__ubsan_abort(loc, "load invalid value (uninitialized? bool∌[01]?)");
}
void __ubsan_handle_load_invalid_value_abort(
const struct UbsanSourceLocation *loc) {
__ubsan_handle_load_invalid_value(loc);
}
void __ubsan_handle_missing_return(const struct UbsanSourceLocation *loc) {
__ubsan_abort(loc, "missing return");
}
void __ubsan_handle_missing_return_abort(
const struct UbsanSourceLocation *loc) {
__ubsan_handle_missing_return(loc);
}
void __ubsan_handle_mul_overflow(const struct UbsanSourceLocation *loc) {
__ubsan_abort(loc, "multiply overflow");
}
void __ubsan_handle_mul_overflow_abort(const struct UbsanSourceLocation *loc) {
__ubsan_handle_mul_overflow(loc);
}
void __ubsan_handle_negate_overflow(const struct UbsanSourceLocation *loc) {
__ubsan_abort(loc, "negate overflow");
}
void __ubsan_handle_negate_overflow_abort(
const struct UbsanSourceLocation *loc) {
__ubsan_handle_negate_overflow(loc);
}
void __ubsan_handle_nonnull_arg(const struct UbsanSourceLocation *loc) {
__ubsan_abort(loc, "nonnull argument");
}
void __ubsan_handle_nonnull_arg_abort(const struct UbsanSourceLocation *loc) {
__ubsan_handle_nonnull_arg(loc);
}
void __ubsan_handle_nonnull_return_v1(const struct UbsanSourceLocation *loc) {
__ubsan_abort(loc, "non-null return (v1)");
}
void __ubsan_handle_nonnull_return_v1_abort(
const struct UbsanSourceLocation *loc) {
__ubsan_handle_nonnull_return_v1(loc);
}
void __ubsan_handle_nullability_arg(const struct UbsanSourceLocation *loc) {
__ubsan_abort(loc, "nullability arg");
}
void __ubsan_handle_nullability_arg_abort(
const struct UbsanSourceLocation *loc) {
__ubsan_handle_nullability_arg(loc);
}
void __ubsan_handle_nullability_return_v1(
const struct UbsanSourceLocation *loc) {
__ubsan_abort(loc, "nullability return (v1)");
}
void __ubsan_handle_nullability_return_v1_abort(
const struct UbsanSourceLocation *loc) {
__ubsan_handle_nullability_return_v1(loc);
}
void __ubsan_handle_pointer_overflow(const struct UbsanSourceLocation *loc) {
__ubsan_abort(loc, "pointer overflow");
}
void __ubsan_handle_pointer_overflow_abort(
const struct UbsanSourceLocation *loc) {
__ubsan_handle_pointer_overflow(loc);
}
void __ubsan_handle_sub_overflow(const struct UbsanSourceLocation *loc) {
__ubsan_abort(loc, "subtract overflow");
}
void __ubsan_handle_sub_overflow_abort(const struct UbsanSourceLocation *loc) {
__ubsan_handle_sub_overflow(loc);
}
void __ubsan_handle_vla_bound_not_positive(
const struct UbsanSourceLocation *loc) {
__ubsan_abort(loc, "vla bound not positive");
}
void __ubsan_handle_vla_bound_not_positive_abort(
const struct UbsanSourceLocation *loc) {
__ubsan_handle_vla_bound_not_positive(loc);
}
void __ubsan_handle_nonnull_return(const struct UbsanSourceLocation *loc) {
__ubsan_abort(loc, "nonnull return");
}
void __ubsan_handle_nonnull_return_abort(
const struct UbsanSourceLocation *loc) {
__ubsan_handle_nonnull_return(loc);
}
void __ubsan_default_options(void) {
}
void __ubsan_on_report(void) {
}
void *__ubsan_get_current_report_data(void) {
return 0;
}

16
libc/isystem/iso646.h Normal file
View file

@ -0,0 +1,16 @@
#ifndef COSMOPOLITAN_LIBC_ISYSTEM_ISO646_H_
#define COSMOPOLITAN_LIBC_ISYSTEM_ISO646_H_
#define and &&
#define and_eq &=
#define bitand &
#define bitor |
#define compl ~
#define not !
#define not_eq !=
#define or ||
#define or_eq |=
#define xor ^
#define xor_eq ^=
#endif

View file

@ -29,10 +29,8 @@
relegated wontreturn void __die(void) {
static bool once;
if (cmpxchg(&once, false, true)) {
if (!IsTiny()) {
if (IsDebuggerPresent(false)) DebugBreak();
ShowBacktrace(2, NULL);
}
if (IsDebuggerPresent(false)) DebugBreak();
ShowBacktrace(2, NULL);
}
exit(77);
}

View file

@ -1,5 +1,6 @@
#ifndef COSMOPOLITAN_LIBC_LOG_LOG_H_
#define COSMOPOLITAN_LIBC_LOG_LOG_H_
#include "libc/bits/likely.h"
#include "libc/calls/struct/sigset.h"
#include "libc/calls/struct/winsize.h"
#include "libc/stdio/stdio.h"

View file

@ -133,7 +133,7 @@ relegated static void ShowGeneralRegisters(int fd, ucontext_t *ctx) {
} else {
memset(&st, 0, sizeof(st));
}
dprintf(fd, " %s(%zu) %Lf", "ST", k, st);
dprintf(fd, " %s(%zu) %Lg", "ST", k, st);
++k;
write(fd, "\r\n", 2);
}

View file

@ -17,12 +17,8 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/errno.h"
#include "libc/fmt/fmt.h"
#include "libc/log/internal.h"
#include "libc/log/log.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
/**
* Writes error messages to standard error.

View file

@ -23,7 +23,6 @@
#include "libc/dce.h"
#include "libc/log/internal.h"
#include "libc/log/log.h"
#include "libc/log/ubsan.internal.h"
#include "libc/macros.internal.h"
#include "libc/nt/signals.h"
#include "libc/str/str.h"
@ -31,7 +30,6 @@
#include "libc/sysv/consts/sig.h"
STATIC_YOINK("__die");
STATIC_YOINK("__ubsan_abort");
extern const unsigned char __oncrash_thunks[7][11];

View file

@ -1,265 +0,0 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
.text.unlikely
.source __FILE__
__ubsan_default_options:
ret
.endfn __ubsan_default_options
__ubsan_on_report:
ret
.endfn __ubsan_on_report,globl
__ubsan_get_current_report_data:
xor %eax,%eax
ret
.endfn __ubsan_get_current_report_data,globl
__ubsan_handle_type_mismatch_abort:
jmp __ubsan_handle_type_mismatch
.endfn __ubsan_handle_type_mismatch_abort,globl
__ubsan_handle_float_cast_overflow_abort:
jmp __ubsan_handle_float_cast_overflow
.endfn __ubsan_handle_float_cast_overflow_abort,globl
__ubsan_handle_type_mismatch_v1:
__ubsan_handle_type_mismatch_v1_abort:
jmp ___ubsan_handle_type_mismatch_v1
.endfn __ubsan_handle_type_mismatch_v1,globl
.endfn __ubsan_handle_type_mismatch_v1_abort,globl
__ubsan_handle_add_overflow_abort:
nop
// fallthrough
.endfn __ubsan_handle_add_overflow_abort,globl
__ubsan_handle_add_overflow:
loadstr "add_overflow",si
jmp __ubsan_hop
.endfn __ubsan_handle_add_overflow,globl
__ubsan_handle_alignment_assumption_abort:
nop
// fallthrough
.endfn __ubsan_handle_alignment_assumption_abort,globl
__ubsan_handle_alignment_assumption:
loadstr "alignment_assumption",si
jmp __ubsan_hop
.endfn __ubsan_handle_alignment_assumption,globl
__ubsan_handle_builtin_unreachable_abort:
nop
// fallthrough
.endfn __ubsan_handle_builtin_unreachable_abort,globl
__ubsan_handle_builtin_unreachable:
loadstr "builtin_unreachable",si
jmp __ubsan_hop
.endfn __ubsan_handle_builtin_unreachable,globl
__ubsan_handle_cfi_bad_type_abort:
nop
// fallthrough
.endfn __ubsan_handle_cfi_bad_type_abort,globl
__ubsan_handle_cfi_bad_type:
loadstr "cfi_bad_type",si
jmp __ubsan_hop
.endfn __ubsan_handle_cfi_bad_type,globl
__ubsan_handle_cfi_check_fail_abort:
nop
// fallthrough
.endfn __ubsan_handle_cfi_check_fail_abort,globl
__ubsan_handle_cfi_check_fail:
loadstr "cfi_check_fail",si
jmp __ubsan_hop
.endfn __ubsan_handle_cfi_check_fail,globl
__ubsan_handle_divrem_overflow_abort:
nop
// fallthrough
.endfn __ubsan_handle_divrem_overflow_abort,globl
__ubsan_handle_divrem_overflow:
loadstr "divrem_overflow",si
jmp __ubsan_hop
.endfn __ubsan_handle_divrem_overflow,globl
__ubsan_handle_dynamic_type_cache_miss_abort:
nop
// fallthrough
.endfn __ubsan_handle_dynamic_type_cache_miss_abort,globl
__ubsan_handle_dynamic_type_cache_miss:
loadstr "dynamic_type_cache_miss",si
jmp __ubsan_hop
.endfn __ubsan_handle_dynamic_type_cache_miss,globl
__ubsan_handle_function_type_mismatch_abort:
nop
// fallthrough
.endfn __ubsan_handle_function_type_mismatch_abort,globl
__ubsan_handle_function_type_mismatch:
loadstr "function_type_mismatch",si
jmp __ubsan_hop
.endfn __ubsan_handle_function_type_mismatch,globl
__ubsan_handle_implicit_conversion_abort:
nop
// fallthrough
.endfn __ubsan_handle_implicit_conversion_abort,globl
__ubsan_handle_implicit_conversion:
loadstr "implicit_conversion",si
jmp __ubsan_hop
.endfn __ubsan_handle_implicit_conversion,globl
__ubsan_handle_invalid_builtin_abort:
nop
// fallthrough
.endfn __ubsan_handle_invalid_builtin_abort,globl
__ubsan_handle_invalid_builtin:
loadstr "invalid_builtin",si
jmp __ubsan_hop
.endfn __ubsan_handle_invalid_builtin,globl
__ubsan_handle_load_invalid_value_abort:
nop
// fallthrough
.endfn __ubsan_handle_load_invalid_value_abort,globl
__ubsan_handle_load_invalid_value:
loadstr "load_invalid_value (try checking for uninitialized variables)",si
jmp __ubsan_hop
.endfn __ubsan_handle_load_invalid_value,globl
__ubsan_handle_missing_return_abort:
nop
// fallthrough
.endfn __ubsan_handle_missing_return_abort,globl
__ubsan_handle_missing_return:
loadstr "missing_return",si
jmp __ubsan_hop
.endfn __ubsan_handle_missing_return,globl
__ubsan_handle_mul_overflow_abort:
nop
// fallthrough
.endfn __ubsan_handle_mul_overflow_abort,globl
__ubsan_handle_mul_overflow:
loadstr "mul_overflow",si
jmp __ubsan_hop
.endfn __ubsan_handle_mul_overflow,globl
__ubsan_handle_negate_overflow_abort:
nop
// fallthrough
.endfn __ubsan_handle_negate_overflow_abort,globl
__ubsan_handle_negate_overflow:
loadstr "negate_overflow",si
jmp __ubsan_hop
.endfn __ubsan_handle_negate_overflow,globl
__ubsan_handle_nonnull_arg_abort:
nop
// fallthrough
.endfn __ubsan_handle_nonnull_arg_abort,globl
__ubsan_handle_nonnull_arg:
loadstr "nonnull_arg",si
jmp __ubsan_hop
.endfn __ubsan_handle_nonnull_arg,globl
__ubsan_handle_nonnull_return_v1_abort:
nop
// fallthrough
.endfn __ubsan_handle_nonnull_return_v1_abort,globl
__ubsan_handle_nonnull_return_v1:
loadstr "nonnull_return_v1",si
jmp __ubsan_hop
.endfn __ubsan_handle_nonnull_return_v1,globl
__ubsan_hop:
jmp __ubsan_abort
.endfn __ubsan_hop
__ubsan_handle_nullability_arg_abort:
nop
// fallthrough
.endfn __ubsan_handle_nullability_arg_abort,globl
__ubsan_handle_nullability_arg:
loadstr "nullability_arg",si
jmp __ubsan_hop
.endfn __ubsan_handle_nullability_arg,globl
__ubsan_handle_nullability_return_v1_abort:
nop
// fallthrough
.endfn __ubsan_handle_nullability_return_v1_abort,globl
__ubsan_handle_nullability_return_v1:
loadstr "nullability_return_v1",si
jmp __ubsan_hop
.endfn __ubsan_handle_nullability_return_v1,globl
__ubsan_handle_pointer_overflow_abort:
nop
// fallthrough
.endfn __ubsan_handle_pointer_overflow_abort,globl
__ubsan_handle_pointer_overflow:
loadstr "pointer_overflow",si
jmp __ubsan_hop
.endfn __ubsan_handle_pointer_overflow,globl
__ubsan_handle_shift_out_of_bounds_abort:
nop
// fallthrough
.endfn __ubsan_handle_shift_out_of_bounds_abort,globl
__ubsan_handle_shift_out_of_bounds:
loadstr "shift_out_of_bounds",si
jmp __ubsan_hop
.endfn __ubsan_handle_shift_out_of_bounds,globl
__ubsan_handle_sub_overflow_abort:
nop
// fallthrough
.endfn __ubsan_handle_sub_overflow_abort,globl
__ubsan_handle_sub_overflow:
loadstr "sub_overflow",si
jmp __ubsan_hop
.endfn __ubsan_handle_sub_overflow,globl
__ubsan_handle_vla_bound_not_positive_abort:
nop
// fallthrough
.endfn __ubsan_handle_vla_bound_not_positive_abort,globl
__ubsan_handle_vla_bound_not_positive:
loadstr "vla_bound_not_positive",si
jmp __ubsan_hop
.endfn __ubsan_handle_vla_bound_not_positive,globl
__ubsan_handle_nonnull_return_abort:
nop
// fallthrough
.endfn __ubsan_handle_nonnull_return_abort,globl
__ubsan_handle_nonnull_return:
loadstr "nonnull_return",si
jmp __ubsan_hop
.endfn __ubsan_handle_nonnull_return,globl
__ubsan_handle_out_of_bounds_abort:
jmp __ubsan_handle_out_of_bounds
.endfn __ubsan_handle_out_of_bounds_abort,globl
.previous

View file

@ -1,120 +0,0 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/bits/pushpop.h"
#include "libc/calls/calls.h"
#include "libc/fmt/fmt.h"
#include "libc/log/internal.h"
#include "libc/log/log.h"
#include "libc/log/ubsan.internal.h"
#include "libc/runtime/internal.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/fileno.h"
static char __ubsan_buf[256];
static const char kUbsanTypeCheckKinds[] = "\
load of\0\
store to\0\
reference binding to\0\
member access within\0\
member call on\0\
constructor call on\0\
downcast of\0\
downcast of\0\
upcast of\0\
cast to virtual base of\0\
\0";
void __ubsan_abort(const struct UbsanSourceLocation *loc,
const char *description) {
static bool once;
if (!once) {
once = true;
} else {
abort();
}
if (IsDebuggerPresent(false)) DebugBreak();
__start_fatal(loc->file, loc->line);
fprintf(stderr, "%s\r\n", description);
__die();
unreachable;
}
void __ubsan_handle_out_of_bounds(struct UbsanOutOfBoundsInfo *info,
uintptr_t index) {
snprintf(__ubsan_buf, sizeof(__ubsan_buf),
"%s index %,lu into %s out of bounds", info->index_type->name, index,
info->array_type->name);
__ubsan_abort(&info->location, __ubsan_buf);
unreachable;
}
void __ubsan_handle_type_mismatch(struct UbsanTypeMismatchInfo *type_mismatch,
uintptr_t pointer) {
struct UbsanSourceLocation *loc = &type_mismatch->location;
const char *description;
const char *kind = IndexDoubleNulString(kUbsanTypeCheckKinds,
type_mismatch->type_check_kind);
if (pointer == 0) {
description = "null pointer access";
} else if (type_mismatch->alignment != 0 &&
(pointer & (type_mismatch->alignment - 1))) {
description = __ubsan_buf;
snprintf(__ubsan_buf, sizeof(__ubsan_buf), "%s %s %s @%p %s %d",
"unaligned", kind, type_mismatch->type->name, pointer, "align",
type_mismatch->alignment);
} else {
description = __ubsan_buf;
snprintf(__ubsan_buf, sizeof(__ubsan_buf), "%s\r\n\t%s %s %p %s %s",
"insufficient size", kind, "address", pointer,
"with insufficient space for object of type",
type_mismatch->type->name);
}
__ubsan_abort(loc, description);
unreachable;
}
void ___ubsan_handle_type_mismatch_v1(
struct UbsanTypeMismatchInfoClang *type_mismatch, uintptr_t pointer) {
struct UbsanTypeMismatchInfo mm;
mm.location = type_mismatch->location;
mm.type = type_mismatch->type;
mm.alignment = 1u << type_mismatch->log_alignment;
mm.type_check_kind = type_mismatch->type_check_kind;
__ubsan_handle_type_mismatch(&mm, pointer);
unreachable;
}
void __ubsan_handle_float_cast_overflow(void *data_raw, void *from_raw) {
struct UbsanFloatCastOverflowData *data =
(struct UbsanFloatCastOverflowData *)data_raw;
#if __GNUC__ + 0 >= 6
__ubsan_abort(&data->location, "float cast overflow");
#else
const struct UbsanSourceLocation kUnknownLocation = {
"<unknown file>",
pushpop(0),
pushpop(0),
};
__ubsan_abort(((void)data, &kUnknownLocation), "float cast overflow");
#endif
unreachable;
}

Some files were not shown because too many files have changed in this diff Show more