mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-09 04:38:29 +00:00
Eliminate some flakes
- Get ASAN working on Windows. - Deleting directories and then recreating them with the same name in a short period of time appears to be a no-no on Windows. - There's no reason to call FlushFileBuffers on close() for pipes, and it's harmful since it might block indefinitely for no good reason.
This commit is contained in:
parent
27c899af56
commit
4e56d89dcd
60 changed files with 588 additions and 751 deletions
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -25,8 +25,9 @@
|
|||
#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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -46,7 +46,7 @@
|
|||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
static textwindows char16_t *ParseInt(char16_t *p, int64_t *x) {
|
||||
static textwindows noasan char16_t *ParseInt(char16_t *p, int64_t *x) {
|
||||
*x = 0;
|
||||
while (*p == ' ') p++;
|
||||
while ('0' <= *p && *p <= '9') {
|
||||
|
@ -56,8 +56,8 @@ static textwindows char16_t *ParseInt(char16_t *p, int64_t *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;
|
||||
|
@ -66,15 +66,17 @@ 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) {
|
||||
textwindows noasan void WinMainForked(void) {
|
||||
void *addr;
|
||||
jmp_buf jb;
|
||||
uint64_t size;
|
||||
|
@ -117,13 +119,13 @@ textwindows void WinMainForked(void) {
|
|||
|
||||
textwindows int fork$nt(void) {
|
||||
jmp_buf jb;
|
||||
int i, rc, pid;
|
||||
char exe[PATH_MAX];
|
||||
int64_t reader, writer;
|
||||
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 = stpcpy(forkvar, "_FORK=");
|
||||
|
@ -148,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));
|
||||
|
@ -170,5 +173,8 @@ textwindows int fork$nt(void) {
|
|||
} else {
|
||||
rc = 0;
|
||||
}
|
||||
if (releaseme != -1) {
|
||||
__releasefd(releaseme);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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_
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -35,7 +35,6 @@ static void __print$nt(const void *data, size_t len) {
|
|||
savexmm(xmm + 128);
|
||||
hand = __imp_GetStdHandle(kNtStdErrorHandle);
|
||||
__imp_WriteFile(hand, data, len, &wrote, NULL);
|
||||
__imp_FlushFileBuffers(hand);
|
||||
loadxmm(xmm + 128);
|
||||
}
|
||||
|
||||
|
|
|
@ -72,6 +72,7 @@ void __print_string(const char *);
|
|||
void __fast_math(void);
|
||||
void *sbrk(intptr_t);
|
||||
int brk(void *);
|
||||
int NtGetVersion(void);
|
||||
|
||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||
│ cosmopolitan § runtime » optimizations ─╬─│┼
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
#include "libc/bits/pushpop.h"
|
||||
#include "libc/nt/enum/version.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/nt/struct/teb.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
#include "libc/sysv/consts/fileno.h"
|
||||
#include "libc/sysv/consts/nr.h"
|
||||
|
@ -29,7 +28,7 @@
|
|||
/**
|
||||
* Aborts program under enemy fire to avoid being taken alive.
|
||||
*/
|
||||
textsyscall void __stack_chk_fail(void) {
|
||||
textsyscall noasan void __stack_chk_fail(void) {
|
||||
size_t len;
|
||||
const char *msg;
|
||||
int64_t ax, cx, si;
|
||||
|
|
|
@ -35,7 +35,6 @@
|
|||
#include "libc/nt/pedef.internal.h"
|
||||
#include "libc/nt/process.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/nt/struct/teb.h"
|
||||
#include "libc/runtime/directmap.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
#include "libc/runtime/memtrack.h"
|
||||
|
@ -56,16 +55,16 @@ struct WinArgs {
|
|||
char envblock[ARG_MAX];
|
||||
};
|
||||
|
||||
static textwindows void SetTrueColor(void) {
|
||||
static noasan textwindows void SetTrueColor(void) {
|
||||
SetEnvironmentVariable(u"TERM", u"xterm-truecolor");
|
||||
}
|
||||
|
||||
static textwindows void MakeLongDoubleLongAgain(void) {
|
||||
static noasan textwindows void MakeLongDoubleLongAgain(void) {
|
||||
int x87cw = 0x037f; /* let's hope win32 won't undo this */
|
||||
asm volatile("fldcw\t%0" : /* no outputs */ : "m"(x87cw));
|
||||
}
|
||||
|
||||
static textwindows void NormalizeCmdExe(void) {
|
||||
static noasan textwindows void NormalizeCmdExe(void) {
|
||||
uint32_t mode;
|
||||
int64_t handle, hstdin, hstdout, hstderr;
|
||||
if ((int)weakaddr("v_ntsubsystem") == kNtImageSubsystemWindowsCui &&
|
||||
|
@ -96,7 +95,7 @@ static textwindows void NormalizeCmdExe(void) {
|
|||
}
|
||||
}
|
||||
|
||||
static textwindows wontreturn void WinMainNew(void) {
|
||||
static noasan textwindows wontreturn void WinMainNew(void) {
|
||||
int64_t h;
|
||||
size_t size;
|
||||
int i, count;
|
||||
|
@ -165,8 +164,8 @@ static textwindows wontreturn void WinMainNew(void) {
|
|||
*
|
||||
* @param hInstance call GetModuleHandle(NULL) from main if you need it
|
||||
*/
|
||||
textwindows int64_t WinMain(int64_t hInstance, int64_t hPrevInstance,
|
||||
const char *lpCmdLine, int nCmdShow) {
|
||||
noasan textwindows int64_t WinMain(int64_t hInstance, int64_t hPrevInstance,
|
||||
const char *lpCmdLine, int nCmdShow) {
|
||||
MakeLongDoubleLongAgain();
|
||||
if (weaken(winsockinit)) weaken(winsockinit)();
|
||||
if (weaken(WinMainForked)) weaken(WinMainForked)();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue