mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-27 04:50:28 +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
|
@ -44,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 \
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -52,6 +52,7 @@ struct Fds {
|
|||
kFdSerial,
|
||||
kFdZip,
|
||||
kFdEpoll,
|
||||
kFdReserved,
|
||||
} kind;
|
||||
unsigned flags;
|
||||
} * p;
|
||||
|
@ -68,7 +69,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;
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -57,8 +54,9 @@ static void SortStrings(char **a, size_t n) {
|
|||
* @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[],
|
||||
const char *extravar) {
|
||||
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;
|
||||
|
@ -66,9 +64,8 @@ textwindows int mkntenvblock(char16_t envvars[ARG_MAX], char *const envp[],
|
|||
size_t i, j, k, n, m;
|
||||
for (n = 0; envp[n];) n++;
|
||||
vars = alloca((n + 1) * sizeof(char *));
|
||||
memcpy(vars, envp, n * sizeof(char *));
|
||||
if (extravar) vars[n++] = extravar;
|
||||
SortStrings(vars, n);
|
||||
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 {
|
||||
|
|
|
@ -112,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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
29
libc/calls/releasefd.c
Normal 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));
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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"
|
||||
|
@ -128,9 +129,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) {
|
||||
|
@ -141,6 +141,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) {
|
||||
|
@ -149,16 +152,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 {
|
||||
|
@ -178,7 +178,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)(
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue