finish intellisense support and sync with upstream

This commit is contained in:
Alexander Nicholi 2021-02-03 13:50:08 -05:00
commit ec9bfd8c56
No known key found for this signature in database
GPG key ID: B75B2EB05540F74C
221 changed files with 2360 additions and 1439 deletions

4
.vscode/vscode.h vendored
View file

@ -121,6 +121,7 @@ typedef struct { int ax, dx; } axdx_t;
#define _Vector_size(x) __attribute__(( vector_size( x ) ))
#define IMAGE_BASE_VIRTUAL 0x400000
#define __SIGACTION(...) (0)
#define VEIL(x, y) (y)
#define STATIC_YOINK(x)
@ -133,9 +134,12 @@ typedef struct { int ax, dx; } axdx_t;
#define reverse(x, y) 0
#define atomic_load(...) 0
#define atomic_store(...) 0
#define autotype(x) int
#define _Generic_(...) (void*)(0)
#define _Generic(...) _Generic_
#define _Alignas(...)
#define _Section(...)
#define offsetof(x, y) 0
#define cmpxchg(...) 0

View file

@ -82,17 +82,19 @@ o: o/$(MODE)/ape \
PKGS =
-include ~/.cosmo.mk #──No.1
-include ~/.cosmo.mk
include build/functions.mk #─┐
include build/definitions.mk # ├──meta
include build/config.mk # │
include build/rules.mk # │
include build/definitions.mk # ├──META
include build/config.mk # │ You can build
include build/rules.mk # │ You can topologically order
include build/online.mk # │
include libc/stubs/stubs.mk #─┘
include libc/nexgen32e/nexgen32e.mk #─┐
include libc/intrin/intrin.mk # │
include libc/linux/linux.mk # │
include libc/tinymath/tinymath.mk # ├──metal
include libc/sysv/sysv.mk # ├──SYSTEM SUPPORT
include libc/nt/nt.mk # │ You can do math
include libc/intrin/intrin.mk # │ You can use the stack
include libc/linux/linux.mk # │ You can manipulate arrays
include libc/tinymath/tinymath.mk # │ You can issue raw system calls
include third_party/compiler_rt/compiler_rt.mk # │
include libc/bits/bits.mk # │
include libc/str/str.mk # │
@ -100,23 +102,20 @@ include third_party/xed/xed.mk # │
include third_party/zlib/zlib.mk # │
include libc/elf/elf.mk # │
include ape/lib/apelib.mk # │
include ape/ape.mk #─┘
include libc/sysv/sysv.mk #─┐
include libc/nt/nt.mk # ├──system
include libc/fmt/fmt.mk # │
include libc/rand/rand.mk #─┘
include ape/ape.mk # │
include libc/fmt/fmt.mk #─┘
include libc/calls/calls.mk #─┐
include libc/runtime/runtime.mk # ├──systems
include libc/crt/crt.mk # │
include libc/runtime/runtime.mk # ├──SYSTEMS RUNTIME
include libc/crt/crt.mk # │ You can issue system calls
include libc/rand/rand.mk # │
include libc/unicode/unicode.mk # │
include third_party/dlmalloc/dlmalloc.mk #
include libc/mem/mem.mk #
include libc/ohmyplus/ohmyplus.mk #
include libc/zipos/zipos.mk # │
include third_party/gdtoa/gdtoa.mk # │
include third_party/dlmalloc/dlmalloc.mk #─┘
include libc/mem/mem.mk #─┐
include libc/ohmyplus/ohmyplus.mk # ├──DYNAMIC RUNTIME
include libc/zipos/zipos.mk # │ You can now use stdio
include third_party/gdtoa/gdtoa.mk # │ You can finally call malloc()
include libc/time/time.mk # │
include libc/alg/alg.mk # │
include libc/calls/hefty/hefty.mk # │
include libc/stdio/stdio.mk # │
include third_party/f2c/f2c.mk # │
include third_party/blas/blas.mk # │
@ -132,8 +131,8 @@ include third_party/musl/musl.mk # │
include third_party/getopt/getopt.mk # │
include libc/libc.mk #─┘
include libc/sock/sock.mk #─┐
include dsp/tty/tty.mk # ├──online
include libc/dns/dns.mk # │
include dsp/tty/tty.mk # ├──ONLINE RUNTIME
include libc/dns/dns.mk # │ You can communicate with the network
include libc/crypto/crypto.mk # │
include net/http/http.mk #─┘
include third_party/lemon/lemon.mk
@ -199,6 +198,7 @@ include test/test.mk
OBJS = $(foreach x,$(PKGS),$($(x)_OBJS))
SRCS = $(foreach x,$(PKGS),$($(x)_SRCS))
HDRS = $(foreach x,$(PKGS),$($(x)_HDRS))
INCS = $(foreach x,$(PKGS),$($(x)_INCS))
BINS = $(foreach x,$(PKGS),$($(x)_BINS))
TESTS = $(foreach x,$(PKGS),$($(x)_TESTS))
CHECKS = $(foreach x,$(PKGS),$($(x)_CHECKS))
@ -215,10 +215,10 @@ o/$(MODE)/.x:
o/$(MODE)/srcs.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(SRCS),$(dir $(x))))
$(file >$@) $(foreach x,$(SRCS),$(file >>$@,$(x)))
o/$(MODE)/hdrs.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(HDRS),$(dir $(x))))
$(file >$@) $(foreach x,$(HDRS),$(file >>$@,$(x)))
o/$(MODE)/hdrs.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(HDRS) $(INCS),$(dir $(x))))
$(file >$@) $(foreach x,$(HDRS) $(INCS),$(file >>$@,$(x)))
o/$(MODE)/depend: o/$(MODE)/.x o/$(MODE)/srcs.txt o/$(MODE)/hdrs.txt $(SRCS) $(HDRS)
o/$(MODE)/depend: o/$(MODE)/.x o/$(MODE)/srcs.txt o/$(MODE)/hdrs.txt $(SRCS) $(HDRS) $(INCS)
@build/mkdeps -o $@ -r o/$(MODE)/ o/$(MODE)/srcs.txt o/$(MODE)/hdrs.txt
TAGS: o/$(MODE)/srcs.txt $(SRCS)
@ -251,7 +251,6 @@ COSMOPOLITAN_OBJECTS = \
APE_LIB \
THIRD_PARTY_MUSL \
LIBC_STDIO \
LIBC_CALLS_HEFTY \
THIRD_PARTY_REGEX \
LIBC_ALG \
LIBC_MEM \
@ -351,6 +350,7 @@ o/cosmopolitan.html: \
~/.cosmo.mk:
$(SRCS):
$(HDRS):
$(INCS):
.DEFAULT:
@echo >&2
@echo NOTE: deleting o/$(MODE)/depend because of an unspecified prerequisite: $@ >&2

View file

