mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-08-05 17:30:27 +00:00
Merge branch 'master' of https://github.com/jart/cosmopolitan into FEATURE/ioctl_SIOCGIFCONF_IPHLPAPI
This commit is contained in:
commit
662b889f81
589 changed files with 327000 additions and 5345 deletions
2
Makefile
2
Makefile
|
@ -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
|
||||
|
|
33
README.md
33
README.md
|
@ -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
|
||||
|
|
27
ape/ape.S
27
ape/ape.S
|
@ -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.
|
@ -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─────────────┘
|
||||
#
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
* Returns parent process id.
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int32_t getppid(void) {
|
||||
int getppid(void) {
|
||||
if (!IsWindows()) {
|
||||
if (!IsNetbsd()) {
|
||||
return sys_getppid();
|
||||
|
|
|
@ -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
164
libc/calls/metaflock.c
Normal 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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
|
@ -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 \
|
||||
|
|
|
@ -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_
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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) */
|
||||
|
|
|
@ -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) */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
107
libc/dns/getnameinfo.c
Normal 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;
|
||||
}
|
|
@ -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)))) {
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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) */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
132
libc/dns/resolvednsreverse.c
Normal file
132
libc/dns/resolvednsreverse.c
Normal 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;
|
||||
}
|
45
libc/dns/resolvehostsreverse.c
Normal file
45
libc/dns/resolvehostsreverse.c
Normal 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;
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
9
libc/dos.h
Normal 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_ */
|
|
@ -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('%');
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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_ */
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
593
libc/intrin/ubsan.c
Normal 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
16
libc/isystem/iso646.h
Normal 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
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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];
|
||||
|
||||
|
|
|
@ -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
|
120
libc/log/ubsan.c
120
libc/log/ubsan.c
|
@ -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
Loading…
Add table
Add a link
Reference in a new issue