Make mmap() work better

- Mapping file offsets now works on Windows
- Mapping stack memory now works on OpenBSD
This commit is contained in:
Justine Tunney 2021-02-03 00:10:12 -08:00
parent 23a14b537c
commit 27c899af56
10 changed files with 71 additions and 56 deletions

View file

@ -42,16 +42,7 @@ static textwindows int64_t open$nt$impl(int dirfd, const char *path,
char16_t path16[PATH_MAX]; char16_t path16[PATH_MAX];
if (__mkntpathat(dirfd, path, flags, path16) == -1) return -1; if (__mkntpathat(dirfd, path, flags, path16) == -1) return -1;
if ((handle = CreateFile( if ((handle = CreateFile(
path16, path16, flags & 0xf000000f, /* see consts.sh */
(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),
(flags & O_EXCL) (flags & O_EXCL)
? kNtFileShareExclusive ? kNtFileShareExclusive
: kNtFileShareRead | kNtFileShareWrite | kNtFileShareDelete, : kNtFileShareRead | kNtFileShareWrite | kNtFileShareDelete,
@ -75,14 +66,6 @@ static textwindows int64_t open$nt$impl(int dirfd, const char *path,
kNtFileFlagBackupSemantics | kNtFileFlagPosixSemantics | kNtFileFlagBackupSemantics | kNtFileFlagPosixSemantics |
kNtFileAttributeTemporary)))), kNtFileAttributeTemporary)))),
0)) != -1) { 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; return handle;
} else if (GetLastError() == kNtErrorFileExists && } else if (GetLastError() == kNtErrorFileExists &&
((flags & O_CREAT) && ((flags & O_CREAT) &&

View file

@ -16,6 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/calls/calls.h"
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/nt/enum/filemapflags.h" #include "libc/nt/enum/filemapflags.h"
#include "libc/nt/enum/pageflags.h" #include "libc/nt/enum/pageflags.h"
@ -30,7 +31,8 @@ textwindows struct DirectMap __mmap$nt(void *addr, size_t size, unsigned prot,
if ((dm.maphandle = CreateFileMappingNuma( if ((dm.maphandle = CreateFileMappingNuma(
handle, &kNtIsInheritable, handle, &kNtIsInheritable,
(prot & PROT_WRITE) ? kNtPageExecuteReadwrite : kNtPageExecuteRead, (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( if (!(dm.addr = MapViewOfFileExNuma(
dm.maphandle, dm.maphandle,
(prot & PROT_WRITE) (prot & PROT_WRITE)

View file

@ -52,13 +52,14 @@
* @param flags can have MAP_ANONYMOUS, MAP_SHARED, MAP_PRIVATE, etc. * @param flags can have MAP_ANONYMOUS, MAP_SHARED, MAP_PRIVATE, etc.
* @param fd is an open()'d file descriptor whose contents shall be * @param fd is an open()'d file descriptor whose contents shall be
* mapped, and is ignored if MAP_ANONYMOUS is specified * mapped, and is ignored if MAP_ANONYMOUS is specified
* @param offset specifies absolute byte index of fd's file for mapping, * @param off specifies absolute byte index of fd's file for mapping,
* and should be zero if MAP_ANONYMOUS is specified * 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 * @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) { 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; struct DirectMap dm;
int i, x, n, a, b, f;
if (!size) return VIP(einval()); if (!size) return VIP(einval());
if (!ALIGNED(off)) return VIP(einval()); if (!ALIGNED(off)) return VIP(einval());
if (!ALIGNED(addr)) 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); 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) { if (dm.addr == MAP_FAILED || dm.addr != addr) {
return MAP_FAILED; return MAP_FAILED;
} }

View file

@ -205,10 +205,10 @@ syscon sig SIGRTMIN 0 0 65 0 0
# │││ │ ┌┴───dwDesiredAccess # │││ │ ┌┴───dwDesiredAccess
# N │││ │ │ # N │││ │ │
# group name GNU/Systemd XNU's Not UNIX FreeBSD OpenBSD T │││┌─┴┐│ Commentary # group name GNU/Systemd XNU's Not UNIX FreeBSD OpenBSD T │││┌─┴┐│ Commentary
syscon open O_RDONLY 0 0 0 0 0x80000000 # unix consensus & kNtGenericRead syscon open O_RDONLY 0 0 0 0 0xA0000000 # unix consensus & kNtGenericRead|kNtGenericExecute
syscon open O_WRONLY 1 1 1 1 0x40000000 # unix consensus & kNtGenericWrite syscon open O_WRONLY 1 1 1 1 0x40000000 # unix consensus & kNtGenericWrite
syscon open O_RDWR 2 2 2 2 0xc0000000 # unix consensus & kNtGenericRead|kNtGenericWrite syscon open O_RDWR 2 2 2 2 0xE0000000 # unix consensus & kNtGenericRead|kNtGenericWrite|kNtGenericExecute
syscon open O_ACCMODE 3 3 3 3 0xc0000000 # O_RDONLY|O_WRONLY|O_RDWR syscon open O_ACCMODE 3 3 3 3 0xE0000000 # O_RDONLY|O_WRONLY|O_RDWR
syscon open O_APPEND 0x0400 8 8 8 0x00000004 # bsd consensus & kNtFileAppendData; won't pose issues w/ mknod(S_IFIFO) syscon open O_APPEND 0x0400 8 8 8 0x00000004 # bsd consensus & kNtFileAppendData; won't pose issues w/ mknod(S_IFIFO)
syscon open O_CREAT 0x40 0x0200 0x0200 0x0200 0x00000040 # bsd consensus & NT faked as Linux syscon open O_CREAT 0x40 0x0200 0x0200 0x0200 0x00000040 # bsd consensus & NT faked as Linux
syscon open O_EXCL 0x80 0x0800 0x0800 0x0800 0x00000080 # bsd consensus & NT faked as Linux syscon open O_EXCL 0x80 0x0800 0x0800 0x0800 0x00000080 # bsd consensus & NT faked as Linux

View file

@ -1,2 +1,2 @@
.include "libc/sysv/consts/syscon.inc" .include "libc/sysv/consts/syscon.inc"
.syscon open O_ACCMODE 3 3 3 3 0xc0000000 .syscon open O_ACCMODE 3 3 3 3 0xE0000000

View file

@ -1,2 +1,2 @@
.include "libc/sysv/consts/syscon.inc" .include "libc/sysv/consts/syscon.inc"
.syscon open O_RDONLY 0 0 0 0 0x80000000 .syscon open O_RDONLY 0 0 0 0 0xA0000000

View file

@ -1,2 +1,2 @@
.include "libc/sysv/consts/syscon.inc" .include "libc/sysv/consts/syscon.inc"
.syscon open O_RDWR 2 2 2 2 0xc0000000 .syscon open O_RDWR 2 2 2 2 0xE0000000

View file

@ -88,6 +88,42 @@ TEST(mmap, testMapFixed_destroysEverythingInItsPath) {
EXPECT_NE(-1, munmap((void *)kFixedmapStart, FRAMESIZE * 3)); EXPECT_NE(-1, munmap((void *)kFixedmapStart, FRAMESIZE * 3));
} }
TEST(mmap, customStackMemory_isAuthorized) {
char *stack;
uintptr_t w, r;
ASSERT_NE(MAP_FAILED,
(stack = mmap(NULL, STACKSIZE, PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_PRIVATE | MAP_GROWSDOWN, -1, 0)));
asm("mov\t%%rsp,%0\n\t"
"mov\t%2,%%rsp\n\t"
"push\t%3\n\t"
"pop\t%1\n\t"
"mov\t%0,%%rsp"
: "=&r"(w), "=&r"(r)
: "rm"(stack + STACKSIZE - 8), "i"(123));
ASSERT_EQ(123, r);
}
TEST(mmap, fileOffset) {
int fd;
char *map;
char testdir[PATH_MAX];
sprintf(testdir, "o/tmp/%s.%d", program_invocation_short_name, getpid());
ASSERT_NE(-1, makedirs(testdir, 0755));
ASSERT_NE(-1, chdir(testdir));
ASSERT_NE(-1, (fd = open("foo", O_CREAT | O_RDWR, 0644)));
EXPECT_NE(-1, ftruncate(fd, FRAMESIZE * 2));
EXPECT_NE(-1, pwrite(fd, "hello", 5, FRAMESIZE * 0));
EXPECT_NE(-1, pwrite(fd, "there", 5, FRAMESIZE * 1));
ASSERT_NE(MAP_FAILED, (map = mmap(NULL, FRAMESIZE, PROT_READ, MAP_PRIVATE, fd,
FRAMESIZE)));
EXPECT_EQ(0, memcmp(map, "there", 5), "%#.*s", 5, map);
EXPECT_NE(-1, munmap(map, FRAMESIZE));
EXPECT_NE(-1, close(fd));
ASSERT_NE(-1, chdir("../../.."));
ASSERT_NE(-1, rmrf(testdir));
}
TEST(isheap, nullPtr) { TEST(isheap, nullPtr) {
ASSERT_FALSE(isheap(NULL)); ASSERT_FALSE(isheap(NULL));
} }

View file

@ -21,13 +21,8 @@ THIRD_PARTY_CHIBICC_TEST_HDRS = $(filter %.h,$(THIRD_PARTY_CHIBICC_TEST_FILES))
THIRD_PARTY_CHIBICC_TEST_TESTS = $(THIRD_PARTY_CHIBICC_TEST_COMS:%=%.ok) THIRD_PARTY_CHIBICC_TEST_TESTS = $(THIRD_PARTY_CHIBICC_TEST_COMS:%=%.ok)
THIRD_PARTY_CHIBICC_TEST_COMS = \ THIRD_PARTY_CHIBICC_TEST_COMS = \
$(THIRD_PARTY_CHIBICC_TEST_SRCS_TEST:%.c=o/$(MODE)/%.com) $(THIRD_PARTY_CHIBICC_TEST_SRCS_TEST:%_test.c=o/$(MODE)/%_test.com) \
$(THIRD_PARTY_CHIBICC_TEST_SRCS_TEST:%_test.c=o/$(MODE)/%_test2.com)
# TODO(jart): make chibicc compiled chibicc work with asan runtime
ifneq ($(MODE),dbg)
THIRD_PARTY_CHIBICC_TEST_COMS += \
$(THIRD_PARTY_CHIBICC_TEST_SRCS_TEST:%.c=o/$(MODE)/%2.com)
endif
THIRD_PARTY_CHIBICC_TEST_OBJS = \ THIRD_PARTY_CHIBICC_TEST_OBJS = \
$(THIRD_PARTY_CHIBICC_TEST_SRCS:%.c=o/$(MODE)/%.chibicc.o) $(THIRD_PARTY_CHIBICC_TEST_SRCS:%.c=o/$(MODE)/%.chibicc.o)
@ -62,21 +57,19 @@ THIRD_PARTY_CHIBICC_TEST_DEPS := \
$(call uniq,$(foreach x,$(THIRD_PARTY_CHIBICC_TEST_DIRECTDEPS),$($(x)))) $(call uniq,$(foreach x,$(THIRD_PARTY_CHIBICC_TEST_DIRECTDEPS),$($(x))))
$(THIRD_PARTY_CHIBICC_TEST_A): \ $(THIRD_PARTY_CHIBICC_TEST_A): \
third_party/chibicc/test/ \
$(THIRD_PARTY_CHIBICC_TEST_A).pkg \ $(THIRD_PARTY_CHIBICC_TEST_A).pkg \
$(THIRD_PARTY_CHIBICC_TEST_OBJS) o/$(MODE)/third_party/chibicc/test/common.chibicc.o
$(THIRD_PARTY_CHIBICC_TEST2_A): \ $(THIRD_PARTY_CHIBICC_TEST2_A): \
third_party/chibicc/test/ \
$(THIRD_PARTY_CHIBICC_TEST2_A).pkg \ $(THIRD_PARTY_CHIBICC_TEST2_A).pkg \
$(THIRD_PARTY_CHIBICC_TEST2_OBJS) o/$(MODE)/third_party/chibicc/test/common.chibicc2.o
$(THIRD_PARTY_CHIBICC_TEST_A).pkg: \ $(THIRD_PARTY_CHIBICC_TEST_A).pkg: \
$(THIRD_PARTY_CHIBICC_TEST_OBJS) \ o/$(MODE)/third_party/chibicc/test/common.chibicc.o \
$(foreach x,$(THIRD_PARTY_CHIBICC_TEST_DIRECTDEPS),$($(x)_A).pkg) $(foreach x,$(THIRD_PARTY_CHIBICC_TEST_DIRECTDEPS),$($(x)_A).pkg)
$(THIRD_PARTY_CHIBICC_TEST2_A).pkg: \ $(THIRD_PARTY_CHIBICC_TEST2_A).pkg: \
$(THIRD_PARTY_CHIBICC_TEST2_OBJS) \ o/$(MODE)/third_party/chibicc/test/common.chibicc2.o \
$(foreach x,$(THIRD_PARTY_CHIBICC_TEST_DIRECTDEPS),$($(x)_A).pkg) $(foreach x,$(THIRD_PARTY_CHIBICC_TEST_DIRECTDEPS),$($(x)_A).pkg)
o/$(MODE)/third_party/chibicc/test/%.com.dbg: \ o/$(MODE)/third_party/chibicc/test/%.com.dbg: \

View file

@ -136,21 +136,16 @@ static int read_ident(char *start) {
} }
} }
static int from_hex(char c) {
if ('0' <= c && c <= '9') return c - '0';
if ('a' <= c && c <= 'f') return c - 'a' + 10;
return c - 'A' + 10;
}
// Read a punctuator token from p and returns its length. // Read a punctuator token from p and returns its length.
int read_punct(char *p) { int read_punct(char *p) {
static char kw[][4] = {"<<=", ">>=", "...", "==", "!=", "<=", ">=", "->", static const char kPunct[][4] = {
"+=", "-=", "*=", "/=", "++", "--", "%=", "&=", "<<=", ">>=", "...", "==", "!=", "<=", ">=", "->", "+=", "-=", "*=", "/=",
"|=", "^=", "&&", "||", "<<", ">>", "##"}; "++", "--", "%=", "&=", "|=", "^=", "&&", "||", "<<", ">>", "##",
for (int i = 0; i < sizeof(kw) / sizeof(*kw); i++) { };
for (int i = 0; i < sizeof(kPunct) / sizeof(*kPunct); i++) {
for (int j = 0;;) { for (int j = 0;;) {
if (p[j] != kw[i][j]) break; if (p[j] != kPunct[i][j]) break;
if (!kw[i][++j]) return j; if (!kPunct[i][++j]) return j;
} }
} }
return ispunct(*p) ? 1 : 0; return ispunct(*p) ? 1 : 0;
@ -200,7 +195,7 @@ int read_escaped_char(char **new_pos, char *p) {
if (!isxdigit(*p)) error_at(p, "invalid hex escape sequence"); if (!isxdigit(*p)) error_at(p, "invalid hex escape sequence");
unsigned c = 0; unsigned c = 0;
for (; isxdigit(*p); p++) { for (; isxdigit(*p); p++) {
c = (c << 4) + from_hex(*p); /* TODO(jart): overflow here unicode_test */ c = (c << 4) + hextoint(*p); /* TODO(jart): overflow here unicode_test */
} }
*new_pos = p; *new_pos = p;
return c; return c;
@ -628,7 +623,7 @@ static uint32_t read_universal_char(char *p, int len) {
uint32_t c = 0; uint32_t c = 0;
for (int i = 0; i < len; i++) { for (int i = 0; i < len; i++) {
if (!isxdigit(p[i])) return 0; if (!isxdigit(p[i])) return 0;
c = (c << 4) | from_hex(p[i]); c = (c << 4) | hextoint(p[i]);
} }
return c; return c;
} }