@ -282,6 +282,9 @@ SECTIONS {
KEEP(*(.textwindowsepilogue))
*(SORT_BY_ALIGNMENT(.text.modernity))
*(SORT_BY_ALIGNMENT(.text.modernity.*))
HIDDEN(__text_syscall_start = .);
*(.text.syscall .text.syscall.*)
HIDDEN(__text_syscall_end = .);
*(SORT_BY_ALIGNMENT(.text.hot))
*(SORT_BY_ALIGNMENT(.text.hot.*))
KEEP(*(.keep.text))
@ -483,6 +486,10 @@ SHSTUB2(.Lape.macho.dd.skip, RVA(ape.macho) / 8);
SHSTUB2(.Lape.macho.dd.count, (.Lape.macho.end - ape.macho) / 8);
PFSTUB4(.Lape.pe.offset, ape.pe - ape.mz);
HIDDEN(__text_syscall_addr = ROUNDDOWN(__text_syscall_start, PAGESIZE));
HIDDEN(__text_syscall_size = (ROUNDUP(__text_syscall_end, PAGESIZE) -
ROUNDDOWN(__text_syscall_start, PAGESIZE)));
HIDDEN(.Lape.pe.optsz = .Lape.pe.sections - (ape.pe + 24));
HIDDEN(.Lape.pe.shnum = (.Lape.pe.sections_end - .Lape.pe.sections) / 40);
HIDDEN(.Lidata.idtsize = idata.idtend - idata.idt);

View file

@ -33,6 +33,7 @@ APELINK = \
APE_FILES := $(wildcard ape/*.*)
APE_HDRS = $(filter %.h,$(APE_FILES))
APE_INCS = $(filter %.inc,$(APE_FILES))
APE_SRCS = $(filter %.S,$(APE_FILES))
APE_OBJS = $(APE_SRCS:%.S=o/$(MODE)/%.o)
APE_DEPS = $(APE_LIB)

View file

@ -37,6 +37,8 @@ export LC_ALL=C
MKDIR=${MKDIR:-$(command -v mkdir) -p} || exit
GZME=
ASAN=
UBSAN=
PLAT="${1%% *}"
FDIAGNOSTIC_COLOR=
CCNAME=${CCNAME:-gcc}
@ -87,11 +89,21 @@ for x; do
set -- "$@" "$x" -Wa,-msse2avx -D__MNO_VZEROUPPER__
;;
-fsanitize=address)
set -- "$@" "$x" -D__FSANITIZE_ADDRESS__
ASAN="$x -D__FSANITIZE_ADDRESS__"
;;
-fsanitize=undefined)
set -- "$@" "$x" -D__FSANITIZE_UNDEFINED__
COUNTERMAND="$COUNTERMAND -fno-data-sections" # sqlite.o
# UBSAN w/ -fdata-sections exceeds ELF's 65,280 section limit
UBSAN="$x -fno-data-sections"
;;
-fno-sanitize=address)
ASAN=
;;
-fno-sanitize=ubsan)
UBSAN=
;;
-fno-sanitize=all)
ASAN=
UBSAN=
;;
-mnop-mcount)
if [ "$CCNAME" = "gcc" ] && [ "$CCVERSION" -ge 6 ]; then
@ -256,7 +268,7 @@ else
done
fi
set -- "$@" -no-canonical-prefixes $FDIAGNOSTIC_COLOR $COUNTERMAND
set -- "$@" -no-canonical-prefixes $FDIAGNOSTIC_COLOR $ASAN $UBSAN $COUNTERMAND
if [ "$SILENT" = "0" ]; then
printf "%s\n" "$*" >&2

View file

@ -94,8 +94,7 @@ CONFIG_CPPFLAGS += \
CONFIG_CCFLAGS += \
$(BACKTRACES) \
$(FTRACE) \
-O1 \
-fno-inline
-O2
CONFIG_COPTS += \
$(SECURITY_BLANKETS) \

View file

@ -2,16 +2,16 @@
#-*-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─────────────┘
#if [ -x "o/$MODE/tool/build/mkdeps.com" ]; then
# set -- "o/$MODE/tool/build/mkdeps.com" "$@"
#else
if [ -x "o/$MODE/tool/build/mkdeps.com" ]; then
set -- "o/$MODE/tool/build/mkdeps.com" "$@"
else
if [ ! -x o/build/bootstrap/mkdeps.com ]; then
mkdir -p o/build/bootstrap &&
cp -a build/bootstrap/mkdeps.com \
o/build/bootstrap/mkdeps.com || exit
fi
set -- o/build/bootstrap/mkdeps.com "$@"
#fi
fi
if [ "$SILENT" = "0" ]; then
printf "%s\n" "$*" >&2

View file

@ -24,9 +24,10 @@ DSP_CORE_A_CHECKS = \
$(DSP_CORE_A_HDRS:%=o/$(MODE)/%.ok)
DSP_CORE_A_DIRECTDEPS = \
LIBC_NEXGEN32E \
LIBC_MEM \
LIBC_INTRIN \
LIBC_MEM \
LIBC_NEXGEN32E \
LIBC_STR \
LIBC_TINYMATH \
LIBC_STUBS

View file

@ -30,6 +30,7 @@ DSP_SCALE_A_DIRECTDEPS = \
LIBC_MEM \
LIBC_NEXGEN32E \
LIBC_RUNTIME \
LIBC_STR \
LIBC_STUBS \
LIBC_STUBS \
LIBC_TIME \

View file

@ -8,7 +8,7 @@
*/
#endif
#include "libc/calls/calls.h"
#include "libc/calls/hefty/copyfile.h"
#include "libc/calls/copyfile.h"
#include "libc/errno.h"
#include "libc/fmt/conv.h"
#include "libc/fmt/fmt.h"

View file

@ -44,7 +44,6 @@ EXAMPLES_DIRECTDEPS = \
LIBC_ALG \
LIBC_BITS \
LIBC_CALLS \
LIBC_CALLS_HEFTY \
LIBC_FMT \
LIBC_INTRIN \
LIBC_LOG \

View file

@ -154,7 +154,6 @@ static bool resized_;
static size_t vtsize_;
static bool artifacts_;
static long tyn_, txn_;
static const char* ffplay_;
static struct Frame vf_[2];
static struct Audio audio_;
static const char* inputfn_;
@ -1685,6 +1684,7 @@ int PlayGame(const char* romfile, const char* opt_tasfile) {
FILE* fp;
int devnull;
int pipefds[2];
const char* ffplay;
inputfn_ = opt_tasfile;
if (!(fp = fopen(romfile, "rb"))) {
@ -1701,7 +1701,7 @@ int PlayGame(const char* romfile, const char* opt_tasfile) {
// open speaker
// todo: this needs plenty of work
if ((ffplay_ = commandvenv("FFPLAY", "ffplay"))) {
if ((ffplay = commandvenv("FFPLAY", "ffplay"))) {
devnull = open("/dev/null", O_WRONLY | O_CLOEXEC);
pipe2(pipefds, O_CLOEXEC);
if (!(playpid_ = vfork())) {
@ -1713,7 +1713,7 @@ int PlayGame(const char* romfile, const char* opt_tasfile) {
dup2(pipefds[0], 0);
dup2(devnull, 1);
dup2(devnull, 2);
execv(ffplay_, (char* const*)args);
execv(ffplay, (char* const*)args);
abort();
}
close(pipefds[0]);

View file

@ -17,6 +17,7 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.h"
.text.syscall
/ Tiny Raw Linux Binary Tutorial
/

View file

@ -8,6 +8,7 @@ LIBC_ALG = $(LIBC_ALG_A_DEPS) $(LIBC_ALG_A)
LIBC_ALG_A = o/$(MODE)/libc/alg/alg.a
LIBC_ALG_A_FILES := $(wildcard libc/alg/*)
LIBC_ALG_A_HDRS = $(filter %.h,$(LIBC_ALG_A_FILES))
LIBC_ALG_A_INCS = $(filter %.inc,$(LIBC_ALG_A_FILES))
LIBC_ALG_A_SRCS_S = $(filter %.S,$(LIBC_ALG_A_FILES))
LIBC_ALG_A_SRCS_C = $(filter %.c,$(LIBC_ALG_A_FILES))
@ -51,6 +52,7 @@ o/$(MODE)/libc/alg/critbit0.o: \
LIBC_ALG_LIBS = $(foreach x,$(LIBC_ALG_ARTIFACTS),$($(x)))
LIBC_ALG_SRCS = $(foreach x,$(LIBC_ALG_ARTIFACTS),$($(x)_SRCS))
LIBC_ALG_HDRS = $(foreach x,$(LIBC_ALG_ARTIFACTS),$($(x)_HDRS))
LIBC_ALG_INCS = $(foreach x,$(LIBC_ALG_ARTIFACTS),$($(x)_INCS))
LIBC_ALG_CHECKS = $(foreach x,$(LIBC_ALG_ARTIFACTS),$($(x)_CHECKS))
LIBC_ALG_OBJS = $(foreach x,$(LIBC_ALG_ARTIFACTS),$($(x)_OBJS))
$(LIBC_ALG_OBJS): $(BUILD_FILES) libc/alg/alg.mk

View file

@ -21,6 +21,7 @@ LIBC_CALLS_A_FILES := \
$(wildcard libc/calls/struct/*) \
$(wildcard libc/calls/*)
LIBC_CALLS_A_HDRS = $(filter %.h,$(LIBC_CALLS_A_FILES))
LIBC_CALLS_A_INCS = $(filter %.inc,$(LIBC_CALLS_A_FILES))
LIBC_CALLS_A_SRCS_S = $(filter %.S,$(LIBC_CALLS_A_FILES))
LIBC_CALLS_A_SRCS_C = $(filter %.c,$(LIBC_CALLS_A_FILES))
@ -43,7 +44,6 @@ LIBC_CALLS_A_DIRECTDEPS = \
LIBC_NT_ADVAPI32 \
LIBC_NT_KERNEL32 \
LIBC_NT_NTDLL \
LIBC_RAND \
LIBC_STR \
LIBC_STUBS \
LIBC_SYSV_CALLS \
@ -86,12 +86,11 @@ o/$(MODE)/libc/calls/mkntenvblock.o: \
LIBC_CALLS_LIBS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)))
LIBC_CALLS_SRCS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)_SRCS))
LIBC_CALLS_HDRS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)_HDRS))
LIBC_CALLS_INCS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)_INCS))
LIBC_CALLS_BINS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)_BINS))
LIBC_CALLS_CHECKS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)_CHECKS))
LIBC_CALLS_OBJS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)_OBJS))
LIBC_CALLS_TESTS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)_TESTS))
.PHONY: o/$(MODE)/libc/calls
o/$(MODE)/libc/calls: \
o/$(MODE)/libc/calls/hefty \
$(LIBC_CALLS_CHECKS)
o/$(MODE)/libc/calls: $(LIBC_CALLS_CHECKS)

View file

@ -42,7 +42,6 @@
* @errors ENOENT, ENOTDIR, ENOSYS
* @asyncsignalsafe
* @see fchmod()
* @syscall
*/
int chmod(const char *pathname, uint32_t mode) {
if (!pathname) return efault();

View file

@ -50,7 +50,6 @@
* errno isn't restored to its original value, to detect prec. loss
* @see strftime(), gettimeofday()
* @asyncsignalsafe
* @syscall
*/
int clock_gettime(int clockid, struct timespec *out_ts) {
/* TODO(jart): Just ignore O/S for MONOTONIC and measure RDTSC on start */

View file

@ -17,13 +17,15 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/internal.h"
#include "libc/nt/enum/filetype.h"
#include "libc/nt/files.h"
#include "libc/nt/runtime.h"
#include "libc/sysv/errfuns.h"
textwindows int close$nt(int fd) {
bool32 ok;
if (g_fds.p[fd].kind == kFdFile) {
if (g_fds.p[fd].kind == kFdFile &&
GetFileType(g_fds.p[fd].handle) == kNtFileTypeDisk) {
/*
* Like Linux, closing a file on Windows doesn't guarantee it's
* immediately synced to disk. But unlike Linux, this could cause
@ -32,6 +34,8 @@ textwindows int close$nt(int fd) {
FlushFileBuffers(g_fds.p[fd].handle);
}
ok = CloseHandle(g_fds.p[fd].handle);
if (g_fds.p[fd].kind == kFdConsole) ok &= CloseHandle(g_fds.p[fd].extra);
if (g_fds.p[fd].kind == kFdConsole) {
ok &= CloseHandle(g_fds.p[fd].extra);
}
return ok ? 0 : __winerr();
}

View file

@ -53,8 +53,7 @@ int close(int fd) {
rc = ebadf();
}
if (!__vforked && fd < g_fds.n) {
g_fds.p[fd].kind = kFdEmpty;
g_fds.f = MIN(g_fds.f, fd);
__releasefd(fd);
}
return rc;
}

View file

@ -16,7 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/hefty/copyfile.h"
#include "libc/calls/copyfile.h"
#include "libc/calls/internal.h"
#include "libc/calls/struct/stat.h"
#include "libc/dce.h"

View file

@ -1,5 +1,5 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_HEFTY_COPYFILE_H_
#define COSMOPOLITAN_LIBC_CALLS_HEFTY_COPYFILE_H_
#ifndef COSMOPOLITAN_LIBC_CALLS_COPYFILE_H_
#define COSMOPOLITAN_LIBC_CALLS_COPYFILE_H_
#define COPYFILE_NOCLOBBER 1
#define COPYFILE_PRESERVE_OWNER 2
@ -12,4 +12,4 @@ int copyfile(const char *, const char *, int) paramsnonnull();
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_CALLS_HEFTY_COPYFILE_H_ */
#endif /* COSMOPOLITAN_LIBC_CALLS_COPYFILE_H_ */

View file

@ -30,17 +30,18 @@
*/
textwindows int dup$nt(int oldfd, int newfd, int flags) {
int64_t proc;
if (!__isfdkind(oldfd, kFdFile)) return ebadf();
if (oldfd < 0) return einval();
if (oldfd >= g_fds.n ||
(g_fds.p[oldfd].kind != kFdFile && g_fds.p[oldfd].kind != kFdSocket &&
g_fds.p[oldfd].kind != kFdConsole)) {
return ebadf();
}
if (newfd == -1) {
if ((newfd = __getemptyfd()) == -1) {
return -1;
}
} else if (__ensurefds(newfd) != -1) {
if (g_fds.p[newfd].kind != kFdEmpty) {
close(newfd);
}
if ((newfd = __reservefd()) == -1) return -1;
} else {
return -1;
if (__ensurefds(newfd) == -1) return -1;
if (g_fds.p[newfd].kind) close(newfd);
g_fds.p[newfd].kind = kFdReserved;
}
proc = GetCurrentProcess();
if (DuplicateHandle(proc, g_fds.p[oldfd].handle, proc, &g_fds.p[newfd].handle,
@ -49,6 +50,7 @@ textwindows int dup$nt(int oldfd, int newfd, int flags) {
g_fds.p[newfd].flags = flags;
return newfd;
} else {
__releasefd(newfd);
return __winerr();
}
}

View file

@ -25,13 +25,14 @@ int32_t dup3$sysv(int32_t oldfd, int32_t newfd, int flags) {
static bool once, demodernize;
int olderr, fd;
if (!once) {
once = true;
olderr = errno;
fd = __dup3$sysv(oldfd, newfd, flags);
if ((fd == -1 && errno == ENOSYS) || fd == __NR_dup3_linux) {
demodernize = true;
once = true;
errno = olderr;
} else {
once = true;
return fd;
}
} else if (!demodernize) {

View file

@ -17,6 +17,7 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/bits/bits.h"
#include "libc/bits/weaken.h"
#include "libc/calls/internal.h"
#include "libc/mem/mem.h"
@ -24,24 +25,29 @@
#include "libc/sysv/errfuns.h"
int __ensurefds(int fd) {
size_t n;
struct Fd *p;
if (fd < g_fds.n) return fd;
if (weaken(malloc)) {
n = MAX(fd + 1, g_fds.n + (g_fds.n << 1));
if ((p = weaken(malloc)(n * sizeof(*p)))) {
memcpy(p, g_fds.p, g_fds.n * sizeof(*p));
memset(p + g_fds.n, 0, (n - g_fds.n) * sizeof(*p));
if (g_fds.p != g_fds.__init_p && weaken(free)) {
weaken(free)(g_fds.p);
size_t n1, n2;
struct Fd *p1, *p2;
for (;;) {
p1 = g_fds.p;
n1 = g_fds.n;
if (fd < n1) return fd;
if (weaken(malloc)) {
n2 = MAX(fd + 1, n1 + (n1 << 1));
if ((p2 = weaken(malloc)(n2 * sizeof(*p1)))) {
memcpy(p2, p1, n1 * sizeof(*p1));
memset(p2 + n1, 0, (n2 - n1) * sizeof(*p1));
if (p1 != g_fds.__init_p && weaken(free)) weaken(free)(p1);
if (cmpxchg(&g_fds.p, p1, p2)) {
g_fds.n = n2;
return fd;
} else if (weaken(free)) {
weaken(free)(p2);
}
} else {
return enomem();
}
g_fds.p = p;
g_fds.n = n;
return fd;
} else {
return enomem();
return emfile();
}
} else {
return emfile();
}
}

View file

@ -47,7 +47,7 @@ textwindows int execve$nt(const char *program, char *const argv[],
close(i);
}
}
rc = ntspawn(program, argv, envp, NULL, NULL, true, 0, NULL, &startinfo,
rc = ntspawn(program, argv, envp, NULL, NULL, NULL, true, 0, NULL, &startinfo,
&procinfo);
if (rc == -1) return -1;
CloseHandle(procinfo.hThread);

View file

@ -29,7 +29,6 @@
* @param len 0 means til end of file
* @param advice can be MADV_SEQUENTIAL, MADV_RANDOM, etc.
* @return -1 on error
* @syscall
*/
int fadvise(int fd, uint64_t offset, uint64_t len, int advice) {
if (!IsWindows()) {

View file

@ -38,7 +38,6 @@
* @return 0 on success, or -1 w/ errno
* @note limited availability on rhel5 and openbsd
* @see ftruncate()
* @syscall
*/
int fallocate(int fd, int32_t mode, int64_t offset, int64_t length) {
int rc;

View file

@ -40,7 +40,6 @@
* @errors ENOSYS
* @asyncsignalsafe
* @see chmod()
* @syscall
*/
int fchmod(int fd, uint32_t mode) {
/* TODO(jart): Windows */

View file

@ -28,7 +28,6 @@
* @return 0 on success, or -1 w/ errno
* @see /etc/passwd for user ids
* @see /etc/group for group ids
* @syscall
*/
int fchown(int fd, uint32_t uid, uint32_t gid) {
/* TODO(jart): Windows? */

View file

@ -29,7 +29,6 @@
* @param arg can be FD_CLOEXEC, etc. depending
* @return 0 on success, or -1 w/ errno
* @asyncsignalsafe
* @syscall
*/
int fcntl(int fd, int cmd, ...) {
va_list va;

View file

@ -26,7 +26,6 @@
* @return 0 on success, or -1 w/ errno
* @see fsync(), sync_file_range()
* @asyncsignalsafe
* @syscall
*/
int fdatasync(int fd) {
if (!IsWindows()) {

View file

@ -16,10 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/bits/bits.h"
#include "libc/bits/safemacros.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
/**
* Returns value of environment variable, or NULL if not found.

View file

@ -1,72 +0,0 @@
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘
#
# SYNOPSIS
#
# Cosmopolitan System Call Compatibility Layer
#
# DESCRIPTION
#
# This subpackage exports functions traditionally understood as system
# calls that Cosmopolitan needs to wrap in a nontrivial way, requiring
# things like dynamic memory allocation.
PKGS += LIBC_CALLS_HEFTY
LIBC_CALLS_HEFTY_ARTIFACTS += LIBC_CALLS_HEFTY_A
LIBC_CALLS_HEFTY = $(LIBC_CALLS_HEFTY_A_DEPS) $(LIBC_CALLS_HEFTY_A)
LIBC_CALLS_HEFTY_A = o/$(MODE)/libc/calls/hefty/hefty.a
LIBC_CALLS_HEFTY_A_FILES := $(wildcard libc/calls/hefty/*)
LIBC_CALLS_HEFTY_A_HDRS = $(filter %.h,$(LIBC_CALLS_HEFTY_A_FILES))
LIBC_CALLS_HEFTY_A_SRCS_S = $(filter %.S,$(LIBC_CALLS_HEFTY_A_FILES))
LIBC_CALLS_HEFTY_A_SRCS_C = $(filter %.c,$(LIBC_CALLS_HEFTY_A_FILES))
LIBC_CALLS_HEFTY_A_SRCS = \
$(LIBC_CALLS_HEFTY_A_SRCS_S) \
$(LIBC_CALLS_HEFTY_A_SRCS_C)
LIBC_CALLS_HEFTY_A_OBJS = \
$(LIBC_CALLS_HEFTY_A_SRCS_S:%.S=o/$(MODE)/%.o) \
$(LIBC_CALLS_HEFTY_A_SRCS_C:%.c=o/$(MODE)/%.o)
LIBC_CALLS_HEFTY_A_CHECKS = \
$(LIBC_CALLS_HEFTY_A).pkg \
$(LIBC_CALLS_HEFTY_A_HDRS:%=o/$(MODE)/%.ok)
LIBC_CALLS_HEFTY_A_DIRECTDEPS = \
LIBC_ALG \
LIBC_CALLS \
LIBC_FMT \
LIBC_INTRIN \
LIBC_MEM \
LIBC_NEXGEN32E \
LIBC_NT_KERNEL32 \
LIBC_RUNTIME \
LIBC_STR \
LIBC_STUBS \
LIBC_SYSV \
LIBC_SYSV_CALLS
LIBC_CALLS_HEFTY_A_DEPS := \
$(call uniq,$(foreach x,$(LIBC_CALLS_HEFTY_A_DIRECTDEPS),$($(x))))
$(LIBC_CALLS_HEFTY_A): \
libc/calls/hefty/ \
$(LIBC_CALLS_HEFTY_A).pkg \
$(LIBC_CALLS_HEFTY_A_OBJS)
$(LIBC_CALLS_HEFTY_A).pkg: \
$(LIBC_CALLS_HEFTY_A_OBJS) \
$(foreach x,$(LIBC_CALLS_HEFTY_A_DIRECTDEPS),$($(x)_A).pkg)
LIBC_CALLS_HEFTY_LIBS = $(foreach x,$(LIBC_CALLS_HEFTY_ARTIFACTS),$($(x)))
LIBC_CALLS_HEFTY_SRCS = $(foreach x,$(LIBC_CALLS_HEFTY_ARTIFACTS),$($(x)_SRCS))
LIBC_CALLS_HEFTY_HDRS = $(foreach x,$(LIBC_CALLS_HEFTY_ARTIFACTS),$($(x)_HDRS))
LIBC_CALLS_HEFTY_BINS = $(foreach x,$(LIBC_CALLS_HEFTY_ARTIFACTS),$($(x)_BINS))
LIBC_CALLS_HEFTY_CHECKS = $(foreach x,$(LIBC_CALLS_HEFTY_ARTIFACTS),$($(x)_CHECKS))
LIBC_CALLS_HEFTY_OBJS = $(foreach x,$(LIBC_CALLS_HEFTY_ARTIFACTS),$($(x)_OBJS))
LIBC_CALLS_HEFTY_TESTS = $(foreach x,$(LIBC_CALLS_HEFTY_ARTIFACTS),$($(x)_TESTS))
$(LIBC_CALLS_HEFTY_OBJS): $(BUILD_FILES) libc/calls/hefty/hefty.mk
.PHONY: o/$(MODE)/libc/calls/hefty
o/$(MODE)/libc/calls/hefty: $(LIBC_CALLS_HEFTY_CHECKS)

View file

@ -36,6 +36,7 @@ struct IoctlPtmGet {
char theduxname[16];
char workername[16];
};
enum FdKind {
kFdEmpty,
kFdFile,
@ -45,6 +46,7 @@ enum FdKind {
kFdSerial,
kFdZip,
kFdEpoll,
kFdReserved
};
struct Fd {
@ -71,7 +73,8 @@ hidden extern struct NtSystemInfo g_ntsysteminfo;
hidden extern struct NtStartupInfo g_ntstartupinfo;
hidden extern const struct NtSecurityAttributes kNtIsInheritable;
ssize_t __getemptyfd(void) hidden;
int __reservefd(void) hidden;
void __releasefd(int) hidden;
int __ensurefds(int) hidden;
void __removefd(int) hidden;

View file

@ -22,7 +22,6 @@
#include "libc/nt/console.h"
#include "libc/nt/enum/consolemodeflags.h"
#include "libc/nt/enum/version.h"
#include "libc/nt/struct/teb.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/termios.h"
#include "libc/sysv/errfuns.h"

View file

@ -25,6 +25,7 @@
/**
* Controls settings on device.
* @vforksafe
*/
int(ioctl)(int fd, uint64_t request, void *memory) {
__IOCTL_DISPATCH(EQUAL, fd, request, memory);

View file

@ -32,7 +32,11 @@
#define kBufSize 1024
#define kProcStatus "/proc/self/status"
_Alignas(16) static const char kGdbPid[] = "TracerPid:\t";
#define kPid "TracerPid:\t"
static noasan int NtBeingDebugged(void) {
return NtGetPeb()->BeingDebugged;
}
/**
* Determines if gdb, strace, windbg, etc. is controlling process.
@ -42,19 +46,18 @@ int IsDebuggerPresent(bool force) {
int fd, res;
ssize_t got;
char buf[1024];
res = 0;
res = false;
if (!force) {
if (getenv("HEISENDEBUG")) return false;
if (IsGenuineCosmo()) return false;
}
if (IsWindows()) {
res = NtGetPeb()->BeingDebugged;
res = NtBeingDebugged();
} else if (IsLinux()) {
if ((fd = openat$sysv(AT_FDCWD, kProcStatus, O_RDONLY, 0)) != -1) {
if ((got = read$sysv(fd, buf, sizeof(buf) - sizeof(kGdbPid))) != -1) {
if ((got = read$sysv(fd, buf, sizeof(buf) - sizeof(kPid))) != -1) {
buf[got] = '\0';
res =
atoi(firstnonnull(strstr(buf, kGdbPid), kGdbPid) + strlen(kGdbPid));
res = atoi(firstnonnull(strstr(buf, kPid), kPid) + strlen(kPid));
}
close$sysv(fd);
}

View file

@ -29,9 +29,9 @@ forceinline typeof(PrefetchVirtualMemory) *GetPrefetchVirtualMemory(void) {
static bool once;
static typeof(PrefetchVirtualMemory) *PrefetchVirtualMemory_;
if (!once) {
once = true;
PrefetchVirtualMemory_ = /* win8.1+ */
GetProcAddressModule("Kernel32.dll", "PrefetchVirtualMemory");
once = true;
}
return PrefetchVirtualMemory_;
}
@ -40,9 +40,9 @@ forceinline typeof(OfferVirtualMemory) *GetOfferVirtualMemory(void) {
static bool once;
static typeof(OfferVirtualMemory) *OfferVirtualMemory_;
if (!once) {
once = true;
OfferVirtualMemory_ = /* win8.1+ */
GetProcAddressModule("Kernel32.dll", "OfferVirtualMemory");
once = true;
}
return OfferVirtualMemory_;
}

View file

@ -37,8 +37,8 @@
* @kudos Daniel Colascione for teaching how to quote
* @see libc/runtime/dosargv.c
*/
textwindows int mkntcmdline(char16_t cmdline[ARG_MAX], const char *prog,
char *const argv[]) {
textwindows noasan int mkntcmdline(char16_t cmdline[ARG_MAX], const char *prog,
char *const argv[]) {
char *arg;
uint64_t w;
wint_t x, y;

View file

@ -29,21 +29,18 @@
#include "libc/str/utf16.h"
#include "libc/sysv/errfuns.h"
static int CompareStrings(const char *l, const char *r) {
static noasan int CompareStrings(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);
}
static void SortStrings(char **a, size_t n) {
char *t;
size_t i, j;
for (i = 1; i < n; ++i) {
for (t = a[i], j = i; j > 0 && CompareStrings(t, a[j - 1]) < 0; --j) {
a[j] = a[j - 1];
}
a[j] = t;
static noasan void InsertString(char **a, size_t i, char *s) {
size_t j;
for (j = i; j > 0 && CompareStrings(s, a[j - 1]) < 0; --j) {
a[j] = a[j - 1];
}
a[j] = s;
}
/**
@ -51,19 +48,24 @@ static void SortStrings(char **a, size_t n) {
*
* This is designed to meet the requirements of CreateProcess().
*
* @param envvars receives sorted double-NUL terminated string list
* @param envp is an a NULL-terminated array of UTF-8 strings
* @return freshly allocated lpEnvironment or NULL w/ errno
* @param extravar is a VAR=val string we consider part of envp or NULL
* @return 0 on success, or -1 w/ errno
* @error E2BIG if total number of shorts exceeded ARG_MAX (0x8000)
*/
textwindows int mkntenvblock(char16_t envvars[ARG_MAX], char *const envp[]) {
textwindows noasan int mkntenvblock(char16_t envvars[ARG_MAX],
char *const envp[], const char *extravar) {
char *t;
axdx_t rc;
uint64_t w;
char **vars;
wint_t x, y;
size_t i, j, k, n, m;
for (n = 0; envp[n];) n++;
vars = alloca(n * sizeof(char *));
memcpy(vars, envp, n * sizeof(char *));
SortStrings(vars, n);
vars = alloca((n + 1) * sizeof(char *));
for (i = 0; i < n; ++i) InsertString(vars, i, envp[i]);
if (extravar) InsertString(vars, n++, extravar);
for (k = i = 0; i < n; ++i) {
j = 0;
do {

View file

@ -34,7 +34,7 @@ extern __msabi typeof(VirtualProtect) *const __imp_VirtualProtect;
* @return 0 on success, or -1 w/ errno
* @see mmap()
*/
int mprotect(void *addr, uint64_t len, int prot) {
textsyscall int mprotect(void *addr, uint64_t len, int prot) {
bool cf;
int64_t rc;
uint32_t oldprot;

View file

@ -23,6 +23,7 @@
#include "libc/dce.h"
#include "libc/nexgen32e/rdtsc.h"
#include "libc/nexgen32e/x86feature.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/clock.h"
#include "libc/time/time.h"
@ -55,19 +56,21 @@ static long double MeasureNanosPerCycle(void) {
}
static void InitTime(void) {
g_now.cpn = MeasureNanosPerCycle();
g_now.r0 = dtime(CLOCK_REALTIME);
g_now.k0 = rdtsc();
g_now.once = true;
struct Now now;
now.cpn = MeasureNanosPerCycle();
now.r0 = dtime(CLOCK_REALTIME);
now.k0 = rdtsc();
now.once = true;
memcpy(&g_now, &now, sizeof(now));
}
long double converttickstonanos(uint64_t ticks) {
long double ConvertTicksToNanos(uint64_t ticks) {
if (!g_now.once) InitTime();
return ticks * g_now.cpn; /* pico scale */
}
long double converttickstoseconds(uint64_t ticks) {
return 1 / 1e9 * converttickstonanos(ticks);
static long double ConvertTicksToSeconds(uint64_t ticks) {
return 1 / 1e9 * ConvertTicksToNanos(ticks);
}
long double nowl$sys(void) {
@ -78,5 +81,5 @@ long double nowl$art(void) {
uint64_t ticks;
if (!g_now.once) InitTime();
ticks = unsignedsubtract(rdtsc(), g_now.k0);
return g_now.r0 + converttickstoseconds(ticks);
return g_now.r0 + ConvertTicksToSeconds(ticks);
}

View file

@ -48,6 +48,7 @@ struct SpawnBlock {
* don't need to be passed in sorted order; however, this function
* goes faster the closer they are to sorted
* @param envp[m-1] is NULL
* @param extravar is added to envp to avoid setenv() in caller
* @param bInheritHandles means handles already marked inheritable will
* be inherited; which, assuming the System V wrapper functions are
* being used, should mean (1) all files and sockets that weren't
@ -59,7 +60,7 @@ struct SpawnBlock {
*/
textwindows int ntspawn(
const char *prog, char *const argv[], char *const envp[],
struct NtSecurityAttributes *opt_lpProcessAttributes,
const char *extravar, struct NtSecurityAttributes *opt_lpProcessAttributes,
struct NtSecurityAttributes *opt_lpThreadAttributes, bool32 bInheritHandles,
uint32_t dwCreationFlags, const char16_t *opt_lpCurrentDirectory,
const struct NtStartupInfo *lpStartupInfo,
@ -81,7 +82,7 @@ textwindows int ntspawn(
MapViewOfFileExNuma(handle, kNtFileMapRead | kNtFileMapWrite, 0, 0,
blocksize, NULL, kNtNumaNoPreferredNode))) {
if (mkntcmdline(block->cmdline, prog, argv) != -1 &&
mkntenvblock(block->envvars, envp) != -1) {
mkntenvblock(block->envvars, envp, extravar) != -1) {
if (CreateProcess(NULL, block->cmdline, opt_lpProcessAttributes,
opt_lpThreadAttributes, bInheritHandles,
dwCreationFlags | kNtCreateUnicodeEnvironment,

View file

@ -1,5 +1,5 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_HEFTY_NTSPAWN_H_
#define COSMOPOLITAN_LIBC_CALLS_HEFTY_NTSPAWN_H_
#ifndef COSMOPOLITAN_LIBC_CALLS_NTSPAWN_H_
#define COSMOPOLITAN_LIBC_CALLS_NTSPAWN_H_
#include "libc/nt/struct/processinformation.h"
#include "libc/nt/struct/securityattributes.h"
#include "libc/nt/struct/startupinfo.h"
@ -7,12 +7,12 @@
COSMOPOLITAN_C_START_
int mkntcmdline(char16_t[ARG_MAX], const char *, char *const[]) hidden;
int mkntenvblock(char16_t[ARG_MAX], char *const[]) hidden;
int ntspawn(const char *, char *const[], char *const[],
int mkntenvblock(char16_t[ARG_MAX], char *const[], const char *) hidden;
int ntspawn(const char *, char *const[], char *const[], const char *,
struct NtSecurityAttributes *, struct NtSecurityAttributes *,
bool32, uint32_t, const char16_t *, const struct NtStartupInfo *,
struct NtProcessInformation *) hidden;
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_CALLS_HEFTY_NTSPAWN_H_ */
#endif /* COSMOPOLITAN_LIBC_CALLS_NTSPAWN_H_ */

View file

@ -42,16 +42,7 @@ static textwindows int64_t open$nt$impl(int dirfd, const char *path,
char16_t path16[PATH_MAX];
if (__mkntpathat(dirfd, path, flags, path16) == -1) return -1;
if ((handle = CreateFile(
path16,
(flags & 0xf000000f) |
(/* this is needed if we mmap(rwx+cow)
nt is choosy about open() access */
(flags & O_APPEND)
? kNtFileAppendData
: (flags & O_ACCMODE) == O_RDONLY
? kNtGenericExecute | kNtFileGenericRead
: kNtGenericExecute | kNtFileGenericRead |
kNtFileGenericWrite),
path16, flags & 0xf000000f, /* see consts.sh */
(flags & O_EXCL)
? kNtFileShareExclusive
: kNtFileShareRead | kNtFileShareWrite | kNtFileShareDelete,
@ -75,14 +66,6 @@ static textwindows int64_t open$nt$impl(int dirfd, const char *path,
kNtFileFlagBackupSemantics | kNtFileFlagPosixSemantics |
kNtFileAttributeTemporary)))),
0)) != -1) {
if (flags & O_SPARSE) {
/*
* TODO(jart): Can all files be sparse files? That seems to be the
* way Linux behaves out of the box.
* TODO(jart): Wow why does sparse wreak havoc?
*/
DeviceIoControl(handle, kNtFsctlSetSparse, NULL, 0, NULL, 0, &br, NULL);
}
return handle;
} else if (GetLastError() == kNtErrorFileExists &&
((flags & O_CREAT) &&
@ -129,11 +112,16 @@ static textwindows ssize_t open$nt$file(int dirfd, const char *file,
textwindows ssize_t open$nt(int dirfd, const char *file, uint32_t flags,
int32_t mode) {
size_t fd;
if ((fd = __getemptyfd()) == -1) return -1;
int fd;
ssize_t rc;
if ((fd = __reservefd()) == -1) return -1;
if ((flags & O_ACCMODE) == O_RDWR && !strcmp(file, kNtMagicPaths.devtty)) {
return open$nt$console(dirfd, &kNtMagicPaths, flags, mode, fd);
rc = open$nt$console(dirfd, &kNtMagicPaths, flags, mode, fd);
} else {
return open$nt$file(dirfd, file, flags, mode, fd);
rc = open$nt$file(dirfd, file, flags, mode, fd);
}
if (rc == -1) {
__releasefd(fd);
}
return rc;
}

View file

@ -31,7 +31,7 @@
* @asyncsignalsafe
* @vforksafe
*/
nodiscard int open(const char *file, int flags, ...) {
int open(const char *file, int flags, ...) {
va_list va;
unsigned mode;
va_start(va, flags);

View file

@ -67,8 +67,8 @@ static int openanon$impl(const char *name, unsigned flags,
}
return fd;
} else {
if ((fd = __getemptyfd()) != -1 &&
(g_fds.p[fd].handle = CreateFileA(
if ((fd = __reservefd()) == -1) return -1;
if ((g_fds.p[fd].handle = CreateFileA(
pathbuf, kNtGenericRead | kNtGenericWrite, kNtFileShareExclusive,
&kNtIsInheritable, kNtCreateAlways,
(kNtFileAttributeNotContentIndexed | kNtFileAttributeNormal |
@ -78,6 +78,7 @@ static int openanon$impl(const char *name, unsigned flags,
g_fds.p[fd].flags = flags;
return fd;
} else {
__releasefd(fd);
return __winerr();
}
}

View file

@ -37,6 +37,7 @@
* ignored if O_CREAT or O_TMPFILE weren't passed
* @return number needing close(), or -1 w/ errno
* @asyncsignalsafe
* @vforksafe
*/
nodiscard int openat(int dirfd, const char *file, int flags, ...) {
va_list va;
@ -47,11 +48,9 @@ nodiscard int openat(int dirfd, const char *file, int flags, ...) {
va_end(va);
if (!file) return efault();
if (weaken(__zipos_open) && weaken(__zipos_parseuri)(file, &zipname) != -1) {
if (dirfd == AT_FDCWD) {
return weaken(__zipos_open)(&zipname, flags, mode);
} else {
return eopnotsupp(); /* TODO */
}
if (__vforked) return einval();
if (dirfd != AT_FDCWD) return einval();
return weaken(__zipos_open)(&zipname, flags, mode);
} else if (!IsWindows()) {
return openat$sysv(dirfd, file, flags, mode);
} else {

View file

@ -58,16 +58,19 @@ textwindows int pipe$nt(int pipefd[2], unsigned flags) {
int reader, writer;
char16_t pipename[64];
CreatePipeName(pipename);
if ((reader = __reservefd()) == -1) return -1;
if ((writer = __reservefd()) == -1) {
__releasefd(reader);
return -1;
}
if ((hin = CreateNamedPipe(pipename, kNtPipeAccessInbound,
kNtPipeWait | kNtPipeReadmodeByte, 1, 65536, 65536,
0, &kNtIsInheritable)) != -1) {
if ((hout = CreateFile(pipename, kNtGenericWrite, kNtFileShareWrite,
&kNtIsInheritable, kNtOpenExisting, 0, 0)) != -1) {
reader = __getemptyfd();
g_fds.p[reader].kind = kFdFile;
g_fds.p[reader].flags = flags;
g_fds.p[reader].handle = hin;
writer = __getemptyfd();
g_fds.p[writer].kind = kFdFile;
g_fds.p[writer].flags = flags;
g_fds.p[writer].handle = hout;
@ -78,5 +81,6 @@ textwindows int pipe$nt(int pipefd[2], unsigned flags) {
CloseHandle(hin);
}
}
__releasefd(reader);
return __winerr();
}

29
libc/calls/releasefd.c Normal file
View file

@ -0,0 +1,29 @@
/*-*- 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/bits/bits.h"
#include "libc/calls/internal.h"
void __releasefd(int fd) {
int x;
g_fds.p[fd].kind = kFdEmpty;
do {
x = g_fds.f;
if (fd >= x) break;
} while (!cmpxchg(&g_fds.f, x, fd));
}

View file

@ -24,11 +24,16 @@
/**
* Finds open file descriptor slot.
*/
ssize_t __getemptyfd(void) {
for (; g_fds.f < g_fds.n; ++g_fds.f) {
if (g_fds.p[g_fds.f].kind == kFdEmpty) {
return g_fds.f;
int __reservefd(void) {
int fd;
for (;;) {
fd = g_fds.f;
if (fd >= g_fds.n) {
if (__ensurefds(fd) == -1) return -1;
}
cmpxchg(&g_fds.f, fd, fd + 1);
if (cmpxchg(&g_fds.p[fd].kind, kFdEmpty, kFdReserved)) {
return fd;
}
}
return __ensurefds(g_fds.f);
}

View file

@ -19,6 +19,7 @@
#include "libc/bits/bits.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/sigbits.h"
#include "libc/calls/struct/sigaction-freebsd.internal.h"
#include "libc/calls/struct/sigaction-linux.internal.h"
#include "libc/calls/struct/sigaction-openbsd.internal.h"
@ -120,6 +121,7 @@ static void sigaction$native2cosmo(union metasigaction *sa) {
*
* @see xsigaction() for a much better api
* @asyncsignalsafe
* @vforksafe
*/
int(sigaction)(int sig, const struct sigaction *act, struct sigaction *oldact) {
_Static_assert(sizeof(struct sigaction) > sizeof(struct sigaction$linux) &&
@ -129,9 +131,8 @@ int(sigaction)(int sig, const struct sigaction *act, struct sigaction *oldact) {
sizeof(struct sigaction) > sizeof(struct sigaction$openbsd));
int rc, rva, oldrva;
struct sigaction *ap, copy;
if (!(0 < sig && sig < NSIG) || sig == SIGKILL || sig == SIGSTOP) {
return einval();
}
if (!(0 < sig && sig < NSIG)) return einval();
if (sig == SIGKILL || sig == SIGSTOP) return einval();
if (!act) {
rva = (int32_t)(intptr_t)SIG_DFL;
} else if ((intptr_t)act->sa_handler < kSigactionMinRva) {
@ -142,6 +143,9 @@ int(sigaction)(int sig, const struct sigaction *act, struct sigaction *oldact) {
} else {
return efault();
}
if (__vforked && rva != (intptr_t)SIG_DFL && rva != (intptr_t)SIG_IGN) {
return einval();
}
if (!IsWindows()) {
if (!IsMetal()) {
if (act) {
@ -150,16 +154,13 @@ int(sigaction)(int sig, const struct sigaction *act, struct sigaction *oldact) {
if (IsXnu()) {
ap->sa_restorer = (void *)&xnutrampoline;
ap->sa_handler = (void *)&xnutrampoline;
} else {
if (IsLinux()) {
if (!(ap->sa_flags & SA_RESTORER)) {
ap->sa_flags |= SA_RESTORER;
ap->sa_restorer = &__restore_rt;
}
}
if (rva >= kSigactionMinRva) {
ap->sa_sigaction = (sigaction_f)__sigenter;
} else if (IsLinux()) {
if (!(ap->sa_flags & SA_RESTORER)) {
ap->sa_flags |= SA_RESTORER;
ap->sa_restorer = &__restore_rt;
}
} else if (rva >= kSigactionMinRva) {
ap->sa_sigaction = (sigaction_f)__sigenter;
}
sigaction$cosmo2native((union metasigaction *)ap);
} else {
@ -179,7 +180,7 @@ int(sigaction)(int sig, const struct sigaction *act, struct sigaction *oldact) {
}
rc = 0;
}
if (rc != -1) {
if (rc != -1 && !__vforked) {
if (oldact) {
oldrva = __sighandrvas[sig];
oldact->sa_sigaction = (sigaction_f)(

View file

@ -20,7 +20,7 @@
#include "libc/macros.h"
.source __FILE__
/ System Five signal handler.
/ BSD signal handler.
/
/ This is needed because (1) a signal is allowed to trigger at
/ just about any time, and leaf functions (e.g. memcpy) aren't

View file

@ -28,7 +28,7 @@
* @return -1 w/ few exceptions
* @note this is a code-size saving device
*/
privileged int64_t __winerr(void) {
privileged noasan int64_t __winerr(void) {
if (IsWindows()) {
errno = GetLastError();
return -1;

View file

@ -42,7 +42,6 @@ textwindows ssize_t write$nt(struct Fd *fd, const struct iovec *iov,
iovlen ? clampio(iov[0].iov_len) : 0, &wrote,
offset2overlap(opt_offset, &overlap))) {
if (!wrote) assert(!SumIovecLen(iov, iovlen));
FlushFileBuffers(fd->handle);
return wrote;
} else {
return __winerr();

View file

@ -17,6 +17,7 @@
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "ape/relocations.h"
#include "libc/macros.h"
/**
* @fileoverview Cosmopolitan ELF-Normative Linker Script.
@ -66,6 +67,9 @@ SECTIONS {
.text : {
*(SORT_BY_ALIGNMENT(.text.hot))
KEEP(*(.keep.text))
HIDDEN(__text_syscall_start = .);
*(.text.syscall .text.syscall.*)
HIDDEN(__text_syscall_end = .);
*(.text .text.*)
KEEP(*(SORT_BY_NAME(.sort.text.*)))
}
@ -207,3 +211,7 @@ SECTIONS {
*(.*)
}
}
HIDDEN(__text_syscall_addr = ROUNDDOWN(__text_syscall_start, PAGESIZE));
HIDDEN(__text_syscall_size = (ROUNDUP(__text_syscall_end, PAGESIZE) -
ROUNDDOWN(__text_syscall_start, PAGESIZE)));

View file

@ -17,6 +17,7 @@ LIBC_FMT = $(LIBC_FMT_A_DEPS) $(LIBC_FMT_A)
LIBC_FMT_A = o/$(MODE)/libc/fmt/fmt.a
LIBC_FMT_A_FILES := $(wildcard libc/fmt/*)
LIBC_FMT_A_HDRS = $(filter %.h,$(LIBC_FMT_A_FILES))
LIBC_FMT_A_INCS = $(filter %.inc,$(LIBC_FMT_A_FILES))
LIBC_FMT_A_SRCS_S = $(filter %.S,$(LIBC_FMT_A_FILES))
LIBC_FMT_A_SRCS_C = $(filter %.c,$(LIBC_FMT_A_FILES))
@ -75,6 +76,7 @@ o/$(MODE)/libc/fmt/itoa128radix10.greg.o: \
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))
LIBC_FMT_INCS = $(foreach x,$(LIBC_FMT_ARTIFACTS),$($(x)_INCS))
LIBC_FMT_CHECKS = $(foreach x,$(LIBC_FMT_ARTIFACTS),$($(x)_CHECKS))
LIBC_FMT_OBJS = $(foreach x,$(LIBC_FMT_ARTIFACTS),$($(x)_OBJS))
$(LIBC_FMT_OBJS): $(BUILD_FILES) libc/fmt/fmt.mk

View file

@ -331,7 +331,7 @@ typedef uint64_t uintmax_t;
#ifndef nullterminated
#if !defined(__STRICT_ANSI__) && \
(__has_attribute(__sentinel__) || __GNUC__ >= 4)
(__has_attribute(__sentinel__) || __GNUC__ + 0 >= 4)
#define nullterminated(x) __attribute__((__sentinel__ x))
#else
#define nullterminated(x)
@ -618,6 +618,7 @@ typedef uint64_t uintmax_t;
#define textexit _Section(".text.exit") noinstrument
#define textreal _Section(".text.real")
#define textwindows _Section(".text.windows")
#define textsyscall _Section(".text.syscall") noinline
#define antiquity _Section(".text.antiquity")
#else
#define testonly

View file

@ -20,17 +20,19 @@
#include "libc/bits/bits.h"
#include "libc/bits/weaken.h"
#include "libc/calls/calls.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/linux/exit.h"
#include "libc/linux/write.h"
#include "libc/log/log.h"
#include "libc/macros.h"
#include "libc/mem/hook/hook.h"
#include "libc/nt/enum/version.h"
#include "libc/nt/runtime.h"
#include "libc/runtime/directmap.h"
#include "libc/runtime/memtrack.h"
#include "libc/runtime/runtime.h"
#include "libc/sysv/consts/auxv.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/nr.h"
#include "libc/sysv/consts/prot.h"
#include "third_party/dlmalloc/dlmalloc.internal.h"
@ -154,6 +156,13 @@ static void *__asan_repstosb(void *di, int al, size_t cx) {
return di;
}
static void *__asan_repmovsb(void *di, void *si, size_t cx) {
asm("rep movsb"
: "=D"(di), "=S"(si), "=c"(cx), "=m"(*(char(*)[cx])di)
: "0"(di), "1"(si), "2"(cx), "m"(*(char(*)[cx])si));
return di;
}
static void *__asan_memset(void *p, int c, size_t n) {
char *b;
size_t i;
@ -264,14 +273,18 @@ static void *__asan_mempcpy(void *dst, const void *src, size_t n) {
__builtin_memcpy(d + n - 8, &b, 8);
return d + n;
default:
i = 0;
do {
__builtin_memcpy(&a, s + i, 8);
asm volatile("" ::: "memory");
__builtin_memcpy(d + i, &a, 8);
} while ((i += 8) + 8 <= n);
for (; i < n; ++i) d[i] = s[i];
return d + i;
if (n <= 64) {
i = 0;
do {
__builtin_memcpy(&a, s + i, 8);
asm volatile("" ::: "memory");
__builtin_memcpy(d + i, &a, 8);
} while ((i += 8) + 8 <= n);
for (; i < n; ++i) d[i] = s[i];
return d + i;
} else {
return __asan_repmovsb(d, s, n);
}
}
}
@ -280,16 +293,6 @@ static void *__asan_memcpy(void *dst, const void *src, size_t n) {
return dst;
}
static void *__asan_memrchr(void *p, int c, size_t n) {
uint8_t *b;
for (c &= 0xff, b = p; n--;) {
if (b[n] == c) {
return b + n;
}
}
return NULL;
}
static size_t __asan_int2hex(uint64_t x, char b[17], uint8_t k) {
int i;
char *p;
@ -373,7 +376,9 @@ static const char *__asan_dscribe_heap_poison(long c) {
}
}
static const char *__asan_describe_access_poison(int c) {
static const char *__asan_describe_access_poison(char *p) {
int c = p[0];
if (1 <= c && c <= 7) c = p[1];
switch (c) {
case kAsanHeapFree:
return "heap use after free";
@ -406,30 +411,42 @@ static const char *__asan_describe_access_poison(int c) {
}
}
static ssize_t __asan_write(const void *data, size_t size) {
static textsyscall wontreturn void __asan_exit(int rc) {
if (!IsWindows()) {
asm volatile("syscall"
: /* no outputs */
: "a"(__NR_exit_group), "D"(rc)
: "memory");
unreachable;
} else {
ExitProcess(rc);
}
}
static textsyscall ssize_t __asan_write(const void *data, size_t size) {
ssize_t rc;
if (weaken(write)) {
if ((rc = weaken(write)(2, data, size)) != -1) {
return 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;
}
}
return LinuxWrite(2, data, size);
}
static ssize_t __asan_write_string(const char *s) {
return __asan_write(s, __asan_strlen(s));
}
static wontreturn void __asan_exit(int rc) {
if (weaken(_Exit)) {
weaken(_Exit)(rc);
} else {
LinuxExit(rc);
}
for (;;) asm("hlt");
}
static wontreturn void __asan_abort(void) {
if (weaken(__die)) weaken(__die)();
if (weaken(abort)) weaken(abort)();
__asan_exit(134);
}
@ -455,8 +472,6 @@ static wontreturn void __asan_report_heap_fault(void *addr, long c) {
char *p, ibuf[21], buf[256];
p = __asan_report_start(buf);
p = __asan_stpcpy(p, __asan_dscribe_heap_poison(c));
p = __asan_stpcpy(p, " ");
p = __asan_mempcpy(p, ibuf, __asan_int2str(c, ibuf));
p = __asan_stpcpy(p, " at 0x");
p = __asan_mempcpy(p, ibuf, __asan_int2hex((intptr_t)addr, ibuf, 48));
p = __asan_stpcpy(p, " shadow 0x");
@ -469,7 +484,7 @@ static wontreturn void __asan_report_memory_fault(uint8_t *addr, int size,
const char *kind) {
char *p, ibuf[21], buf[256];
p = __asan_report_start(buf);
p = __asan_stpcpy(p, __asan_describe_access_poison(*SHADOW(addr)));
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_stpcpy(p, "-byte ");
@ -525,6 +540,7 @@ static void *__asan_allocate(size_t a, size_t n, int underrun, int overrun) {
__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);
}
return p;
@ -637,7 +653,9 @@ void __asan_stack_free(char *p, size_t size, int classid) {
__asan_deallocate(p, kAsanStackFree);
}
void __asan_handle_no_return_impl(uintptr_t rsp) {
void __asan_handle_no_return(void) {
uintptr_t rsp;
rsp = (uintptr_t)__builtin_frame_address(0);
__asan_unpoison(rsp, ROUNDUP(rsp, STACKSIZE) - rsp);
}
@ -657,14 +675,22 @@ void __asan_unregister_globals(struct AsanGlobal g[], int n) {
}
}
void __asan_report_load_impl(uint8_t *addr, int size) {
void __asan_report_load(uint8_t *addr, int size) {
__asan_report_memory_fault(addr, size, "load");
}
void __asan_report_store_impl(uint8_t *addr, int size) {
void __asan_report_store(uint8_t *addr, int size) {
__asan_report_memory_fault(addr, size, "store");
}
void __asan_poison_stack_memory(uintptr_t addr, size_t size) {
__asan_poison(addr, size, kAsanStackFree);
}
void __asan_unpoison_stack_memory(uintptr_t addr, size_t size) {
__asan_unpoison(addr, size);
}
void __asan_alloca_poison(uintptr_t addr, size_t size) {
/* TODO(jart): Make sense of this function. */
/* __asan_poison(addr - 32, 32, kAsanAllocaUnderrun); */
@ -709,7 +735,9 @@ void __asan_map_shadow(uintptr_t p, size_t n) {
int i, x, a, b;
struct DirectMap sm;
struct MemoryIntervals *m;
if (0x7fff8000 <= p && p < 0x100080000000) {
if ((0x7fff8000 <= p && p < 0x100080000000) ||
(0x7fff8000 <= p + n && p + n < 0x100080000000) ||
(p < 0x7fff8000 && 0x100080000000 <= p + n)) {
__asan_die("asan error: mmap can't shadow a shadow\r\n");
}
m = weaken(_mmi);
@ -777,6 +805,10 @@ textstartup void __asan_init(int argc, char **argv, char **envp,
intptr_t *auxv) {
static bool once;
if (!cmpxchg(&once, false, true)) return;
if (IsWindows() && NtGetVersion() < kNtVersionWindows10) {
__asan_write_string("error: asan binaries require windows10\n");
__asan_exit(0); /* So `make MODE=dbg test` passes w/ Windows7 */
}
REQUIRE(_mmi);
REQUIRE(__mmap);
REQUIRE(MAP_ANONYMOUS);

View file

@ -25,7 +25,9 @@ LIBC_INTRIN_A_CHECKS = \
LIBC_INTRIN_A_DIRECTDEPS = \
LIBC_STUBS \
LIBC_NEXGEN32E
LIBC_SYSV \
LIBC_NEXGEN32E \
LIBC_NT_KERNEL32
LIBC_INTRIN_A_DEPS := \
$(call uniq,$(foreach x,$(LIBC_INTRIN_A_DIRECTDEPS),$($(x))))
@ -46,7 +48,8 @@ $(LIBC_INTRIN_A_OBJS): \
o/$(MODE)/libc/intrin/asan.o: \
OVERRIDE_CFLAGS += \
-mgeneral-regs-only
-mgeneral-regs-only \
-O2
LIBC_INTRIN_LIBS = $(foreach x,$(LIBC_INTRIN_ARTIFACTS),$($(x)))
LIBC_INTRIN_HDRS = $(foreach x,$(LIBC_INTRIN_ARTIFACTS),$($(x)_HDRS))

View file

@ -1,7 +1,7 @@
/*-*- 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,9 +16,9 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/math.h"
#include "libc/nexgen32e/nexgen32e.h"
#include "libc/nt/struct/teb.h"
#include "libc/runtime/runtime.h"
bool ctz(double x, double y) {
return __builtin_islessgreater(x, y);
textwindows noasan int NtGetVersion(void) {
return (NtGetPeb()->OSMajorVersion & 0xff) << 8 | NtGetPeb()->OSMinorVersion;
}

View file

@ -29,6 +29,6 @@
void(psrldq)(uint8_t b[16], const uint8_t a[16], unsigned long n) {
unsigned i;
if (n > 16) n = 16;
memcpy(b, a + n, 16 - n);
memset(b + (16 - n), 0, n);
__builtin_memcpy(b, a + n, 16 - n);
__builtin_memset(b + (16 - n), 0, n);
}

View file

@ -25,6 +25,18 @@
/ since ASAN has the same stylistic hugeness as UBSAN.
/ We also guard all the functions, against reentrancy.
.rodata.cst4
__asan_option_detect_stack_use_after_return:
.long 0
.endobj __asan_option_detect_stack_use_after_return,globl
.previous
.bss
__asan_noreentry:
.byte 0
.endobj __asan_noreentry
.previous
__asan_report_load1:
push $1
jmp OnReportLoad
@ -43,14 +55,18 @@ __asan_report_load8:
.endfn __asan_report_load8,globl
__asan_report_load16:
push $16
/ 𝑠𝑙𝑖𝑑𝑒
jmp OnReportLoad
.endfn __asan_report_load16,globl
__asan_report_load32:
push $32
/ 𝑠𝑙𝑖𝑑𝑒
.endfn __asan_report_load32,globl
OnReportLoad:
pop %rsi
/ 𝑠𝑙𝑖𝑑𝑒
.endfn OnReportLoad
__asan_report_load_n:
lea __asan_report_load_impl(%rip),%r11
lea __asan_report_load(%rip),%r11
jmp __asan_report_noreentry
.endfn __asan_report_load_n,globl
@ -83,7 +99,7 @@ ReportStore:
/ 𝑠𝑙𝑖𝑑𝑒
.endfn ReportStore
__asan_report_store_n:
lea __asan_report_store_impl(%rip),%r11
lea __asan_report_store(%rip),%r11
/ 𝑠𝑙𝑖𝑑𝑒
.endfn __asan_report_store_n,globl
@ -198,31 +214,6 @@ OnStackMalloc:
jmp __asan_stack_malloc
.endfn OnStackMalloc
__asan_handle_no_return:
push %rbp
mov %rsp,%rbp
lea 8(%rsp),%rdi
call __asan_handle_no_return_impl
pop %rbp
ret
.endfn __asan_handle_no_return,globl
__asan_before_dynamic_init:
push %rbp
mov %rsp,%rbp
ud2
pop %rbp
ret
.endfn __asan_before_dynamic_init,globl
__asan_after_dynamic_init:
push %rbp
mov %rsp,%rbp
ud2
pop %rbp
ret
.endfn __asan_after_dynamic_init,globl
__asan_version_mismatch_check_v8:
ret
.endfn __asan_version_mismatch_check_v8,globl
@ -240,14 +231,76 @@ __asan_version_mismatch_check_v8:
pop %rdi
.init.end 301,_init_asan
.rodata.cst4
__asan_option_detect_stack_use_after_return:
.long 0
.endobj __asan_option_detect_stack_use_after_return,globl
.previous
__asan_before_dynamic_init:
push %rbp
mov %rsp,%rbp
ud2
.endfn __asan_before_dynamic_init,globl
.bss
__asan_noreentry:
.byte 0
.endobj __asan_noreentry
.previous
__asan_after_dynamic_init:
push %rbp
mov %rsp,%rbp
ud2
.endfn __asan_after_dynamic_init,globl
__asan_load1:
push %rbp
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
ud2
.endfn __asan_load32,globl
__asan_store1:
push %rbp
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
ud2
.endfn __asan_store32,globl

View file

@ -4,6 +4,7 @@
PKGS += LIBC
LIBC_HDRS = $(filter %.h,$(LIBC_FILES))
LIBC_INCS = $(filter %.inc,$(LIBC_FILES))
LIBC_FILES := $(wildcard libc/*)
LIBC_CHECKS = $(LIBC_HDRS:%=o/$(MODE)/%.ok)

View file

@ -48,7 +48,6 @@ static int PrintBacktraceUsingAddr2line(int fd, const struct StackFrame *bp) {
struct Garbages *garbage;
sigset_t chldmask, savemask;
const struct StackFrame *frame;
struct sigaction ignore, saveint, savequit;
const char *debugbin, *p1, *p2, *p3, *addr2line;
char buf[kBacktraceBufSize], *argv[kBacktraceMaxFrames];
if (IsOpenbsd()) return -1;
@ -77,18 +76,11 @@ static int PrintBacktraceUsingAddr2line(int fd, const struct StackFrame *bp) {
j += uint64toarray_radix16(addr - 1, buf + j) + 1;
}
argv[i++] = NULL;
ignore.sa_flags = 0;
ignore.sa_handler = SIG_IGN;
sigemptyset(&ignore.sa_mask);
sigaction(SIGINT, &ignore, &saveint);
sigaction(SIGQUIT, &ignore, &savequit);
sigemptyset(&chldmask);
sigaddset(&chldmask, SIGCHLD);
sigprocmask(SIG_BLOCK, &chldmask, &savemask);
pipe(pipefds);
if (!(pid = vfork())) {
sigaction(SIGINT, &saveint, NULL);
sigaction(SIGQUIT, &savequit, NULL);
sigprocmask(SIG_SETMASK, &savemask, NULL);
dup2(pipefds[1], 1);
close(pipefds[0]);
@ -124,8 +116,6 @@ static int PrintBacktraceUsingAddr2line(int fd, const struct StackFrame *bp) {
if (errno == EINTR) continue;
return -1;
}
sigaction(SIGINT, &saveint, NULL);
sigaction(SIGQUIT, &savequit, NULL);
sigprocmask(SIG_SETMASK, &savemask, NULL);
if (WIFEXITED(ws) && !WEXITSTATUS(ws)) {
return 0;

View file

@ -25,19 +25,30 @@
/**
* Finds full executable path in overridable way.
*
* This is a higher level version of the commandv() function. Programs
* that spawn subprocesses can use this function to determine the path
* at startup.
*
* @param var is environment variable which may be used to override
* PATH search, and it can force a NULL result if it's empty
* @param cmd is name of program, which is returned asap if it's an
* absolute path
* @return pointer to exe path string, or NULL if it couldn't be found
* or the environment variable was empty; noting that the caller
* should copy this string before saving it
*/
nodiscard char *commandvenv(const char *var, const char *cmd) {
const char *commandvenv(const char *var, const char *cmd) {
const char *exepath;
char pathbuf[PATH_MAX];
static char pathbuf[PATH_MAX];
if (*cmd == '/' || *cmd == '\\') return cmd;
if ((exepath = getenv(var))) {
if (!isempty(exepath) && access(exepath, X_OK) != -1) {
return strdup(exepath);
if (isempty(exepath)) return NULL;
if (access(exepath, X_OK) != -1) {
return exepath;
} else {
return NULL;
}
} else if ((exepath = commandv(cmd, pathbuf))) {
return strdup(exepath);
} else {
return NULL;
}
return commandv(cmd, pathbuf);
}

View file

@ -40,7 +40,7 @@ void memsummary(int); /* light version of same thing */
uint16_t getttycols(uint16_t);
int getttysize(int, struct winsize *) paramsnonnull();
bool IsTerminalInarticulate(void) nosideeffect;
char *commandvenv(const char *, const char *) nodiscard;
const char *commandvenv(const char *, const char *);
const char *GetAddr2linePath(void);
const char *GetGdbPath(void);

View file

@ -28,7 +28,6 @@ LIBC_LOG_A_CHECKS = \
LIBC_LOG_A_DIRECTDEPS = \
LIBC_ALG \
LIBC_CALLS \
LIBC_CALLS_HEFTY \
LIBC_ELF \
LIBC_FMT \
LIBC_INTRIN \

View file

@ -17,9 +17,11 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/fmt/itoa.h"
#include "libc/log/color.internal.h"
#include "libc/log/internal.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/fileno.h"
/**
@ -29,6 +31,18 @@
* @see __start_fatal_ndebug()
*/
relegated void __start_fatal(const char *file, int line) {
dprintf(STDERR_FILENO, "%s%s%s%s:%s:%d:%s%s: ", CLS, RED, "error", BLUE1,
file, line, program_invocation_short_name, RESET);
char s[16 + 16 + 16 + 16 + PATH_MAX + 16 + NAME_MAX + 16], *p;
p = stpcpy(s, CLS);
p = stpcpy(p, RED);
p = stpcpy(p, "error");
p = stpcpy(p, BLUE1);
p = stpcpy(p, ":");
p = stpcpy(p, file);
p = stpcpy(p, ":");
p += int64toarray_radix10(line, p);
p = stpcpy(p, ":");
p = stpcpy(p, program_invocation_short_name);
p = stpcpy(p, RESET);
p = stpcpy(p, ": ");
write(2, s, p - s);
}

View file

@ -33,6 +33,9 @@
.macro .text.exit
.section .text.exit,"ax",@progbits
.endm
.macro .text.syscall
.section .text.syscall,"ax",@progbits
.endm
.macro .firstclass
.section .text.hot,"ax",@progbits
.endm

View file

@ -18,8 +18,8 @@
*/
#include "libc/macros.h"
/ Half size of level 3 cache in bytes.
.initbss 202,_init_kHalfCache3
/ Half size of level 3 cache in bytes.
kHalfCache3:
.quad 0
.endobj kHalfCache3,globl

View file

@ -3,6 +3,8 @@
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
extern long kHalfCache3;
void imapxlatab(void *);
void insertionsort(int32_t *, size_t);

View file

@ -8,6 +8,7 @@ LIBC_NEXGEN32E = $(LIBC_NEXGEN32E_A_DEPS) $(LIBC_NEXGEN32E_A)
LIBC_NEXGEN32E_A = o/$(MODE)/libc/nexgen32e/nexgen32e.a
LIBC_NEXGEN32E_A_FILES := $(wildcard libc/nexgen32e/*)
LIBC_NEXGEN32E_A_HDRS = $(filter %.h,$(LIBC_NEXGEN32E_A_FILES))
LIBC_NEXGEN32E_A_INCS = $(filter %.inc,$(LIBC_NEXGEN32E_A_FILES))
LIBC_NEXGEN32E_A_SRCS_A = $(filter %.s,$(LIBC_NEXGEN32E_A_FILES))
LIBC_NEXGEN32E_A_SRCS_S = $(filter %.S,$(LIBC_NEXGEN32E_A_FILES))
LIBC_NEXGEN32E_A_SRCS_C = $(filter %.c,$(LIBC_NEXGEN32E_A_FILES))
@ -49,6 +50,7 @@ o/$(MODE)/libc/nexgen32e/tinystrncmp.ncabi.o: \
LIBC_NEXGEN32E_LIBS = $(foreach x,$(LIBC_NEXGEN32E_ARTIFACTS),$($(x)))
LIBC_NEXGEN32E_SRCS = $(foreach x,$(LIBC_NEXGEN32E_ARTIFACTS),$($(x)_SRCS))
LIBC_NEXGEN32E_HDRS = $(foreach x,$(LIBC_NEXGEN32E_ARTIFACTS),$($(x)_HDRS))
LIBC_NEXGEN32E_INCS = $(foreach x,$(LIBC_NEXGEN32E_ARTIFACTS),$($(x)_INCS))
LIBC_NEXGEN32E_CHECKS = $(foreach x,$(LIBC_NEXGEN32E_ARTIFACTS),$($(x)_CHECKS))
LIBC_NEXGEN32E_OBJS = $(foreach x,$(LIBC_NEXGEN32E_ARTIFACTS),$($(x)_OBJS))
$(LIBC_NEXGEN32E_OBJS): $(BUILD_FILES) libc/nexgen32e/nexgen32e.mk

View file

@ -1,100 +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/nexgen32e/macros.h"
#include "libc/nexgen32e/x86feature.h"
#include "libc/macros.h"
/ Mutates string to uppercase roman characters.
/
/ @param RDI points to non-const NUL-terminated string
/ @return RAX will be original RDI
/ @note 10x faster than C
strtoupper:
mov $'A-'a,%edx # adding this uppers
mov $'a|'z<<8,%ecx # uint8_t range a..z
jmp strcaseconv
.endfn strtoupper,globl
/ Mutates string to lowercase roman characters.
/
/ @param RDI points to non-const NUL-terminated string
/ @return RAX will be original RDI
/ @note 10x faster than C
strtolower:
mov $'a-'A,%edx # adding this lowers
mov $'A|'Z<<8,%ecx # uint8_t range A..Z
/ 𝑠𝑙𝑖𝑑𝑒
.endfn strtolower,globl
/ Support code for strtolower() and strtoupper().
/
/ @param RDI points to non-const NUL-terminated string
/ @param CL defines start of character range to mutate
/ @param CH defines end of character range to mutate
/ @param DL is added to each DIL ∈ [CL,CH]
/ @return RAX will be original RDI
strcaseconv:
.leafprologue
.profilable
mov %rdi,%rsi
0: testb $15,%sil # is it aligned?
#if X86_NEED(SSE4_2)
jz .Lsse4
#else
jnz 1f
testb X86_HAVE(SSE4_2)+kCpuids(%rip)
jnz .Lsse4 # is it nehalem?
#endif
1: lodsb # AL = *RSI++
test %al,%al # is it NUL?
jz 3f
cmp %cl,%al # is it in range?
jb 0b
cmp %ch,%al
ja 0b
add %dl,-1(%rsi)
jmp 0b
.Lsse4: movd %ecx,%xmm1 # XMM1 = ['A,'Z,0,0,...]
movd %edx,%xmm2 # XMM2 = ['a-'A,'a-'A,...]
pbroadcastb %xmm2
xor %ecx,%ecx
2: movdqa (%rsi,%rcx),%xmm3
/ 0:index of the LEAST significant, set, bit is used
/ regardless of corresponding input element validity
/ intres2 is returned in least significant bits of xmm0
/ 1:index of the MOST significant, set, bit is used
/ regardless of corresponding input element validity
/ each bit of intres2 is expanded to byte/word
/ 0:negation of intres1 is for all 16 (8) bits
/ 1:negation of intres1 is masked by reg/mem validity
/ intres1 is negated (1s complement)
/ mode{equalany,ranges,equaleach,equalordered}
/ issigned
/ is16bit
/ u
pcmpistrm $0b01000100,%xmm3,%xmm1 # XMM0 8-bit byte mask
pand %xmm2,%xmm0 # won't mask after NUL
paddb %xmm0,%xmm3
movdqa %xmm3,(%rsi,%rcx)
lea 16(%rcx),%rcx
jnz 2b # PCMPISTRM found NUL
3: mov %rdi,%rax
.leafepilogue
.endfn strcaseconv
.source __FILE__

View file

@ -21,71 +21,6 @@
#include "libc/macros.h"
.source __FILE__
/ Returns pointer to first instance of character.
/
/ @param rdi is a non-null NUL-terminated string pointer
/ @param esi is the search byte
/ @return rax points to character, or to NUL byte if not found
/ @note this won't return NULL if search character is NUL
strchrnul:
.leafprologue
.profilable
or $-1,%r9
jmp 0f
.endfn strchrnul,globl
/ Returns pointer to first instance of character, the BSD way.
/
/ @param rdi is a non-null NUL-terminated string pointer
/ @param esi is the search byte
/ @return rax points to first result, or NULL if not found
/ @note this won't return NULL if search character is NUL
index: nop
/ 𝑠𝑙𝑖𝑑𝑒
.endfn index,globl
/ Returns pointer to first instance of character.
/
/ @param rdi is a non-null NUL-terminated string pointer
/ @param esi is the search byte
/ @return rax points to first result, or NULL if not found
/ @note this won't return NULL if search character is NUL
/ @asyncsignalsafe
strchr: .leafprologue
.profilable
xor %r9d,%r9d
0: movzbl %sil,%edx
or $-1,%rsi
xor %r8,%r8
jmp strsak
.endfn strchr,globl
/ Returns pointer to first instance of character in range.
/
/ @param rdi is a non-null pointer to memory
/ @param esi is the search byte
/ @return rax points to byte if found, or else undefined behavior
rawmemchr:
or $-1,%rdx
/ 𝑠𝑙𝑖𝑑𝑒
.endfn rawmemchr,globl
/ Returns pointer to first instance of character in range.
/
/ @param rdi is a non-null pointer to memory
/ @param esi is the search byte
/ @param rdx is length of memory in bytes
/ @return rax points to byte if found or NULL
/ @asyncsignalsafe
memchr: .leafprologue
.profilable
xchg %rsi,%rdx
mov %dl,%dh
xor %r8,%r8
xor %r10,%r10
jmp strsak
.endfn memchr,globl
/ Returns length of NUL-terminated string w/ security blankets.
/
/ This is like strnlen() except it'll return 0 if (1) RDI is NULL
@ -102,24 +37,13 @@ strnlen_s:
test %rdi,%rdi
jnz 0f
.leafepilogue
.endfn strnlen_s,globl
/ Returns length of NUL-terminated memory, with limit.
/
/ @param rdi is non-null memory
/ @param rsi is the maximum number of bytes to consider
/ @return rax is the number of bytes, excluding the NUL
/ @asyncsignalsafe
strnlen:.leafprologue
.profilable
or $-1,%r10
0: xor %edx,%edx
mov %rdi,%r8
/ 𝑠𝑙𝑖𝑑𝑒
.endfn strnlen,globl
.endfn strnlen_s,globl
/ Swiss army knife of string character scanning.
/ Fourteen fast functions in one.
/ Used to be fourteen fast functions in one.
/
/ @param rdi is non-null string memory
/ @param rsi is max number of bytes to consider

View file

@ -5,6 +5,7 @@ PKGS += LIBC_NT
LIBC_NT_LIBS = $(foreach x,$(LIBC_NT_ARTIFACTS),$($(x)))
LIBC_NT_HDRS = $(foreach x,$(LIBC_NT_ARTIFACTS),$($(x)_HDRS))
LIBC_NT_INCS = $(foreach x,$(LIBC_NT_ARTIFACTS),$($(x)_INCS))
LIBC_NT_SRCS = $(foreach x,$(LIBC_NT_ARTIFACTS),$($(x)_SRCS))
LIBC_NT_OBJS = $(foreach x,$(LIBC_NT_ARTIFACTS),$($(x)_OBJS))
LIBC_NT_CHECKS = $(foreach x,$(LIBC_NT_ARTIFACTS),$($(x)_CHECKS))
@ -22,9 +23,8 @@ LIBC_NT_A_FILES := \
$(wildcard libc/nt/nt/*.*) \
$(wildcard libc/nt/*)
LIBC_NT_A_HDRS = \
$(filter %.h,$(LIBC_NT_A_FILES))
LIBC_NT_A_HDRS = $(filter %.h,$(LIBC_NT_A_FILES))
LIBC_NT_A_INCS = $(filter %.inc,$(LIBC_NT_A_FILES))
LIBC_NT_A_CHECKS = $(patsubst %,o/$(MODE)/%.ok,$(filter %.h,$(LIBC_NT_A_HDRS)))
#───────────────────────────────────────────────────────────────────────────────

View file

@ -4,14 +4,15 @@
#include "libc/nt/struct/peb.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
/* These macros address directly into NT's TEB a.k.a. TIB */
#define NtGetPeb() gs((struct NtPeb **)(0x60ULL))
#define NtGetTeb() gs((void **)(0x30)) /* %gs:0 linear address */
#define NtGetPid() gs((uint32_t *)(0x40)) /* GetCurrentProcessId() */
#define NtGetTid() gs((uint32_t *)(0x48)) /* GetCurrentThreadId() */
#define NtGetErr() gs((int *)(0x68))
#define NtGetVersion() \
((NtGetPeb()->OSMajorVersion & 0xff) << 8 | NtGetPeb()->OSMinorVersion)
/*
* These macros address directly into NT's TEB a.k.a. TIB
* Any function that does this needs the `noasan` keyword
*/
#define NtGetPeb() gs((struct NtPeb **)(0x60ULL))
#define NtGetTeb() gs((void **)(0x30)) /* %gs:0 linear address */
#define NtGetPid() gs((uint32_t *)(0x40)) /* GetCurrentProcessId() */
#define NtGetTid() gs((uint32_t *)(0x48)) /* GetCurrentThreadId() */
#define NtGetErr() gs((int *)(0x68))
#define _NtGetSeh() gs((void **)(0x00))
#define _NtGetStackHigh() gs((void **)(0x08))
#define _NtGetStackLow() gs((void **)(0x10))

View file

@ -24,14 +24,14 @@ LIBC_RAND_A_CHECKS = \
$(LIBC_RAND_A_HDRS:%=o/$(MODE)/%.ok)
LIBC_RAND_A_DIRECTDEPS = \
LIBC_STUBS \
LIBC_INTRIN \
LIBC_TINYMATH \
LIBC_CALLS \
LIBC_NEXGEN32E \
LIBC_NT_KERNEL32 \
LIBC_STR \
LIBC_STUBS \
LIBC_SYSV \
LIBC_SYSV_CALLS \
LIBC_SYSV
LIBC_TINYMATH
LIBC_RAND_A_DEPS := \
$(call uniq,$(foreach x,$(LIBC_RAND_A_DIRECTDEPS),$($(x))))

View file

@ -33,7 +33,7 @@ hidden extern uint64_t g_rando64;
*
* @see rngset()
*/
nodebuginfo uint64_t(rand64)(void) {
nodebuginfo uint64_t rand64(void) {
uint64_t res;
if (X86_HAVE(RDRND)) {
res = rdrand();

View file

@ -16,11 +16,11 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/nexgen32e/rdtsc.h"
#include "libc/nt/dll.h"
#include "libc/nt/events.h"
#include "libc/nt/struct/point.h"
#include "libc/nt/struct/teb.h"
#include "libc/rand/rand.h"
/**
@ -29,7 +29,7 @@
textwindows int64_t winrandish(void) {
int64_t res;
struct NtPoint point;
res = ((int64_t)NtGetPid() << 17) ^ NtGetTid() ^ rdtsc();
res = ((int64_t)getpid() << 17) ^ gettid() ^ rdtsc();
/*
* This function is intended for older CPUs built before 2012, so
* let's avoid having our CUI apps yoink USER32.DLL until we're

View file

@ -21,7 +21,7 @@
#include "libc/sysv/consts/sig.h"
#include "libc/sysv/consts/nr.h"
#include "libc/macros.h"
.real
.text.syscall
.source __FILE__
/ Terminates program abnormally.

View file

@ -95,7 +95,7 @@ static int arch_prctl$freebsd(int code, int64_t addr) {
}
}
static int arch_prctl$xnu(int code, int64_t addr) {
static textsyscall int arch_prctl$xnu(int code, int64_t addr) {
int ax;
switch (code) {
case ARCH_SET_GS:
@ -113,7 +113,7 @@ static int arch_prctl$xnu(int code, int64_t addr) {
}
}
static int arch_prctl$openbsd(int code, int64_t addr) {
static textsyscall int arch_prctl$openbsd(int code, int64_t addr) {
int64_t rax;
switch (code) {
case ARCH_GET_FS:

View file

@ -19,7 +19,7 @@
#include "libc/runtime/memtrack.h"
#include "libc/runtime/runtime.h"
bool AreMemoryIntervalsOk(const struct MemoryIntervals *mm) {
noasan bool AreMemoryIntervalsOk(const struct MemoryIntervals *mm) {
int i;
for (i = 0; i < mm->i; ++i) {
if (mm->p[i].y < mm->p[i].x) return false;

View file

@ -17,38 +17,83 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/bits/bits.h"
#include "libc/bits/weaken.h"
#include "libc/calls/calls.h"
#include "libc/dce.h"
#include "libc/log/log.h"
#include "libc/macros.h"
#include "libc/mem/alloca.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/fileno.h"
#include "libc/nt/runtime.h"
#include "libc/sysv/consts/nr.h"
static noasan size_t __assert_strlen(const char *s) {
size_t i = 0;
while (s[i]) ++i;
return i;
}
static noasan char *__assert_stpcpy(char *d, const char *s) {
size_t i;
for (i = 0;; ++i) {
if (!(d[i] = s[i])) {
return d + i;
}
}
}
static textsyscall noasan wontreturn void __assert_exit(int rc) {
if (!IsWindows()) {
asm volatile("syscall"
: /* no outputs */
: "a"(__NR_exit_group), "D"(rc)
: "memory");
unreachable;
} else {
ExitProcess(rc);
}
}
static textsyscall noasan ssize_t __assert_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;
}
}
}
/**
* Handles failure of assert() macro.
*/
relegated void __assert_fail(const char *expr, const char *file, int line) {
relegated wontreturn noasan void __assert_fail(const char *expr,
const char *file, int line) {
static bool once;
char *msg, *p, linebuf[16];
unsigned i, exprlen, filelen;
if (!once) {
once = true;
exprlen = expr ? strlen(expr) : 0;
filelen = file ? strlen(file) : 0;
if (cmpxchg(&once, false, true)) {
exprlen = expr ? __assert_strlen(expr) : 0;
filelen = file ? __assert_strlen(file) : 0;
p = msg = alloca(MIN(512, exprlen + filelen + 64));
p = mempcpy(p, file, filelen);
p = stpcpy(p, ":");
p = __assert_stpcpy(p, file);
p = __assert_stpcpy(p, ":");
if (line < 1) line = 1;
for (i = 0; line; line /= 10) linebuf[i++] = '0' + line % 10;
while (i) *p++ = linebuf[--i];
p = stpcpy(p, ":");
p = mempcpy(p, expr, exprlen);
p = stpcpy(p, "\r\n");
write(STDERR_FILENO, msg, p - msg);
p = __assert_stpcpy(p, ":");
p = __assert_stpcpy(p, expr);
p = __assert_stpcpy(p, "\r\n");
__assert_write(msg, p - msg);
if (weaken(__die)) weaken(__die)();
}
abort();
unreachable;
__assert_exit(23);
}

View file

@ -51,7 +51,7 @@ static struct CxaAtexitBlocks {
* @return 0 on success or nonzero w/ errno
* @note folks have forked libc in past just to unbloat atexit()
*/
int __cxa_atexit(void *fp, void *arg, void *pred) {
noasan int __cxa_atexit(void *fp, void *arg, void *pred) {
unsigned i;
struct CxaAtexitBlock *b, *b2;
b = __cxa_blocks.p;
@ -83,7 +83,7 @@ int __cxa_atexit(void *fp, void *arg, void *pred) {
*
* @param pred can be null to match all
*/
void __cxa_finalize(void *pred) {
noasan void __cxa_finalize(void *pred) {
unsigned i;
unsigned long mask;
struct CxaAtexitBlock *b, *b2;

View file

@ -28,8 +28,8 @@
* bypassed by calling this function. However the caller is responsible
* for passing the magic memory handle on Windows NT to CloseHandle().
*/
struct DirectMap __mmap(void *addr, size_t size, unsigned prot, unsigned flags,
int fd, int64_t off) {
noasan struct DirectMap __mmap(void *addr, size_t size, unsigned prot,
unsigned flags, int fd, int64_t off) {
if (!IsWindows()) {
return (struct DirectMap){mmap$sysv(addr, size, prot, flags, fd, off),
kNtInvalidHandleValue};

View file

@ -16,6 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/nt/enum/filemapflags.h"
#include "libc/nt/enum/pageflags.h"
@ -24,13 +25,15 @@
#include "libc/runtime/directmap.h"
#include "libc/sysv/consts/prot.h"
textwindows struct DirectMap __mmap$nt(void *addr, size_t size, unsigned prot,
int64_t handle, int64_t off) {
textwindows noasan struct DirectMap __mmap$nt(void *addr, size_t size,
unsigned prot, int64_t handle,
int64_t off) {
struct DirectMap dm;
if ((dm.maphandle = CreateFileMappingNuma(
handle, &kNtIsInheritable,
(prot & PROT_WRITE) ? kNtPageExecuteReadwrite : kNtPageExecuteRead,
size >> 32, size, NULL, kNtNumaNoPreferredNode))) {
handle != -1 ? 0 : size >> 32, handle != -1 ? 0 : size, NULL,
kNtNumaNoPreferredNode))) {
if (!(dm.addr = MapViewOfFileExNuma(
dm.maphandle,
(prot & PROT_WRITE)

View file

@ -19,7 +19,7 @@
#include "libc/dce.h"
#include "libc/runtime/internal.h"
#include "libc/macros.h"
.privileged
.text.syscall
.source __FILE__
/ Terminates process, ignoring destructors and atexit() handlers.

View file

@ -18,7 +18,7 @@
*/
#include "libc/runtime/memtrack.h"
unsigned FindMemoryInterval(const struct MemoryIntervals *mm, int x) {
noasan unsigned FindMemoryInterval(const struct MemoryIntervals *mm, int x) {
unsigned l, m, r;
l = 0;
r = mm->i;

View file

@ -46,17 +46,18 @@
#include "libc/sysv/consts/sig.h"
#include "libc/sysv/errfuns.h"
static textwindows int64_t ParseInt(char16_t **p) {
uint64_t x = 0;
while ('0' <= **p && **p <= '9') {
x *= 10;
x += *(*p)++ - '0';
static textwindows noasan char16_t *ParseInt(char16_t *p, int64_t *x) {
*x = 0;
while (*p == ' ') p++;
while ('0' <= *p && *p <= '9') {
*x *= 10;
*x += *p++ - '0';
}
return x;
return p;
}
static noinline textwindows void ForkIo(int64_t h, void *buf, size_t n,
bool32 (*f)()) {
static noinline textwindows noasan void ForkIo(int64_t h, void *buf, size_t n,
bool32 (*f)()) {
char *p;
size_t i;
uint32_t x;
@ -65,41 +66,39 @@ static noinline textwindows void ForkIo(int64_t h, void *buf, size_t n,
}
}
static noinline textwindows void WriteAll(int64_t h, void *buf, size_t n) {
static noinline textwindows noasan void WriteAll(int64_t h, void *buf,
size_t n) {
ForkIo(h, buf, n, WriteFile);
}
static noinline textwindows void ReadAll(int64_t h, void *buf, size_t n) {
static textwindows noinline noasan void ReadAll(int64_t h, void *buf,
size_t n) {
ForkIo(h, buf, n, ReadFile);
}
textwindows void WinMainForked(void) {
int64_t h;
textwindows noasan void WinMainForked(void) {
void *addr;
jmp_buf jb;
char16_t *p;
uint64_t size;
uint32_t i, varlen;
struct DirectMap dm;
int64_t reader, writer;
char16_t var[21 + 1 + 21 + 1];
varlen = GetEnvironmentVariable(u"_FORK", var, ARRAYLEN(var));
if (!varlen) return;
if (varlen >= ARRAYLEN(var)) ExitProcess(123);
SetEnvironmentVariable(u"_FORK", NULL);
if (!varlen || varlen >= ARRAYLEN(var)) return;
p = var;
h = ParseInt(&p);
if (*p++ == ' ') CloseHandle(ParseInt(&p));
ReadAll(h, jb, sizeof(jb));
ReadAll(h, &_mmi.i, sizeof(_mmi.i));
ParseInt(ParseInt(var, &reader), &writer);
ReadAll(reader, jb, sizeof(jb));
ReadAll(reader, &_mmi.i, sizeof(_mmi.i));
for (i = 0; i < _mmi.i; ++i) {
ReadAll(h, &_mmi.p[i], sizeof(_mmi.p[i]));
ReadAll(reader, &_mmi.p[i], sizeof(_mmi.p[i]));
addr = (void *)((uint64_t)_mmi.p[i].x << 16);
size = ((uint64_t)(_mmi.p[i].y - _mmi.p[i].x) << 16) + FRAMESIZE;
if (_mmi.p[i].flags & MAP_PRIVATE) {
CloseHandle(_mmi.p[i].h);
_mmi.p[i].h =
__mmap$nt(addr, size, PROT_READ | PROT_WRITE | PROT_EXEC, -1, 0)
.maphandle;
ReadAll(h, addr, size);
_mmi.p[i].h = __mmap$nt(addr, size, _mmi.p[i].prot, -1, 0).maphandle;
ReadAll(reader, addr, size);
} else {
MapViewOfFileExNuma(
_mmi.p[i].h,
@ -109,9 +108,9 @@ textwindows void WinMainForked(void) {
0, 0, size, addr, kNtNumaNoPreferredNode);
}
}
ReadAll(h, _edata, _end - _edata);
CloseHandle(h);
unsetenv("_FORK");
ReadAll(reader, _edata, _end - _edata);
CloseHandle(reader);
CloseHandle(writer);
if (weaken(__wincrash$nt)) {
AddVectoredExceptionHandler(1, (void *)weaken(__wincrash$nt));
}
@ -120,20 +119,19 @@ textwindows void WinMainForked(void) {
textwindows int fork$nt(void) {
jmp_buf jb;
int i, rc, pid;
char exe[PATH_MAX];
int64_t reader, writer;
char *p, buf[21 + 1 + 21 + 1];
int i, rc, pid, releaseme;
char *p, forkvar[6 + 21 + 1 + 21 + 1];
struct NtStartupInfo startinfo;
struct NtProcessInformation procinfo;
if ((pid = __getemptyfd()) == -1) return -1;
if ((pid = releaseme = __reservefd()) == -1) return -1;
if (!setjmp(jb)) {
if (CreatePipe(&reader, &writer, &kNtIsInheritable, 0)) {
p = buf;
p = stpcpy(forkvar, "_FORK=");
p += uint64toarray_radix10(reader, p);
*p++ = ' ';
p += uint64toarray_radix10(writer, p);
setenv("_FORK", buf, true);
memset(&startinfo, 0, sizeof(startinfo));
startinfo.cb = sizeof(struct NtStartupInfo);
startinfo.dwFlags = kNtStartfUsestdhandles;
@ -141,8 +139,8 @@ textwindows int fork$nt(void) {
startinfo.hStdOutput = g_fds.p[1].handle;
startinfo.hStdError = g_fds.p[2].handle;
GetModuleFileNameA(0, exe, ARRAYLEN(exe));
if (ntspawn(exe, g_argv, environ, &kNtIsInheritable, NULL, true, 0, NULL,
&startinfo, &procinfo) != -1) {
if (ntspawn(exe, g_argv, environ, forkvar, &kNtIsInheritable, NULL, true,
0, NULL, &startinfo, &procinfo) != -1) {
CloseHandle(reader);
CloseHandle(procinfo.hThread);
if (weaken(__sighandrvas) &&
@ -152,6 +150,7 @@ textwindows int fork$nt(void) {
g_fds.p[pid].kind = kFdProcess;
g_fds.p[pid].handle = procinfo.hProcess;
g_fds.p[pid].flags = O_CLOEXEC;
releaseme = -1;
}
WriteAll(writer, jb, sizeof(jb));
WriteAll(writer, &_mmi.i, sizeof(_mmi.i));
@ -167,7 +166,6 @@ textwindows int fork$nt(void) {
} else {
rc = -1;
}
unsetenv("_FORK");
rc = pid;
} else {
rc = __winerr();
@ -175,5 +173,8 @@ textwindows int fork$nt(void) {
} else {
rc = 0;
}
if (releaseme != -1) {
__releasefd(releaseme);
}
return rc;
}

View file

@ -32,7 +32,7 @@ struct DosArgv {
wint_t wc;
};
static textwindows wint_t DecodeDosArgv(const char16_t **s) {
static textwindows noasan wint_t DecodeDosArgv(const char16_t **s) {
wint_t x, y;
for (;;) {
if (!(x = *(*s)++)) break;
@ -50,7 +50,7 @@ static textwindows wint_t DecodeDosArgv(const char16_t **s) {
return x;
}
static textwindows void AppendDosArgv(struct DosArgv *st, wint_t wc) {
static textwindows noasan void AppendDosArgv(struct DosArgv *st, wint_t wc) {
uint64_t w;
w = tpenc(wc);
do {
@ -78,8 +78,8 @@ static textwindows void AppendDosArgv(struct DosArgv *st, wint_t wc) {
* @see libc/runtime/ntspawn.c
* @note kudos to Simon Tatham for figuring out quoting behavior
*/
textwindows int GetDosArgv(const char16_t *cmdline, char *buf, size_t size,
char **argv, size_t max) {
textwindows noasan int GetDosArgv(const char16_t *cmdline, char *buf,
size_t size, char **argv, size_t max) {
bool inquote;
size_t i, argc, slashes, quotes;
struct DosArgv st;

View file

@ -18,6 +18,30 @@
*/
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/str/tpenc.h"
#include "libc/str/utf16.h"
static textwindows noasan axdx_t Recode16to8(char *dst, size_t dstsize,
const char16_t *src) {
axdx_t r;
uint64_t w;
wint_t x, y;
for (r.ax = 0, r.dx = 0;;) {
if (!(x = src[r.dx++])) break;
if (IsUtf16Cont(x)) continue;
if (!IsUcs2(x)) {
if (!(y = src[r.dx++])) break;
x = MergeUtf16(x, y);
}
for (w = tpenc(x); w && r.ax + 1 < dstsize; w >>= 8) {
dst[r.ax++] = w & 0xFF;
}
}
if (r.ax < dstsize) {
dst[r.ax] = 0;
}
return r;
}
/**
* Transcodes NT environment variable block from UTF-16 to UTF-8.
@ -29,8 +53,8 @@
* @param max is the pointer count capacity of envp
* @return number of variables decoded, excluding NULL-terminator
*/
textwindows int GetDosEnviron(const char16_t *env, char *buf, size_t size,
char **envp, size_t max) {
textwindows noasan int GetDosEnviron(const char16_t *env, char *buf,
size_t size, char **envp, size_t max) {
int i;
axdx_t r;
i = 0;
@ -38,7 +62,7 @@ textwindows int GetDosEnviron(const char16_t *env, char *buf, size_t size,
--size;
while (*env) {
if (i + 1 < max) envp[i++] = buf;
r = tprecode16to8(buf, size, env);
r = Recode16to8(buf, size, env);
size -= r.ax + 1;
buf += r.ax + 1;
env += r.dx;

View file

@ -24,7 +24,8 @@
#include "libc/str/str.h"
#include "libc/sysv/errfuns.h"
static void RemoveMemoryIntervals(struct MemoryIntervals *mm, int i, int n) {
static noasan void RemoveMemoryIntervals(struct MemoryIntervals *mm, int i,
int n) {
assert(i >= 0);
assert(i + n <= mm->i);
memcpy(mm->p + i, mm->p + i + n,
@ -32,7 +33,7 @@ static void RemoveMemoryIntervals(struct MemoryIntervals *mm, int i, int n) {
mm->i -= n;
}
static void CreateMemoryInterval(struct MemoryIntervals *mm, int i) {
static noasan void CreateMemoryInterval(struct MemoryIntervals *mm, int i) {
assert(i >= 0);
assert(i <= mm->i);
assert(mm->i < ARRAYLEN(mm->p));
@ -41,7 +42,7 @@ static void CreateMemoryInterval(struct MemoryIntervals *mm, int i) {
++mm->i;
}
static int PunchHole(struct MemoryIntervals *mm, int x, int y, int i) {
static noasan int PunchHole(struct MemoryIntervals *mm, int x, int y, int i) {
if (mm->i == ARRAYLEN(mm->p)) return enomem();
CreateMemoryInterval(mm, i);
mm->p[i].y = x - 1;
@ -49,8 +50,8 @@ static int PunchHole(struct MemoryIntervals *mm, int x, int y, int i) {
return 0;
}
int ReleaseMemoryIntervals(struct MemoryIntervals *mm, int x, int y,
void wincb(struct MemoryIntervals *, int, int)) {
noasan int ReleaseMemoryIntervals(struct MemoryIntervals *mm, int x, int y,
void wf(struct MemoryIntervals *, int, int)) {
unsigned l, r;
assert(y >= x);
assert(AreMemoryIntervalsOk(mm));
@ -81,16 +82,16 @@ int ReleaseMemoryIntervals(struct MemoryIntervals *mm, int x, int y,
--r;
}
if (l <= r) {
if (IsWindows() && wincb) {
wincb(mm, l, r);
if (IsWindows() && wf) {
wf(mm, l, r);
}
RemoveMemoryIntervals(mm, l, r - l + 1);
}
return 0;
}
int TrackMemoryInterval(struct MemoryIntervals *mm, int x, int y, long h,
int prot, int flags) {
noasan int TrackMemoryInterval(struct MemoryIntervals *mm, int x, int y, long h,
int prot, int flags) {
unsigned i;
assert(y >= x);
assert(AreMemoryIntervalsOk(mm));

View file

@ -3,7 +3,6 @@
#include "libc/dce.h"
#include "libc/macros.h"
#include "libc/nt/enum/version.h"
#include "libc/nt/struct/teb.h"
#include "libc/runtime/runtime.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_

View file

@ -22,14 +22,14 @@
#include "libc/runtime/memtrack.h"
#include "libc/runtime/runtime.h"
static void *GetFrameAddr(int f) {
static noasan void *GetFrameAddr(int f) {
intptr_t a;
a = f;
a *= FRAMESIZE;
return (void *)a;
}
void ReleaseMemoryNt(struct MemoryIntervals *mm, int l, int r) {
noasan void ReleaseMemoryNt(struct MemoryIntervals *mm, int l, int r) {
int i, ok;
for (i = l; i <= r; ++i) {
ok = UnmapViewOfFile(GetFrameAddr(mm->p[i].x));

View file

@ -52,13 +52,14 @@
* @param flags can have MAP_ANONYMOUS, MAP_SHARED, MAP_PRIVATE, etc.
* @param fd is an open()'d file descriptor whose contents shall be
* mapped, and is ignored if MAP_ANONYMOUS is specified
* @param offset specifies absolute byte index of fd's file for mapping,
* and should be zero if MAP_ANONYMOUS is specified
* @param off specifies absolute byte index of fd's file for mapping,
* should be zero if MAP_ANONYMOUS is specified, and sadly needs
* to be 64kb aligned too
* @return virtual base address of new mapping, or MAP_FAILED w/ errno
*/
void *mmap(void *addr, size_t size, int prot, int flags, int fd, int64_t off) {
int i, x, n, a, b;
struct DirectMap dm;
int i, x, n, a, b, f;
if (!size) return VIP(einval());
if (!ALIGNED(off)) return VIP(einval());
if (!ALIGNED(addr)) return VIP(einval());
@ -84,7 +85,12 @@ void *mmap(void *addr, size_t size, int prot, int flags, int fd, int64_t off) {
}
addr = (void *)(intptr_t)((int64_t)x << 16);
}
dm = __mmap(addr, size, prot, flags | MAP_FIXED, fd, off);
f = flags | MAP_FIXED;
if (IsOpenbsd() && (f & MAP_GROWSDOWN)) { /* openbsd:dubstack */
dm = __mmap(addr, size, prot, f & ~MAP_GROWSDOWN, fd, off);
if (dm.addr == MAP_FAILED) return MAP_FAILED;
}
dm = __mmap(addr, size, prot, f, fd, off);
if (dm.addr == MAP_FAILED || dm.addr != addr) {
return MAP_FAILED;
}

View file

@ -28,14 +28,13 @@
#define WasImported(SLOT) \
((void *)*SLOT && *SLOT != (void *)&missingno /* see libc/crt/crt.S */)
static privileged void __print$nt(const void *data, size_t len) {
static void __print$nt(const void *data, size_t len) {
int64_t hand;
char xmm[256];
uint32_t wrote;
savexmm(xmm + 128);
hand = __imp_GetStdHandle(kNtStdErrorHandle);
__imp_WriteFile(hand, data, len, &wrote, NULL);
__imp_FlushFileBuffers(hand);
loadxmm(xmm + 128);
}
@ -49,7 +48,7 @@ static privileged void __print$nt(const void *data, size_t len) {
* @param len can be computed w/ tinystrlen()
* @clob nothing except flags
*/
privileged void __print(const void *data, size_t len) {
textsyscall void __print(const void *data, size_t len) {
int64_t ax, ordinal;
if (WasImported(__imp_WriteFile)) {
__print$nt(data, len);
@ -68,7 +67,7 @@ privileged void __print(const void *data, size_t len) {
}
}
privileged void __print_string(const char *s) {
void __print_string(const char *s) {
size_t n = 0;
while (s[n]) ++n;
__print(s, n);

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