mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-08 04:08:32 +00:00
Fix more things
- Update a couple unicode data files - Disable strace during logger calls - SQLite now uses pread() / pwrite() - pread() past EOF on NT now returns 0 - Make the NT mmap() and fork() code elegant - Give NT a big performance boost with memory - Add many more mmap() tests to prove it works
This commit is contained in:
parent
b90fa996b4
commit
98909b1391
36 changed files with 1034 additions and 318 deletions
|
@ -16,14 +16,10 @@
|
|||
│ 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/calls/strace.internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nt/enum/filemapflags.h"
|
||||
#include "libc/nt/enum/pageflags.h"
|
||||
#include "libc/nt/memory.h"
|
||||
#include "libc/nt/process.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/nt/struct/overlapped.h"
|
||||
#include "libc/runtime/directmap.internal.h"
|
||||
|
@ -33,55 +29,56 @@
|
|||
textwindows noasan struct DirectMap sys_mmap_nt(void *addr, size_t size,
|
||||
int prot, int flags,
|
||||
int64_t handle, int64_t off) {
|
||||
/* asan runtime depends on this function */
|
||||
uint32_t got;
|
||||
size_t i, upsize;
|
||||
size_t i;
|
||||
struct DirectMap dm;
|
||||
struct NtOverlapped op;
|
||||
uint32_t flags1, flags2;
|
||||
const struct NtSecurityAttributes *sec;
|
||||
|
||||
if (flags & MAP_PRIVATE) {
|
||||
sec = 0; // MAP_PRIVATE isn't inherited across fork()
|
||||
} else {
|
||||
sec = &kNtIsInheritable; // MAP_SHARED gives us zero-copy fork()
|
||||
}
|
||||
|
||||
if ((prot & PROT_WRITE) && (flags & MAP_PRIVATE) && handle != -1) {
|
||||
/*
|
||||
* WIN32 claims it can do COW mappings but we still haven't found a
|
||||
* combination of flags, that'll cause Windows to actually do this!
|
||||
*/
|
||||
upsize = ROUNDUP(size, FRAMESIZE);
|
||||
if ((dm.maphandle =
|
||||
CreateFileMapping(-1, &kNtIsInheritable, kNtPageExecuteReadwrite,
|
||||
upsize >> 32, upsize, NULL))) {
|
||||
if ((dm.addr = MapViewOfFileEx(dm.maphandle,
|
||||
kNtFileMapWrite | kNtFileMapExecute, 0, 0,
|
||||
upsize, addr))) {
|
||||
for (i = 0; i < size; i += got) {
|
||||
got = 0;
|
||||
op.Internal = 0;
|
||||
op.InternalHigh = 0;
|
||||
op.Pointer = (void *)(uintptr_t)i;
|
||||
op.hEvent = 0;
|
||||
if (!ReadFile(handle, (char *)dm.addr + i, size - i, &got, &op)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == size) {
|
||||
return dm;
|
||||
}
|
||||
UnmapViewOfFile(dm.addr);
|
||||
}
|
||||
CloseHandle(dm.maphandle);
|
||||
// windows has cow pages but they can't propagate across fork()
|
||||
if (prot & PROT_EXEC) {
|
||||
flags1 = kNtPageExecuteWritecopy;
|
||||
flags2 = kNtFileMapCopy | kNtFileMapExecute;
|
||||
} else {
|
||||
flags1 = kNtPageWritecopy;
|
||||
flags2 = kNtFileMapCopy;
|
||||
}
|
||||
} else if (prot & PROT_WRITE) {
|
||||
if (prot & PROT_EXEC) {
|
||||
flags1 = kNtPageExecuteReadwrite;
|
||||
flags2 = kNtFileMapWrite | kNtFileMapExecute;
|
||||
} else {
|
||||
flags1 = kNtPageReadwrite;
|
||||
flags2 = kNtFileMapWrite;
|
||||
}
|
||||
} else if (prot & PROT_READ) {
|
||||
if (prot & PROT_EXEC) {
|
||||
flags1 = kNtPageExecuteRead;
|
||||
flags2 = kNtFileMapRead | kNtFileMapExecute;
|
||||
} else {
|
||||
flags1 = kNtPageReadonly;
|
||||
flags2 = kNtFileMapRead;
|
||||
}
|
||||
} else {
|
||||
if ((dm.maphandle = CreateFileMapping(
|
||||
handle, &kNtIsInheritable,
|
||||
(prot & PROT_WRITE) ? kNtPageExecuteReadwrite : kNtPageExecuteRead,
|
||||
handle != -1 ? 0 : size >> 32, handle != -1 ? 0 : size, NULL))) {
|
||||
if ((dm.addr = MapViewOfFileEx(dm.maphandle,
|
||||
(prot & PROT_WRITE)
|
||||
? kNtFileMapWrite | kNtFileMapExecute
|
||||
: kNtFileMapRead | kNtFileMapExecute,
|
||||
off >> 32, off, size, addr))) {
|
||||
return dm;
|
||||
}
|
||||
CloseHandle(dm.maphandle);
|
||||
}
|
||||
flags1 = kNtPageNoaccess;
|
||||
flags2 = 0;
|
||||
}
|
||||
|
||||
if ((dm.maphandle = CreateFileMapping(handle, sec, flags1, (size + off) >> 32,
|
||||
(size + off), 0))) {
|
||||
if ((dm.addr = MapViewOfFileEx(dm.maphandle, flags2, off >> 32, off, size,
|
||||
addr))) {
|
||||
return dm;
|
||||
}
|
||||
CloseHandle(dm.maphandle);
|
||||
}
|
||||
|
||||
dm.maphandle = kNtInvalidHandleValue;
|
||||
dm.addr = (void *)(intptr_t)-1;
|
||||
return dm;
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/errno.h"
|
||||
|
||||
#define __NR_dup3_linux 0x0124 /*RHEL5:CVE-2010-3301*/
|
||||
|
@ -28,6 +29,7 @@ int32_t sys_dup3(int32_t oldfd, int32_t newfd, int flags) {
|
|||
olderr = errno;
|
||||
fd = __sys_dup3(oldfd, newfd, flags);
|
||||
if ((fd == -1 && errno == ENOSYS) || fd == __NR_dup3_linux) {
|
||||
STRACE("demodernizing %s() due to %s", "dup3", "RHEL5:CVE-2010-3301");
|
||||
demodernize = true;
|
||||
once = true;
|
||||
errno = olderr;
|
||||
|
|
|
@ -29,7 +29,7 @@ hidden struct Fds g_fds;
|
|||
static textwindows int64_t GetHandleNt(long a) {
|
||||
int64_t b;
|
||||
b = GetStdHandle(a);
|
||||
STRACE("GetStdHandle(%ld) → %p% m", a, b);
|
||||
STRACE("GetStdHandle(%ld) → %ld% m", a, b);
|
||||
return b;
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "libc/bits/weaken.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/calls/struct/iovec.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/macros.internal.h"
|
||||
|
@ -54,8 +55,8 @@ ssize_t pread(int fd, void *buf, size_t size, int64_t offset) {
|
|||
} else {
|
||||
rc = ebadf();
|
||||
}
|
||||
if (!IsTrustworthy() && rc != -1) {
|
||||
if ((size_t)rc > size) abort();
|
||||
}
|
||||
assert(rc == -1 || (size_t)rc <= size);
|
||||
STRACE("pread(%d, [%#.*hhs%s], %'zu, %'zd) → %'zd% m", fd,
|
||||
MAX(0, MIN(40, rc)), buf, rc > 40 ? "..." : "", size, offset, rc);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "libc/bits/weaken.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/calls/struct/iovec.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
|
@ -70,9 +71,11 @@ ssize_t preadv(int fd, struct iovec *iov, int iovlen, int64_t off) {
|
|||
errno = err;
|
||||
once = true;
|
||||
demodernize = true;
|
||||
STRACE("demodernizing %s() due to %s", "preadv", "ENOSYS");
|
||||
} else if (IsLinux() && rc == __NR_preadv_linux) {
|
||||
if (__iovec_size(iov, iovlen) < __NR_preadv_linux) {
|
||||
demodernize = true; /*RHEL5:CVE-2010-3301*/
|
||||
demodernize = true;
|
||||
STRACE("demodernizing %s() due to %s", "preadv", "RHEL5:CVE-2010-3301");
|
||||
once = true;
|
||||
} else {
|
||||
return rc;
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "libc/assert.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/calls/struct/iovec.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/macros.internal.h"
|
||||
|
@ -57,5 +58,7 @@ ssize_t pwrite(int fd, const void *buf, size_t size, int64_t offset) {
|
|||
assert(wrote <= size);
|
||||
}
|
||||
}
|
||||
STRACE("pwrite(%d, %#.*hhs%s, %'zu, %'zd) → %'zd% m", fd, MAX(0, MIN(40, rc)),
|
||||
buf, rc > 40 ? "..." : "", size, offset, rc);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "libc/bits/weaken.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/calls/struct/iovec.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
|
@ -74,9 +75,12 @@ ssize_t pwritev(int fd, const struct iovec *iov, int iovlen, int64_t off) {
|
|||
errno = err;
|
||||
once = true;
|
||||
demodernize = true;
|
||||
STRACE("demodernizing %s() due to %s", "pwritev", "ENOSYS");
|
||||
} else if (IsLinux() && rc == __NR_pwritev_linux) {
|
||||
if (__iovec_size(iov, iovlen) < __NR_pwritev_linux) {
|
||||
demodernize = true; /*RHEL5:CVE-2010-3301*/
|
||||
demodernize = true;
|
||||
STRACE("demodernizing %s() due to %s", "pwritev",
|
||||
"RHEL5:CVE-2010-3301");
|
||||
once = true;
|
||||
} else {
|
||||
return rc;
|
||||
|
|
|
@ -35,7 +35,11 @@ static textwindows ssize_t sys_read_nt_impl(struct Fd *fd, void *data,
|
|||
if (ReadFile(fd->handle, data, clampio(size), &got,
|
||||
offset2overlap(offset, &overlap))) {
|
||||
return got;
|
||||
} else if (GetLastError() == kNtErrorBrokenPipe) {
|
||||
} else if (
|
||||
// make sure read() returns 0 on broken pipe
|
||||
GetLastError() == kNtErrorBrokenPipe ||
|
||||
// make sure pread() returns 0 if we start reading after EOF
|
||||
GetLastError() == kNtErrorHandleEof) {
|
||||
return 0;
|
||||
} else {
|
||||
return __winerr();
|
||||
|
|
|
@ -60,6 +60,7 @@ ssize_t read(int fd, void *buf, size_t size) {
|
|||
} else {
|
||||
rc = einval();
|
||||
}
|
||||
STRACE("read(%d, %p, %'zu) → %'zd% m", fd, buf, size, rc);
|
||||
STRACE("read(%d, [%#.*hhs%s], %'zu) → %'zd% m", fd, MAX(0, MIN(40, rc)), buf,
|
||||
rc > 40 ? "..." : "", size, rc);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -16,8 +16,8 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/errno.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/errno.h"
|
||||
|
||||
/**
|
||||
* Deletes "file" or empty directory associtaed with name.
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/calls/struct/itimerval.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
|
@ -64,18 +65,41 @@
|
|||
*/
|
||||
int setitimer(int which, const struct itimerval *newvalue,
|
||||
struct itimerval *oldvalue) {
|
||||
int rc;
|
||||
|
||||
if (IsAsan() &&
|
||||
((newvalue && !__asan_is_valid(newvalue, sizeof(*newvalue))) ||
|
||||
(oldvalue && !__asan_is_valid(oldvalue, sizeof(*oldvalue))))) {
|
||||
return efault();
|
||||
}
|
||||
if (!IsWindows()) {
|
||||
rc = efault();
|
||||
} else if (!IsWindows()) {
|
||||
if (newvalue) {
|
||||
return sys_setitimer(which, newvalue, oldvalue);
|
||||
rc = sys_setitimer(which, newvalue, oldvalue);
|
||||
} else {
|
||||
return sys_getitimer(which, oldvalue);
|
||||
rc = sys_getitimer(which, oldvalue);
|
||||
}
|
||||
} else {
|
||||
return sys_setitimer_nt(which, newvalue, oldvalue);
|
||||
rc = sys_setitimer_nt(which, newvalue, oldvalue);
|
||||
}
|
||||
|
||||
if (newvalue && oldvalue) {
|
||||
STRACE("setitimer(%d, "
|
||||
"{{%'ld, %'ld}, {%'ld, %'ld}}, "
|
||||
"[{{%'ld, %'ld}, {%'ld, %'ld}}]) → %d% m",
|
||||
which, newvalue->it_interval.tv_sec, newvalue->it_interval.tv_usec,
|
||||
newvalue->it_value.tv_sec, newvalue->it_value.tv_usec,
|
||||
oldvalue->it_interval.tv_sec, oldvalue->it_interval.tv_usec,
|
||||
oldvalue->it_value.tv_sec, oldvalue->it_value.tv_usec, rc);
|
||||
} else if (newvalue) {
|
||||
STRACE("setitimer(%d, {{%'ld, %'ld}, {%'ld, %'ld}}, NULL) → %d% m", which,
|
||||
newvalue->it_interval.tv_sec, newvalue->it_interval.tv_usec,
|
||||
newvalue->it_value.tv_sec, newvalue->it_value.tv_usec, rc);
|
||||
} else if (oldvalue) {
|
||||
STRACE("setitimer(%d, NULL, [{{%'ld, %'ld}, {%'ld, %'ld}}]) → %d% m", which,
|
||||
oldvalue->it_interval.tv_sec, oldvalue->it_interval.tv_usec,
|
||||
oldvalue->it_value.tv_sec, oldvalue->it_value.tv_usec, rc);
|
||||
} else {
|
||||
STRACE("setitimer(%d, NULL, NULL) → %d% m", which, rc);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -18,7 +18,11 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/nt/createfile.h"
|
||||
#include "libc/nt/enum/accessmask.h"
|
||||
#include "libc/nt/enum/creationdisposition.h"
|
||||
#include "libc/nt/enum/fileflagandattributes.h"
|
||||
#include "libc/nt/enum/filesharemode.h"
|
||||
#include "libc/nt/enum/io.h"
|
||||
#include "libc/nt/errors.h"
|
||||
#include "libc/nt/files.h"
|
||||
|
@ -28,6 +32,48 @@
|
|||
#include "libc/nt/synchronization.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
|
||||
/**
|
||||
* Performs synchronization on directory of pathname.
|
||||
*
|
||||
* This code is intended to help prevent subsequent i/o operations
|
||||
* from failing for no reason at all. For example a unit test that
|
||||
* repeatedly opens and unlinks the same filename.
|
||||
*/
|
||||
static textwindows int SyncDirectory(int df, char16_t path[PATH_MAX], int n) {
|
||||
int rc;
|
||||
int64_t fh;
|
||||
char16_t *p;
|
||||
if ((p = memrchr16(path, '\\', n))) {
|
||||
if (p - path == 2 && path[1] == ':') return 0; // XXX: avoid syncing volume
|
||||
*p = 0;
|
||||
} else {
|
||||
if (df != AT_FDCWD) {
|
||||
if (FlushFileBuffers(df)) {
|
||||
return 0;
|
||||
} else {
|
||||
return __winerr();
|
||||
}
|
||||
}
|
||||
path[0] = '.';
|
||||
path[1] = 0;
|
||||
}
|
||||
if ((fh = CreateFile(
|
||||
path, kNtFileGenericWrite,
|
||||
kNtFileShareRead | kNtFileShareWrite | kNtFileShareDelete, 0,
|
||||
kNtOpenExisting, kNtFileAttributeNormal | kNtFileFlagBackupSemantics,
|
||||
0)) != -1) {
|
||||
if (FlushFileBuffers(fh)) {
|
||||
rc = 0;
|
||||
} else {
|
||||
rc = __winerr();
|
||||
}
|
||||
CloseHandle(fh);
|
||||
} else {
|
||||
rc = __winerr();
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static textwindows bool IsDirectorySymlink(const char16_t *path) {
|
||||
int64_t h;
|
||||
struct NtWin32FindData data;
|
||||
|
@ -67,16 +113,28 @@ static textwindows int sys_rmdir_nt(const char16_t *path) {
|
|||
}
|
||||
|
||||
static textwindows int sys_unlink_nt(const char16_t *path) {
|
||||
if (IsDirectorySymlink(path)) return sys_rmdir_nt(path);
|
||||
return DeleteFile(path) ? 0 : __winerr();
|
||||
if (IsDirectorySymlink(path)) {
|
||||
return sys_rmdir_nt(path);
|
||||
} else if (DeleteFile(path)) {
|
||||
return 0;
|
||||
} else {
|
||||
return __winerr();
|
||||
}
|
||||
}
|
||||
|
||||
textwindows int sys_unlinkat_nt(int dirfd, const char *path, int flags) {
|
||||
uint16_t path16[PATH_MAX];
|
||||
if (__mkntpathat(dirfd, path, 0, path16) == -1) return -1;
|
||||
if (flags & AT_REMOVEDIR) {
|
||||
return sys_rmdir_nt(path16);
|
||||
int n, rc;
|
||||
char16_t path16[PATH_MAX];
|
||||
if ((n = __mkntpathat(dirfd, path, 0, path16)) == -1) {
|
||||
rc = -1;
|
||||
} else if (flags & AT_REMOVEDIR) {
|
||||
rc = sys_rmdir_nt(path16);
|
||||
} else {
|
||||
return sys_unlink_nt(path16);
|
||||
rc = sys_unlink_nt(path16);
|
||||
if (rc != -1) {
|
||||
// TODO(jart): prove that it helps first
|
||||
// rc = SyncDirectory(dirfd, path16, n);
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -29,6 +29,8 @@
|
|||
/**
|
||||
* Deletes inode and maybe the file too.
|
||||
*
|
||||
* This may be used to delete files and directories and symlinks.
|
||||
*
|
||||
* @param dirfd is normally AT_FDCWD but if it's an open directory and
|
||||
* path is relative, then path becomes relative to dirfd
|
||||
* @param path is the thing to delete
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/time/time.h"
|
||||
|
||||
|
@ -23,7 +24,10 @@
|
|||
* Sleeps for particular amount of microseconds.
|
||||
*/
|
||||
int usleep(uint32_t microseconds) {
|
||||
return nanosleep(
|
||||
&(struct timespec){microseconds / 1000000, microseconds % 1000000 * 1000},
|
||||
NULL);
|
||||
int rc;
|
||||
rc = nanosleep(&(struct timespec){(uint64_t)microseconds / 1000000,
|
||||
(uint64_t)microseconds % 1000000 * 1000},
|
||||
NULL);
|
||||
STRACE("usleep(%'u) → %d% m", microseconds, rc);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -58,6 +58,7 @@ ssize_t write(int fd, const void *buf, size_t size) {
|
|||
} else {
|
||||
rc = einval();
|
||||
}
|
||||
STRACE("write(%d, %p, %'zu) → %'zd% m", fd, buf, size, rc);
|
||||
STRACE("write(%d, %#.*hhs%s, %'zu) → %'zd% m", fd, MAX(0, MIN(40, rc)), buf,
|
||||
rc > 40 ? "..." : "", size, rc);
|
||||
return rc;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue