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:
Justine Tunney 2022-03-24 00:05:59 -07:00
parent b90fa996b4
commit 98909b1391
36 changed files with 1034 additions and 318 deletions

View file

@ -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;

View file

@ -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;

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;

View file

@ -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;
}

View file

@ -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;

View file

@ -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();

View file

@ -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;
}

View file

@ -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.

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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

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/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;
}

View file

@ -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;
}