mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-05-28 00:02:28 +00:00
Rewrite memory manager
Actually Portable Executable now supports Android. Cosmo's old mmap code required a 47 bit address space. The new implementation is very agnostic and supports both smaller address spaces (e.g. embedded) and even modern 56-bit PML5T paging for x86 which finally came true on Zen4 Threadripper Cosmopolitan no longer requires UNIX systems to observe the Windows 64kb granularity; i.e. sysconf(_SC_PAGE_SIZE) will now report the host native page size. This fixes a longstanding POSIX conformance issue, concerning file mappings that overlap the end of file. Other aspects of conformance have been improved too, such as the subtleties of address assignment and and the various subtleties surrounding MAP_FIXED and MAP_FIXED_NOREPLACE On Windows, mappings larger than 100 megabytes won't be broken down into thousands of independent 64kb mappings. Support for MAP_STACK is removed by this change; please use NewCosmoStack() instead. Stack overflow avoidance is now being implemented using the POSIX thread APIs. Please use GetStackBottom() and GetStackAddr(), instead of the old error-prone GetStackAddr() and HaveStackMemory() APIs which are removed.
This commit is contained in:
parent
7f6d0b8709
commit
6ffed14b9c
150 changed files with 1893 additions and 5634 deletions
|
@ -33,41 +33,41 @@ void SetUpOnce(void) {
|
|||
|
||||
TEST(madvise, anon) {
|
||||
char *p;
|
||||
ASSERT_NE(MAP_FAILED, (p = mmap(0, FRAMESIZE, PROT_READ | PROT_WRITE,
|
||||
ASSERT_NE(MAP_FAILED, (p = mmap(0, __granularity(), PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)));
|
||||
ASSERT_SYS(0, 0, madvise(p, FRAMESIZE, MADV_WILLNEED));
|
||||
ASSERT_SYS(0, 0, munmap(p, FRAMESIZE));
|
||||
ASSERT_SYS(0, 0, madvise(p, __granularity(), MADV_WILLNEED));
|
||||
ASSERT_SYS(0, 0, munmap(p, __granularity()));
|
||||
}
|
||||
|
||||
TEST(madvise, file) {
|
||||
char *p;
|
||||
ASSERT_SYS(0, 3, creat("foo.dat", 0644));
|
||||
ASSERT_SYS(0, 0, ftruncate(3, FRAMESIZE));
|
||||
ASSERT_SYS(0, 0, ftruncate(3, __granularity()));
|
||||
ASSERT_SYS(0, 0, close(3));
|
||||
ASSERT_SYS(0, 3, open("foo.dat", O_RDWR));
|
||||
ASSERT_NE(MAP_FAILED, (p = mmap(0, FRAMESIZE, PROT_READ | PROT_WRITE,
|
||||
ASSERT_NE(MAP_FAILED, (p = mmap(0, __granularity(), PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE, 3, 0)));
|
||||
ASSERT_SYS(0, 0, madvise(p, FRAMESIZE, MADV_WILLNEED));
|
||||
ASSERT_SYS(0, 0, munmap(p, FRAMESIZE));
|
||||
ASSERT_SYS(0, 0, madvise(p, __granularity(), MADV_WILLNEED));
|
||||
ASSERT_SYS(0, 0, munmap(p, __granularity()));
|
||||
ASSERT_SYS(0, 0, close(3));
|
||||
}
|
||||
|
||||
TEST(madvise, short) {
|
||||
char *p;
|
||||
ASSERT_NE(MAP_FAILED, (p = mmap(0, FRAMESIZE, PROT_READ | PROT_WRITE,
|
||||
ASSERT_NE(MAP_FAILED, (p = mmap(0, __granularity(), PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)));
|
||||
ASSERT_SYS(0, 0, madvise(p, FRAMESIZE - 1, MADV_WILLNEED));
|
||||
ASSERT_SYS(0, 0, munmap(p, FRAMESIZE));
|
||||
ASSERT_SYS(0, 0, madvise(p, __granularity() - 1, MADV_WILLNEED));
|
||||
ASSERT_SYS(0, 0, munmap(p, __granularity()));
|
||||
}
|
||||
|
||||
TEST(madvise, subPages) {
|
||||
char *p;
|
||||
ASSERT_NE(MAP_FAILED, (p = mmap(0, FRAMESIZE, PROT_READ | PROT_WRITE,
|
||||
ASSERT_NE(MAP_FAILED, (p = mmap(0, __granularity(), PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)));
|
||||
ASSERT_SYS(0, 0,
|
||||
madvise(p + getauxval(AT_PAGESZ), FRAMESIZE - getauxval(AT_PAGESZ),
|
||||
MADV_WILLNEED));
|
||||
ASSERT_SYS(0, 0, munmap(p, FRAMESIZE));
|
||||
madvise(p + getauxval(AT_PAGESZ),
|
||||
__granularity() - getauxval(AT_PAGESZ), MADV_WILLNEED));
|
||||
ASSERT_SYS(0, 0, munmap(p, __granularity()));
|
||||
}
|
||||
|
||||
TEST(madvise, misalign) {
|
||||
|
@ -76,20 +76,20 @@ TEST(madvise, misalign) {
|
|||
return; // most platforms don't care
|
||||
if (IsQemuUser())
|
||||
return; // qemu claims to be linux but doesn't care
|
||||
ASSERT_NE(MAP_FAILED, (p = mmap(0, FRAMESIZE, PROT_READ | PROT_WRITE,
|
||||
ASSERT_NE(MAP_FAILED, (p = mmap(0, __granularity(), PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)));
|
||||
ASSERT_SYS(EINVAL, -1, madvise(p + 1, FRAMESIZE - 1, MADV_WILLNEED));
|
||||
ASSERT_SYS(0, 0, munmap(p, FRAMESIZE));
|
||||
ASSERT_SYS(EINVAL, -1, madvise(p + 1, __granularity() - 1, MADV_WILLNEED));
|
||||
ASSERT_SYS(0, 0, munmap(p, __granularity()));
|
||||
}
|
||||
|
||||
TEST(madvise, badAdvice) {
|
||||
char *p;
|
||||
if (IsAarch64() && IsQemuUser())
|
||||
return; // qemu doesn't validate advice
|
||||
ASSERT_NE(MAP_FAILED, (p = mmap(0, FRAMESIZE, PROT_READ | PROT_WRITE,
|
||||
ASSERT_NE(MAP_FAILED, (p = mmap(0, __granularity(), PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)));
|
||||
ASSERT_SYS(EINVAL, -1, madvise(p, FRAMESIZE, 127));
|
||||
ASSERT_SYS(0, 0, munmap(p, FRAMESIZE));
|
||||
ASSERT_SYS(EINVAL, -1, madvise(p, __granularity(), 127));
|
||||
ASSERT_SYS(0, 0, munmap(p, __granularity()));
|
||||
}
|
||||
|
||||
TEST(madvise, missingMemory) {
|
||||
|
@ -98,5 +98,5 @@ TEST(madvise, missingMemory) {
|
|||
if (IsQemuUser())
|
||||
return; // qemu claims to be linux but doesn't care
|
||||
ASSERT_SYS(ENOMEM, -1,
|
||||
madvise((char *)0x83483838000, FRAMESIZE, MADV_WILLNEED));
|
||||
madvise((char *)0x83483838000, __granularity(), MADV_WILLNEED));
|
||||
}
|
||||
|
|
|
@ -85,7 +85,7 @@ TEST(pledge, default_allowsExit) {
|
|||
int *job;
|
||||
int ws, pid;
|
||||
// create small shared memory region
|
||||
ASSERT_NE(-1, (job = mmap(0, FRAMESIZE, PROT_READ | PROT_WRITE,
|
||||
ASSERT_NE(-1, (job = mmap(0, __granularity(), PROT_READ | PROT_WRITE,
|
||||
MAP_SHARED | MAP_ANONYMOUS, -1, 0)));
|
||||
job[0] = 2; // create workload
|
||||
job[1] = 2;
|
||||
|
@ -99,7 +99,7 @@ TEST(pledge, default_allowsExit) {
|
|||
EXPECT_TRUE(WIFEXITED(ws));
|
||||
EXPECT_EQ(0, WEXITSTATUS(ws));
|
||||
EXPECT_EQ(4, job[0]); // check result
|
||||
EXPECT_SYS(0, 0, munmap(job, FRAMESIZE));
|
||||
EXPECT_SYS(0, 0, munmap(job, __granularity()));
|
||||
}
|
||||
|
||||
TEST(pledge, execpromises_notok) {
|
||||
|
@ -297,7 +297,7 @@ TEST(pledge, stdioTty_sendtoRestricted_requiresNullAddr) {
|
|||
errno = 0;
|
||||
// set lower 32-bit word of pointer to zero lool
|
||||
struct sockaddr_in *sin =
|
||||
mmap((void *)0x300000000000, FRAMESIZE, PROT_READ | PROT_WRITE,
|
||||
mmap((void *)0x300000000000, __granularity(), PROT_READ | PROT_WRITE,
|
||||
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
|
||||
sin->sin_family = AF_INET;
|
||||
ASSERT_SYS(
|
||||
|
@ -333,7 +333,7 @@ TEST(pledge, unix_forbidsInetSockets) {
|
|||
TEST(pledge, wpath_doesNotImplyRpath) {
|
||||
int ws, pid;
|
||||
bool *gotsome;
|
||||
ASSERT_NE(-1, (gotsome = _mapshared(FRAMESIZE)));
|
||||
ASSERT_NE(-1, (gotsome = _mapshared(__granularity())));
|
||||
ASSERT_SYS(0, 0, touch("foo", 0644));
|
||||
ASSERT_NE(-1, (pid = fork()));
|
||||
if (!pid) {
|
||||
|
@ -411,13 +411,13 @@ TEST(pledge, mmap) {
|
|||
ASSERT_NE(-1, (pid = fork()));
|
||||
if (!pid) {
|
||||
ASSERT_SYS(0, 0, pledge("stdio", 0));
|
||||
ASSERT_NE(MAP_FAILED, (p = mmap(0, FRAMESIZE, PROT_READ | PROT_WRITE,
|
||||
ASSERT_NE(MAP_FAILED, (p = mmap(0, __granularity(), PROT_READ | PROT_WRITE,
|
||||
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)));
|
||||
ASSERT_SYS(0, 0, mprotect(p, FRAMESIZE, PROT_READ));
|
||||
ASSERT_SYS(0, 0, mprotect(p, __granularity(), PROT_READ));
|
||||
ASSERT_SYS(EPERM, MAP_FAILED,
|
||||
mprotect(p, FRAMESIZE, PROT_READ | PROT_EXEC));
|
||||
mprotect(p, __granularity(), PROT_READ | PROT_EXEC));
|
||||
ASSERT_SYS(EPERM, MAP_FAILED,
|
||||
mmap(0, FRAMESIZE, PROT_EXEC | PROT_READ,
|
||||
mmap(0, __granularity(), PROT_EXEC | PROT_READ,
|
||||
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0));
|
||||
_Exit(0);
|
||||
}
|
||||
|
@ -433,11 +433,11 @@ TEST(pledge, mmapProtExec) {
|
|||
ASSERT_NE(-1, (pid = fork()));
|
||||
if (!pid) {
|
||||
ASSERT_SYS(0, 0, pledge("stdio prot_exec", 0));
|
||||
ASSERT_NE(MAP_FAILED, (p = mmap(0, FRAMESIZE, PROT_READ | PROT_WRITE,
|
||||
ASSERT_NE(MAP_FAILED, (p = mmap(0, __granularity(), PROT_READ | PROT_WRITE,
|
||||
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)));
|
||||
ASSERT_SYS(0, 0, mprotect(p, FRAMESIZE, PROT_READ));
|
||||
ASSERT_SYS(0, 0, mprotect(p, FRAMESIZE, PROT_READ | PROT_EXEC));
|
||||
ASSERT_NE(MAP_FAILED, mmap(0, FRAMESIZE, PROT_EXEC | PROT_READ,
|
||||
ASSERT_SYS(0, 0, mprotect(p, __granularity(), PROT_READ));
|
||||
ASSERT_SYS(0, 0, mprotect(p, __granularity(), PROT_READ | PROT_EXEC));
|
||||
ASSERT_NE(MAP_FAILED, mmap(0, __granularity(), PROT_EXEC | PROT_READ,
|
||||
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0));
|
||||
_Exit(0);
|
||||
}
|
||||
|
|
|
@ -335,7 +335,7 @@ TEST(unveil, isThreadSpecificOnLinux_isProcessWideOnOpenbsd) {
|
|||
TEST(unveil, usedTwice_forbidden_worksWithPledge) {
|
||||
int ws, pid;
|
||||
bool *gotsome;
|
||||
ASSERT_NE(-1, (gotsome = _mapshared(FRAMESIZE)));
|
||||
ASSERT_NE(-1, (gotsome = _mapshared(__granularity())));
|
||||
ASSERT_NE(-1, (pid = fork()));
|
||||
if (!pid) {
|
||||
__pledge_mode = PLEDGE_PENALTY_KILL_PROCESS;
|
||||
|
@ -359,7 +359,7 @@ TEST(unveil, usedTwice_forbidden_worksWithPledge) {
|
|||
ASSERT_TRUE(*gotsome);
|
||||
ASSERT_TRUE(WIFSIGNALED(ws));
|
||||
ASSERT_EQ(IsOpenbsd() ? SIGABRT : SIGSYS, WTERMSIG(ws));
|
||||
EXPECT_SYS(0, 0, munmap(gotsome, FRAMESIZE));
|
||||
EXPECT_SYS(0, 0, munmap(gotsome, __granularity()));
|
||||
}
|
||||
|
||||
TEST(unveil, lotsOfPaths) {
|
||||
|
|
|
@ -8,73 +8,75 @@ TEST_LIBC_INTRIN_SRCS = $(filter %.c,$(TEST_LIBC_INTRIN_FILES))
|
|||
TEST_LIBC_INTRIN_INCS = $(filter %.inc,$(TEST_LIBC_INTRIN_FILES))
|
||||
TEST_LIBC_INTRIN_SRCS_TEST = $(filter %_test.c,$(TEST_LIBC_INTRIN_SRCS))
|
||||
|
||||
TEST_LIBC_INTRIN_OBJS = \
|
||||
TEST_LIBC_INTRIN_OBJS = \
|
||||
$(TEST_LIBC_INTRIN_SRCS:%.c=o/$(MODE)/%.o)
|
||||
|
||||
TEST_LIBC_INTRIN_COMS = \
|
||||
TEST_LIBC_INTRIN_COMS = \
|
||||
$(TEST_LIBC_INTRIN_SRCS:%.c=o/$(MODE)/%)
|
||||
|
||||
TEST_LIBC_INTRIN_BINS = \
|
||||
$(TEST_LIBC_INTRIN_COMS) \
|
||||
TEST_LIBC_INTRIN_BINS = \
|
||||
$(TEST_LIBC_INTRIN_COMS) \
|
||||
$(TEST_LIBC_INTRIN_COMS:%=%.dbg)
|
||||
|
||||
TEST_LIBC_INTRIN_TESTS = \
|
||||
TEST_LIBC_INTRIN_TESTS = \
|
||||
$(TEST_LIBC_INTRIN_SRCS_TEST:%.c=o/$(MODE)/%.ok)
|
||||
|
||||
TEST_LIBC_INTRIN_CHECKS = \
|
||||
TEST_LIBC_INTRIN_CHECKS = \
|
||||
$(TEST_LIBC_INTRIN_SRCS_TEST:%.c=o/$(MODE)/%.runs)
|
||||
|
||||
TEST_LIBC_INTRIN_DIRECTDEPS = \
|
||||
LIBC_CALLS \
|
||||
LIBC_FMT \
|
||||
LIBC_INTRIN \
|
||||
LIBC_LOG \
|
||||
LIBC_MEM \
|
||||
LIBC_NEXGEN32E \
|
||||
LIBC_PROC \
|
||||
LIBC_RUNTIME \
|
||||
LIBC_STDIO \
|
||||
LIBC_STR \
|
||||
LIBC_SYSV \
|
||||
LIBC_SYSV_CALLS \
|
||||
LIBC_THREAD \
|
||||
LIBC_TESTLIB \
|
||||
LIBC_TINYMATH \
|
||||
LIBC_X \
|
||||
TOOL_VIZ_LIB \
|
||||
THIRD_PARTY_COMPILER_RT \
|
||||
THIRD_PARTY_NSYNC
|
||||
TEST_LIBC_INTRIN_DIRECTDEPS = \
|
||||
LIBC_CALLS \
|
||||
LIBC_FMT \
|
||||
LIBC_INTRIN \
|
||||
LIBC_LOG \
|
||||
LIBC_MEM \
|
||||
LIBC_NEXGEN32E \
|
||||
LIBC_PROC \
|
||||
LIBC_RUNTIME \
|
||||
LIBC_STDIO \
|
||||
LIBC_STR \
|
||||
LIBC_SYSV \
|
||||
LIBC_SYSV_CALLS \
|
||||
LIBC_THREAD \
|
||||
LIBC_TESTLIB \
|
||||
LIBC_TINYMATH \
|
||||
LIBC_X \
|
||||
TOOL_VIZ_LIB \
|
||||
THIRD_PARTY_COMPILER_RT \
|
||||
THIRD_PARTY_NSYNC \
|
||||
THIRD_PARTY_XED
|
||||
|
||||
TEST_LIBC_INTRIN_DEPS := \
|
||||
TEST_LIBC_INTRIN_DEPS := \
|
||||
$(call uniq,$(foreach x,$(TEST_LIBC_INTRIN_DIRECTDEPS),$($(x))))
|
||||
|
||||
o/$(MODE)/test/libc/intrin/intrin.pkg: \
|
||||
$(TEST_LIBC_INTRIN_OBJS) \
|
||||
o/$(MODE)/test/libc/intrin/intrin.pkg: \
|
||||
$(TEST_LIBC_INTRIN_OBJS) \
|
||||
$(foreach x,$(TEST_LIBC_INTRIN_DIRECTDEPS),$($(x)_A).pkg)
|
||||
|
||||
o/$(MODE)/test/libc/intrin/%.dbg: \
|
||||
$(TEST_LIBC_INTRIN_DEPS) \
|
||||
o/$(MODE)/test/libc/intrin/%.o \
|
||||
o/$(MODE)/test/libc/intrin/intrin.pkg \
|
||||
$(LIBC_TESTMAIN) \
|
||||
$(CRT) \
|
||||
o/$(MODE)/test/libc/intrin/%.dbg: \
|
||||
$(TEST_LIBC_INTRIN_DEPS) \
|
||||
o/$(MODE)/test/libc/intrin/%.o \
|
||||
o/$(MODE)/test/libc/intrin/intrin.pkg \
|
||||
o/$(MODE)/test/libc/mem/prog/life.elf.zip.o \
|
||||
$(LIBC_TESTMAIN) \
|
||||
$(CRT) \
|
||||
$(APE_NO_MODIFY_SELF)
|
||||
@$(APELINK)
|
||||
|
||||
# Test what happens when *NSYNC isn't linked.
|
||||
o/$(MODE)/test/libc/intrin/lock_test.dbg: \
|
||||
$(TEST_LIBC_INTRIN_DEPS) \
|
||||
o/$(MODE)/test/libc/intrin/lock_test.o \
|
||||
o/$(MODE)/test/libc/intrin/intrin.pkg \
|
||||
$(CRT) \
|
||||
o/$(MODE)/test/libc/intrin/lock_test.dbg: \
|
||||
$(TEST_LIBC_INTRIN_DEPS) \
|
||||
o/$(MODE)/test/libc/intrin/lock_test.o \
|
||||
o/$(MODE)/test/libc/intrin/intrin.pkg \
|
||||
$(CRT) \
|
||||
$(APE_NO_MODIFY_SELF)
|
||||
@$(APELINK)
|
||||
|
||||
$(TEST_LIBC_INTRIN_OBJS): private \
|
||||
CFLAGS += \
|
||||
$(TEST_LIBC_INTRIN_OBJS): private \
|
||||
CFLAGS += \
|
||||
-fno-builtin
|
||||
|
||||
.PHONY: o/$(MODE)/test/libc/intrin
|
||||
o/$(MODE)/test/libc/intrin: \
|
||||
$(TEST_LIBC_INTRIN_BINS) \
|
||||
o/$(MODE)/test/libc/intrin: \
|
||||
$(TEST_LIBC_INTRIN_BINS) \
|
||||
$(TEST_LIBC_INTRIN_CHECKS)
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "libc/calls/calls.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/log/libfatal.internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
|
@ -56,7 +57,6 @@ static const struct {
|
|||
uintptr_t arg1;
|
||||
uintptr_t arg2;
|
||||
} V[] = {
|
||||
{"!!WONTFMT", (const char *)31337, 123}, //
|
||||
{"!!31337", "%s", 0x31337}, //
|
||||
{"!!1", "%#s", 1}, //
|
||||
{"!!feff800000031337", "%s", 0xfeff800000031337ull}, //
|
||||
|
@ -226,9 +226,9 @@ TEST(ksnprintf, fuzzTheUnbreakable) {
|
|||
size_t i;
|
||||
uint64_t x;
|
||||
char *f, b[32];
|
||||
_Alignas(FRAMESIZE) static const char weasel[FRAMESIZE];
|
||||
_Alignas(65536) static const char weasel[65535];
|
||||
f = (void *)__veil("r", weasel);
|
||||
EXPECT_SYS(0, 0, mprotect(f, FRAMESIZE, PROT_READ | PROT_WRITE));
|
||||
EXPECT_SYS(0, 0, mprotect(f, __granularity(), PROT_READ | PROT_WRITE));
|
||||
strcpy(f, "hello %s\n");
|
||||
EXPECT_EQ(12, ksnprintf(b, sizeof(b), f, "world"));
|
||||
EXPECT_STREQ("hello world\n", b);
|
||||
|
@ -240,7 +240,7 @@ TEST(ksnprintf, fuzzTheUnbreakable) {
|
|||
f[Rando() & 15] = '%';
|
||||
ksnprintf(b, sizeof(b), f, lemur64(), lemur64(), lemur64());
|
||||
}
|
||||
EXPECT_SYS(0, 0, mprotect(f, FRAMESIZE, PROT_READ));
|
||||
EXPECT_SYS(0, 0, mprotect(f, __granularity(), PROT_READ));
|
||||
}
|
||||
|
||||
TEST(kprintf, testFailure_wontClobberErrnoAndBypassesSystemCallSupport) {
|
||||
|
@ -267,13 +267,6 @@ TEST(ksnprintf, testy) {
|
|||
EXPECT_STREQ("!!1", b);
|
||||
}
|
||||
|
||||
TEST(ksnprintf, testNonTextFmt_wontFormat) {
|
||||
char b[32];
|
||||
char variable_format_string[16] = "%s";
|
||||
EXPECT_EQ(9, ksnprintf(b, 32, variable_format_string, NULL));
|
||||
EXPECT_STREQ("!!WONTFMT", b);
|
||||
}
|
||||
|
||||
TEST(ksnprintf, testMisalignedPointer_wontFormat) {
|
||||
char b[32];
|
||||
const char16_t *s = u"hello";
|
||||
|
@ -284,11 +277,12 @@ TEST(ksnprintf, testMisalignedPointer_wontFormat) {
|
|||
TEST(ksnprintf, testUnterminatedOverrun_truncatesAtPageBoundary) {
|
||||
char *m;
|
||||
char b[32];
|
||||
m = memset(_mapanon(FRAMESIZE * 2), 1, FRAMESIZE);
|
||||
EXPECT_SYS(0, 0, munmap(m + FRAMESIZE, FRAMESIZE));
|
||||
EXPECT_EQ(12, ksnprintf(b, 32, "%'s", m + FRAMESIZE - 3));
|
||||
int gran = __granularity();
|
||||
m = memset(_mapanon(gran * 2), 1, gran);
|
||||
EXPECT_SYS(0, 0, munmap(m + gran, gran));
|
||||
EXPECT_EQ(12, ksnprintf(b, 32, "%'s", m + gran - 3));
|
||||
EXPECT_STREQ("\\001\\001\\001", b);
|
||||
EXPECT_SYS(0, 0, munmap(m, FRAMESIZE));
|
||||
EXPECT_SYS(0, 0, munmap(m, gran));
|
||||
}
|
||||
|
||||
TEST(ksnprintf, testEmptyBuffer_determinesTrueLength) {
|
||||
|
|
|
@ -47,7 +47,7 @@ TEST(lockipc, mutex) {
|
|||
int e, rc, ws, pid;
|
||||
|
||||
// create shared memory
|
||||
shm = _mapshared(FRAMESIZE);
|
||||
shm = _mapshared(__granularity());
|
||||
|
||||
// create shared mutex
|
||||
pthread_mutexattr_t mattr;
|
||||
|
@ -86,5 +86,5 @@ TEST(lockipc, mutex) {
|
|||
|
||||
EXPECT_EQ(PROCESSES * ITERATIONS, shm->x);
|
||||
ASSERT_EQ(0, pthread_mutex_destroy(&shm->mutex));
|
||||
ASSERT_SYS(0, 0, munmap(shm, FRAMESIZE));
|
||||
ASSERT_SYS(0, 0, munmap(shm, __granularity()));
|
||||
}
|
||||
|
|
|
@ -18,15 +18,18 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "ape/sections.internal.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/calls/ucontext.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/intrin/atomic.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/intrin/safemacros.internal.h"
|
||||
#include "libc/intrin/xchg.internal.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/mem/gc.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/memtrack.internal.h"
|
||||
|
@ -48,9 +51,20 @@
|
|||
#include "libc/x/xspawn.h"
|
||||
#include "third_party/xed/x86.h"
|
||||
|
||||
// this is also a good torture test for mmap
|
||||
//
|
||||
// make -j o//test/libc/intrin/pthread_mutex_lock2_test
|
||||
// for i in $(seq 100); do
|
||||
// o//test/libc/intrin/pthread_mutex_lock2_test &
|
||||
// done
|
||||
//
|
||||
|
||||
__static_yoink("zipos");
|
||||
|
||||
int granularity;
|
||||
|
||||
void SetUpOnce(void) {
|
||||
granularity = __granularity();
|
||||
testlib_enable_tmp_setup_teardown();
|
||||
// ASSERT_SYS(0, 0, pledge("stdio rpath wpath cpath proc", 0));
|
||||
}
|
||||
|
@ -61,34 +75,63 @@ TEST(mmap, zeroSize) {
|
|||
}
|
||||
|
||||
TEST(mmap, overflow) {
|
||||
ASSERT_SYS(EINVAL, MAP_FAILED,
|
||||
ASSERT_SYS(ENOMEM, MAP_FAILED,
|
||||
mmap(NULL, 0x800000000000, PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE,
|
||||
-1, 0));
|
||||
ASSERT_SYS(EINVAL, MAP_FAILED,
|
||||
ASSERT_SYS(ENOMEM, MAP_FAILED,
|
||||
mmap(NULL, 0x7fffffffffff, PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE,
|
||||
-1, 0));
|
||||
}
|
||||
|
||||
TEST(mmap, outOfAutomapRange) {
|
||||
ASSERT_SYS(
|
||||
ENOMEM, MAP_FAILED,
|
||||
mmap(NULL, kAutomapSize, PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0));
|
||||
}
|
||||
|
||||
TEST(mmap, noreplaceImage) {
|
||||
ASSERT_SYS(EEXIST, MAP_FAILED,
|
||||
mmap(__executable_start, FRAMESIZE, PROT_READ,
|
||||
mmap(__executable_start, granularity, PROT_READ,
|
||||
MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED_NOREPLACE, -1, 0));
|
||||
}
|
||||
|
||||
TEST(mmap, noreplaceExistingMap) {
|
||||
char *p;
|
||||
ASSERT_NE(MAP_FAILED, (p = mmap(0, FRAMESIZE, PROT_READ,
|
||||
ASSERT_NE(MAP_FAILED, (p = mmap(0, granularity, PROT_READ,
|
||||
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)));
|
||||
ASSERT_SYS(EEXIST, MAP_FAILED,
|
||||
mmap(p, FRAMESIZE, PROT_READ,
|
||||
mmap(p, granularity, PROT_READ,
|
||||
MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED_NOREPLACE, -1, 0));
|
||||
EXPECT_SYS(0, 0, munmap(p, FRAMESIZE));
|
||||
EXPECT_SYS(0, 0, munmap(p, granularity));
|
||||
}
|
||||
|
||||
TEST(mmap, hint) {
|
||||
char *p, *q;
|
||||
|
||||
// obtain four pages
|
||||
EXPECT_NE(MAP_FAILED, (p = mmap(NULL, granularity * 4, PROT_READ,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)));
|
||||
|
||||
// unmap two of those pages
|
||||
EXPECT_SYS(0, 0, munmap(p + granularity, granularity));
|
||||
EXPECT_SYS(0, 0, munmap(p + granularity * 3, granularity));
|
||||
|
||||
// test AVAILABLE nonfixed nonzero addr is granted
|
||||
// - posix doesn't mandate this behavior (but should)
|
||||
// - freebsd always chooses for you (which has no acceptable workaround)
|
||||
// - netbsd manual claims it'll be like freebsd, but is actually like openbsd
|
||||
if (!IsFreebsd())
|
||||
EXPECT_EQ(p + granularity, mmap(p + granularity, granularity, PROT_READ,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
|
||||
|
||||
// test UNAVAILABLE nonfixed nonzero addr picks something nearby
|
||||
// - posix actually does require this, but doesn't say how close
|
||||
// - xnu / linux / openbsd always choose nearest on the right
|
||||
// - freebsd goes about 16mb to the right
|
||||
// - qemu-user is off the wall
|
||||
if (!IsQemuUser()) {
|
||||
q = mmap(p + granularity * 2, granularity, PROT_READ,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
EXPECT_LE(ABS(q - (p + granularity * 2)), 64 * 1024 * 1024);
|
||||
EXPECT_SYS(0, 0, munmap(q, granularity));
|
||||
}
|
||||
|
||||
// clean up
|
||||
EXPECT_SYS(0, 0, munmap(p, granularity * 4));
|
||||
}
|
||||
|
||||
TEST(mmap, smallerThanPage_mapsRemainder) {
|
||||
|
@ -150,47 +193,10 @@ TEST(mmap, testMapFile_fdGetsClosed_makesNoDifference) {
|
|||
EXPECT_NE(-1, unlink(path));
|
||||
}
|
||||
|
||||
TEST(mmap, testMapFixed_destroysEverythingInItsPath) {
|
||||
unsigned m1 = _mmi.i;
|
||||
EXPECT_NE(MAP_FAILED, mmap((void *)(kFixedmapStart + FRAMESIZE * 0),
|
||||
FRAMESIZE, PROT_READ | PROT_WRITE,
|
||||
MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
|
||||
EXPECT_NE(MAP_FAILED, mmap((void *)(kFixedmapStart + FRAMESIZE * 1),
|
||||
FRAMESIZE, PROT_READ | PROT_WRITE,
|
||||
MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
|
||||
EXPECT_NE(MAP_FAILED, mmap((void *)(kFixedmapStart + FRAMESIZE * 2),
|
||||
FRAMESIZE, PROT_READ | PROT_WRITE,
|
||||
MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
|
||||
EXPECT_NE(MAP_FAILED, mmap((void *)(kFixedmapStart + FRAMESIZE * 0),
|
||||
FRAMESIZE * 3, PROT_READ | PROT_WRITE,
|
||||
MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
|
||||
ASSERT_GT(_mmi.i, m1);
|
||||
EXPECT_NE(-1, munmap((void *)kFixedmapStart, FRAMESIZE * 3));
|
||||
}
|
||||
|
||||
#ifdef __x86_64__
|
||||
TEST(mmap, customStackMemory_isAuthorized) {
|
||||
char *stack;
|
||||
uintptr_t w, r;
|
||||
ASSERT_NE(MAP_FAILED,
|
||||
(stack = mmap(NULL, GetStackSize(), PROT_READ | PROT_WRITE,
|
||||
MAP_ANONYMOUS | MAP_STACK, -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 + GetStackSize() - 8), "i"(123));
|
||||
ASSERT_EQ(123, r);
|
||||
EXPECT_SYS(0, 0, munmap(stack, GetStackSize()));
|
||||
}
|
||||
#endif /* __x86_64__ */
|
||||
|
||||
TEST(mmap, fileOffset) {
|
||||
int fd;
|
||||
char *map;
|
||||
int offset_align = IsWindows() ? FRAMESIZE : getauxval(AT_PAGESZ);
|
||||
int offset_align = IsWindows() ? granularity : getauxval(AT_PAGESZ);
|
||||
ASSERT_NE(-1, (fd = open("foo", O_CREAT | O_RDWR, 0644)));
|
||||
EXPECT_NE(-1, ftruncate(fd, offset_align * 2));
|
||||
EXPECT_NE(-1, pwrite(fd, "hello", 5, offset_align * 0));
|
||||
|
@ -207,65 +213,26 @@ TEST(mmap, mapPrivate_writesDontChangeFile) {
|
|||
int fd;
|
||||
char *map, buf[6];
|
||||
ASSERT_NE(-1, (fd = open("bar", O_CREAT | O_RDWR, 0644)));
|
||||
EXPECT_NE(-1, ftruncate(fd, FRAMESIZE));
|
||||
EXPECT_NE(-1, ftruncate(fd, granularity));
|
||||
EXPECT_NE(-1, pwrite(fd, "hello", 5, 0));
|
||||
ASSERT_NE(MAP_FAILED, (map = mmap(NULL, FRAMESIZE, PROT_READ | PROT_WRITE,
|
||||
ASSERT_NE(MAP_FAILED, (map = mmap(NULL, granularity, PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE, fd, 0)));
|
||||
memcpy(map, "there", 5);
|
||||
EXPECT_NE(-1, msync(map, FRAMESIZE, MS_SYNC));
|
||||
EXPECT_NE(-1, munmap(map, FRAMESIZE));
|
||||
EXPECT_NE(-1, msync(map, granularity, MS_SYNC));
|
||||
EXPECT_NE(-1, munmap(map, granularity));
|
||||
EXPECT_NE(-1, pread(fd, buf, 6, 0));
|
||||
EXPECT_EQ(0, memcmp(buf, "hello", 5), "%#.*s", 5, buf);
|
||||
EXPECT_NE(-1, close(fd));
|
||||
}
|
||||
|
||||
TEST(mmap, twoPowerSize_automapsAddressWithThatAlignment) {
|
||||
char *q, *p;
|
||||
// increase the likelihood automap is unaligned w.r.t. following call
|
||||
ASSERT_NE(MAP_FAILED, (q = mmap(NULL, 0x00010000, PROT_READ | PROT_WRITE,
|
||||
MAP_SHARED | MAP_ANONYMOUS, -1, 0)));
|
||||
// ask for a nice big round size
|
||||
ASSERT_NE(MAP_FAILED, (p = mmap(NULL, 0x00080000, PROT_READ | PROT_WRITE,
|
||||
MAP_SHARED | MAP_ANONYMOUS, -1, 0)));
|
||||
// verify it's aligned
|
||||
ASSERT_EQ(0, (intptr_t)p & 0x0007ffff);
|
||||
EXPECT_SYS(0, 0, munmap(p, 0x00080000));
|
||||
}
|
||||
|
||||
TEST(isheap, nullPtr) {
|
||||
ASSERT_FALSE(_isheap(NULL));
|
||||
}
|
||||
|
||||
TEST(isheap, malloc) {
|
||||
ASSERT_TRUE(_isheap(gc(malloc(1))));
|
||||
}
|
||||
|
||||
/* TEST(isheap, emptyMalloc) { */
|
||||
/* ASSERT_TRUE(_isheap(gc(malloc(0)))); */
|
||||
/* } */
|
||||
|
||||
/* TEST(isheap, mallocOffset) { */
|
||||
/* char *p = gc(malloc(131072)); */
|
||||
/* ASSERT_TRUE(_isheap(p + 100000)); */
|
||||
/* } */
|
||||
|
||||
static const char *ziposLifePath = "/zip/life.elf";
|
||||
TEST(mmap, ziposCannotBeAnonymous) {
|
||||
int fd;
|
||||
void *p;
|
||||
ASSERT_NE(-1, (fd = open(ziposLifePath, O_RDONLY), "%s", ziposLifePath));
|
||||
EXPECT_SYS(EINVAL, MAP_FAILED,
|
||||
(p = mmap(NULL, 0x00010000, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS,
|
||||
fd, 0)));
|
||||
close(fd);
|
||||
}
|
||||
|
||||
TEST(mmap, ziposCannotBeShared) {
|
||||
int fd;
|
||||
void *p;
|
||||
ASSERT_NE(-1, (fd = open(ziposLifePath, O_RDONLY), "%s", ziposLifePath));
|
||||
EXPECT_SYS(EINVAL, MAP_FAILED,
|
||||
(p = mmap(NULL, 0x00010000, PROT_READ, MAP_SHARED, fd, 0)));
|
||||
(p = mmap(NULL, granularity, PROT_READ, MAP_SHARED, fd, 0)));
|
||||
close(fd);
|
||||
}
|
||||
|
||||
|
@ -277,9 +244,9 @@ TEST(mmap, ziposCow) {
|
|||
void *p;
|
||||
ASSERT_NE(-1, (fd = open(ziposLifePath, O_RDONLY), "%s", ziposLifePath));
|
||||
EXPECT_NE(MAP_FAILED,
|
||||
(p = mmap(NULL, 0x00010000, PROT_READ, MAP_PRIVATE, fd, 0)));
|
||||
(p = mmap(NULL, granularity, PROT_READ, MAP_PRIVATE, fd, 0)));
|
||||
EXPECT_STREQN("\177ELF", ((const char *)p), 4);
|
||||
EXPECT_NE(-1, munmap(p, 0x00010000));
|
||||
EXPECT_NE(-1, munmap(p, granularity));
|
||||
EXPECT_NE(-1, close(fd));
|
||||
}
|
||||
|
||||
|
@ -467,19 +434,20 @@ TEST(mmap, sharedFileMapFork) {
|
|||
int count;
|
||||
void *ptrs[N];
|
||||
|
||||
void BenchUnmap(void) {
|
||||
ASSERT_EQ(0, munmap(ptrs[count++], FRAMESIZE));
|
||||
}
|
||||
|
||||
void BenchMmapPrivate(void) {
|
||||
void *p;
|
||||
p = mmap(0, FRAMESIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE,
|
||||
p = mmap(0, granularity, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE,
|
||||
-1, 0);
|
||||
if (p == MAP_FAILED)
|
||||
abort();
|
||||
__builtin_trap();
|
||||
ptrs[count++] = p;
|
||||
}
|
||||
|
||||
void BenchUnmap(void) {
|
||||
if (munmap(ptrs[--count], granularity))
|
||||
__builtin_trap();
|
||||
}
|
||||
|
||||
BENCH(mmap, bench) {
|
||||
EZBENCH2("mmap", donothing, BenchMmapPrivate());
|
||||
EZBENCH2("munmap", donothing, BenchUnmap());
|
|
@ -148,18 +148,18 @@ TEST(mprotect, testSegfault_writeToReadOnlyAnonymous) {
|
|||
}
|
||||
|
||||
TEST(mprotect, testExecOnly_canExecute) {
|
||||
char *p = _mapanon(FRAMESIZE);
|
||||
char *p = _mapanon(__granularity());
|
||||
void (*f)(void) = (void *)p;
|
||||
memcpy(p, kRet31337, sizeof(kRet31337));
|
||||
ASSERT_SYS(0, 0, mprotect(p, FRAMESIZE, PROT_EXEC | PROT_READ));
|
||||
ASSERT_SYS(0, 0, mprotect(p, __granularity(), PROT_EXEC | PROT_READ));
|
||||
f();
|
||||
// On all supported platforms, PROT_EXEC implies PROT_READ. There is
|
||||
// one exception to this rule: Chromebook's fork of the Linux kernel
|
||||
// which has been reported, to have the ability to prevent a program
|
||||
// from reading its own code.
|
||||
ASSERT_SYS(0, 0, mprotect(p, FRAMESIZE, PROT_EXEC));
|
||||
ASSERT_SYS(0, 0, mprotect(p, __granularity(), PROT_EXEC));
|
||||
f();
|
||||
munmap(p, FRAMESIZE);
|
||||
munmap(p, __granularity());
|
||||
}
|
||||
|
||||
TEST(mprotect, testProtNone_cantEvenRead) {
|
||||
|
@ -243,3 +243,12 @@ TEST(mprotect, testZeroSize_doesNothing) {
|
|||
EXPECT_FALSE(gotsegv);
|
||||
EXPECT_FALSE(gotbusted);
|
||||
}
|
||||
|
||||
TEST(mprotect, image) {
|
||||
_Alignas(16384) static const char lol[16384] = {1, 2, 3};
|
||||
intptr_t i = (intptr_t)lol;
|
||||
asm("" : "+r"(i));
|
||||
char *p = (char *)i;
|
||||
EXPECT_SYS(0, 0, mprotect(p, 16384, PROT_READ | PROT_WRITE));
|
||||
EXPECT_EQ(2, ++p[0]);
|
||||
}
|
|
@ -26,12 +26,15 @@
|
|||
#include "libc/sysv/consts/prot.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
|
||||
int granularity;
|
||||
|
||||
void SetUpOnce(void) {
|
||||
granularity = __granularity();
|
||||
testlib_enable_tmp_setup_teardown();
|
||||
}
|
||||
|
||||
TEST(munmap, doesntExist_doesntCare) {
|
||||
EXPECT_SYS(0, 0, munmap(0, FRAMESIZE * 8));
|
||||
EXPECT_SYS(0, 0, munmap(0, granularity * 8));
|
||||
if (IsAsan()) {
|
||||
// make sure it didn't unmap the null pointer shadow memory
|
||||
EXPECT_TRUE(testlib_memoryexists((char *)0x7fff8000));
|
||||
|
@ -41,112 +44,112 @@ TEST(munmap, doesntExist_doesntCare) {
|
|||
TEST(munmap, invalidParams) {
|
||||
EXPECT_SYS(EINVAL, -1, munmap(0, 0));
|
||||
EXPECT_SYS(EINVAL, -1, munmap((void *)0x100080000000, 0));
|
||||
EXPECT_SYS(EINVAL, -1, munmap((void *)0x100080000001, FRAMESIZE));
|
||||
EXPECT_SYS(EINVAL, -1, munmap((void *)0x100080000001, granularity));
|
||||
}
|
||||
|
||||
TEST(munmap, test) {
|
||||
char *p;
|
||||
ASSERT_NE(MAP_FAILED, (p = mmap(0, FRAMESIZE, PROT_READ | PROT_WRITE,
|
||||
ASSERT_NE(MAP_FAILED, (p = mmap(0, granularity, PROT_READ | PROT_WRITE,
|
||||
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)));
|
||||
EXPECT_TRUE(testlib_memoryexists(p));
|
||||
EXPECT_SYS(0, 0, munmap(p, FRAMESIZE));
|
||||
EXPECT_SYS(0, 0, munmap(p, granularity));
|
||||
EXPECT_FALSE(testlib_memoryexists(p));
|
||||
}
|
||||
|
||||
TEST(munmap, punchHoleInMemory) {
|
||||
char *p;
|
||||
ASSERT_NE(MAP_FAILED, (p = mmap(0, FRAMESIZE * 3, PROT_READ | PROT_WRITE,
|
||||
ASSERT_NE(MAP_FAILED, (p = mmap(0, granularity * 3, PROT_READ | PROT_WRITE,
|
||||
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)));
|
||||
EXPECT_TRUE(testlib_memoryexists(p + FRAMESIZE * 0));
|
||||
EXPECT_TRUE(testlib_memoryexists(p + FRAMESIZE * 1));
|
||||
EXPECT_TRUE(testlib_memoryexists(p + FRAMESIZE * 2));
|
||||
EXPECT_SYS(0, 0, munmap(p + FRAMESIZE, FRAMESIZE));
|
||||
EXPECT_TRUE(testlib_memoryexists(p + FRAMESIZE * 0));
|
||||
EXPECT_FALSE(testlib_memoryexists(p + FRAMESIZE * 1));
|
||||
EXPECT_TRUE(testlib_memoryexists(p + FRAMESIZE * 2));
|
||||
EXPECT_SYS(0, 0, munmap(p, FRAMESIZE));
|
||||
EXPECT_SYS(0, 0, munmap(p + FRAMESIZE * 2, FRAMESIZE));
|
||||
EXPECT_FALSE(testlib_memoryexists(p + FRAMESIZE * 0));
|
||||
EXPECT_FALSE(testlib_memoryexists(p + FRAMESIZE * 1));
|
||||
EXPECT_FALSE(testlib_memoryexists(p + FRAMESIZE * 2));
|
||||
EXPECT_TRUE(testlib_memoryexists(p + granularity * 0));
|
||||
EXPECT_TRUE(testlib_memoryexists(p + granularity * 1));
|
||||
EXPECT_TRUE(testlib_memoryexists(p + granularity * 2));
|
||||
EXPECT_SYS(0, 0, munmap(p + granularity, granularity));
|
||||
EXPECT_TRUE(testlib_memoryexists(p + granularity * 0));
|
||||
EXPECT_FALSE(testlib_memoryexists(p + granularity * 1));
|
||||
EXPECT_TRUE(testlib_memoryexists(p + granularity * 2));
|
||||
EXPECT_SYS(0, 0, munmap(p, granularity));
|
||||
EXPECT_SYS(0, 0, munmap(p + granularity * 2, granularity));
|
||||
EXPECT_FALSE(testlib_memoryexists(p + granularity * 0));
|
||||
EXPECT_FALSE(testlib_memoryexists(p + granularity * 1));
|
||||
EXPECT_FALSE(testlib_memoryexists(p + granularity * 2));
|
||||
}
|
||||
|
||||
TEST(munmap, memoryHasHole) {
|
||||
char *p;
|
||||
ASSERT_NE(MAP_FAILED, (p = mmap(0, FRAMESIZE * 3, PROT_READ | PROT_WRITE,
|
||||
ASSERT_NE(MAP_FAILED, (p = mmap(0, granularity * 3, PROT_READ | PROT_WRITE,
|
||||
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)));
|
||||
EXPECT_SYS(0, 0, munmap(p + FRAMESIZE, FRAMESIZE));
|
||||
EXPECT_TRUE(testlib_memoryexists(p + FRAMESIZE * 0));
|
||||
EXPECT_FALSE(testlib_memoryexists(p + FRAMESIZE * 1));
|
||||
EXPECT_TRUE(testlib_memoryexists(p + FRAMESIZE * 2));
|
||||
EXPECT_SYS(0, 0, munmap(p, FRAMESIZE * 3));
|
||||
EXPECT_FALSE(testlib_memoryexists(p + FRAMESIZE * 0));
|
||||
EXPECT_FALSE(testlib_memoryexists(p + FRAMESIZE * 1));
|
||||
EXPECT_FALSE(testlib_memoryexists(p + FRAMESIZE * 2));
|
||||
EXPECT_SYS(0, 0, munmap(p + granularity, granularity));
|
||||
EXPECT_TRUE(testlib_memoryexists(p + granularity * 0));
|
||||
EXPECT_FALSE(testlib_memoryexists(p + granularity * 1));
|
||||
EXPECT_TRUE(testlib_memoryexists(p + granularity * 2));
|
||||
EXPECT_SYS(0, 0, munmap(p, granularity * 3));
|
||||
EXPECT_FALSE(testlib_memoryexists(p + granularity * 0));
|
||||
EXPECT_FALSE(testlib_memoryexists(p + granularity * 1));
|
||||
EXPECT_FALSE(testlib_memoryexists(p + granularity * 2));
|
||||
}
|
||||
|
||||
TEST(munmap, blanketFree) {
|
||||
char *p;
|
||||
ASSERT_NE(MAP_FAILED, (p = mmap(0, FRAMESIZE * 3, PROT_READ | PROT_WRITE,
|
||||
ASSERT_NE(MAP_FAILED, (p = mmap(0, granularity * 3, PROT_READ | PROT_WRITE,
|
||||
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)));
|
||||
EXPECT_TRUE(testlib_memoryexists(p + FRAMESIZE * 0));
|
||||
EXPECT_TRUE(testlib_memoryexists(p + FRAMESIZE * 1));
|
||||
EXPECT_TRUE(testlib_memoryexists(p + FRAMESIZE * 2));
|
||||
EXPECT_SYS(0, 0, munmap(p + FRAMESIZE * 0, FRAMESIZE));
|
||||
EXPECT_SYS(0, 0, munmap(p + FRAMESIZE * 2, FRAMESIZE));
|
||||
EXPECT_FALSE(testlib_memoryexists(p + FRAMESIZE * 0));
|
||||
EXPECT_TRUE(testlib_memoryexists(p + FRAMESIZE * 1));
|
||||
EXPECT_FALSE(testlib_memoryexists(p + FRAMESIZE * 2));
|
||||
EXPECT_SYS(0, 0, munmap(p, FRAMESIZE * 3));
|
||||
EXPECT_FALSE(testlib_memoryexists(p + FRAMESIZE * 0));
|
||||
EXPECT_FALSE(testlib_memoryexists(p + FRAMESIZE * 1));
|
||||
EXPECT_FALSE(testlib_memoryexists(p + FRAMESIZE * 2));
|
||||
EXPECT_TRUE(testlib_memoryexists(p + granularity * 0));
|
||||
EXPECT_TRUE(testlib_memoryexists(p + granularity * 1));
|
||||
EXPECT_TRUE(testlib_memoryexists(p + granularity * 2));
|
||||
EXPECT_SYS(0, 0, munmap(p + granularity * 0, granularity));
|
||||
EXPECT_SYS(0, 0, munmap(p + granularity * 2, granularity));
|
||||
EXPECT_FALSE(testlib_memoryexists(p + granularity * 0));
|
||||
EXPECT_TRUE(testlib_memoryexists(p + granularity * 1));
|
||||
EXPECT_FALSE(testlib_memoryexists(p + granularity * 2));
|
||||
EXPECT_SYS(0, 0, munmap(p, granularity * 3));
|
||||
EXPECT_FALSE(testlib_memoryexists(p + granularity * 0));
|
||||
EXPECT_FALSE(testlib_memoryexists(p + granularity * 1));
|
||||
EXPECT_FALSE(testlib_memoryexists(p + granularity * 2));
|
||||
}
|
||||
|
||||
TEST(munmap, trimLeft) {
|
||||
char *p;
|
||||
ASSERT_NE(MAP_FAILED, (p = mmap(0, FRAMESIZE * 2, PROT_READ | PROT_WRITE,
|
||||
ASSERT_NE(MAP_FAILED, (p = mmap(0, granularity * 2, PROT_READ | PROT_WRITE,
|
||||
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)));
|
||||
EXPECT_TRUE(testlib_memoryexists(p + FRAMESIZE * 0));
|
||||
EXPECT_TRUE(testlib_memoryexists(p + FRAMESIZE * 1));
|
||||
EXPECT_SYS(0, 0, munmap(p, FRAMESIZE));
|
||||
EXPECT_FALSE(testlib_memoryexists(p + FRAMESIZE * 0));
|
||||
EXPECT_TRUE(testlib_memoryexists(p + FRAMESIZE * 1));
|
||||
EXPECT_SYS(0, 0, munmap(p, FRAMESIZE * 2));
|
||||
EXPECT_FALSE(testlib_memoryexists(p + FRAMESIZE * 0));
|
||||
EXPECT_FALSE(testlib_memoryexists(p + FRAMESIZE * 1));
|
||||
EXPECT_TRUE(testlib_memoryexists(p + granularity * 0));
|
||||
EXPECT_TRUE(testlib_memoryexists(p + granularity * 1));
|
||||
EXPECT_SYS(0, 0, munmap(p, granularity));
|
||||
EXPECT_FALSE(testlib_memoryexists(p + granularity * 0));
|
||||
EXPECT_TRUE(testlib_memoryexists(p + granularity * 1));
|
||||
EXPECT_SYS(0, 0, munmap(p, granularity * 2));
|
||||
EXPECT_FALSE(testlib_memoryexists(p + granularity * 0));
|
||||
EXPECT_FALSE(testlib_memoryexists(p + granularity * 1));
|
||||
}
|
||||
|
||||
TEST(munmap, trimRight) {
|
||||
char *p;
|
||||
ASSERT_NE(MAP_FAILED, (p = mmap(0, FRAMESIZE * 2, PROT_READ | PROT_WRITE,
|
||||
ASSERT_NE(MAP_FAILED, (p = mmap(0, granularity * 2, PROT_READ | PROT_WRITE,
|
||||
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)));
|
||||
EXPECT_TRUE(testlib_memoryexists(p + FRAMESIZE * 0));
|
||||
EXPECT_TRUE(testlib_memoryexists(p + FRAMESIZE * 1));
|
||||
EXPECT_SYS(0, 0, munmap(p + FRAMESIZE, FRAMESIZE));
|
||||
EXPECT_TRUE(testlib_memoryexists(p + FRAMESIZE * 0));
|
||||
EXPECT_FALSE(testlib_memoryexists(p + FRAMESIZE * 1));
|
||||
EXPECT_SYS(0, 0, munmap(p, FRAMESIZE * 2));
|
||||
EXPECT_FALSE(testlib_memoryexists(p + FRAMESIZE * 0));
|
||||
EXPECT_FALSE(testlib_memoryexists(p + FRAMESIZE * 1));
|
||||
EXPECT_TRUE(testlib_memoryexists(p + granularity * 0));
|
||||
EXPECT_TRUE(testlib_memoryexists(p + granularity * 1));
|
||||
EXPECT_SYS(0, 0, munmap(p + granularity, granularity));
|
||||
EXPECT_TRUE(testlib_memoryexists(p + granularity * 0));
|
||||
EXPECT_FALSE(testlib_memoryexists(p + granularity * 1));
|
||||
EXPECT_SYS(0, 0, munmap(p, granularity * 2));
|
||||
EXPECT_FALSE(testlib_memoryexists(p + granularity * 0));
|
||||
EXPECT_FALSE(testlib_memoryexists(p + granularity * 1));
|
||||
}
|
||||
|
||||
TEST(munmap, memoryGone) {
|
||||
char *p;
|
||||
ASSERT_NE(MAP_FAILED, (p = mmap(0, FRAMESIZE, PROT_READ | PROT_WRITE,
|
||||
ASSERT_NE(MAP_FAILED, (p = mmap(0, granularity, PROT_READ | PROT_WRITE,
|
||||
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)));
|
||||
EXPECT_SYS(0, 0, munmap(p, FRAMESIZE));
|
||||
EXPECT_SYS(0, 0, munmap(p, FRAMESIZE));
|
||||
EXPECT_SYS(0, 0, munmap(p, granularity));
|
||||
EXPECT_SYS(0, 0, munmap(p, granularity));
|
||||
}
|
||||
|
||||
TEST(munmap, testTooSmallToUnmapAsan) {
|
||||
if (!IsAsan())
|
||||
return;
|
||||
char *p;
|
||||
ASSERT_NE(MAP_FAILED, (p = mmap(0, FRAMESIZE, PROT_READ | PROT_WRITE,
|
||||
ASSERT_NE(MAP_FAILED, (p = mmap(0, granularity, PROT_READ | PROT_WRITE,
|
||||
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)));
|
||||
EXPECT_TRUE(testlib_memoryexists((char *)(((intptr_t)p >> 3) + 0x7fff8000)));
|
||||
EXPECT_SYS(0, 0, munmap(p, FRAMESIZE));
|
||||
EXPECT_SYS(0, 0, munmap(p, granularity));
|
||||
EXPECT_TRUE(testlib_memoryexists((char *)(((intptr_t)p >> 3) + 0x7fff8000)));
|
||||
}
|
||||
|
||||
|
@ -161,7 +164,7 @@ TEST(munmap, testLargeEnoughToUnmapAsan) {
|
|||
}
|
||||
char *p;
|
||||
size_t n;
|
||||
n = FRAMESIZE * 8 * 2;
|
||||
n = granularity * 8 * 2;
|
||||
ASSERT_NE(MAP_FAILED, (p = mmap(0, n, PROT_READ | PROT_WRITE,
|
||||
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)));
|
||||
EXPECT_SYS(0, 0, munmap(p, n));
|
||||
|
@ -180,7 +183,7 @@ TEST(munmap, tinyFile_roundupUnmapSize) {
|
|||
ASSERT_NE(MAP_FAILED, (p = mmap(0, 5, PROT_READ, MAP_PRIVATE, 3, 0)));
|
||||
ASSERT_SYS(0, 0, close(3));
|
||||
EXPECT_TRUE(testlib_memoryexists(p));
|
||||
EXPECT_SYS(0, 0, munmap(p, FRAMESIZE));
|
||||
EXPECT_SYS(0, 0, munmap(p, granularity));
|
||||
EXPECT_FALSE(testlib_memoryexists(p));
|
||||
EXPECT_FALSE(testlib_memoryexists(p + 5));
|
||||
}
|
||||
|
@ -204,22 +207,22 @@ TEST(munmap, tinyFile_preciseUnmapSize) {
|
|||
}
|
||||
|
||||
// clang-format off
|
||||
TEST(munmap, tinyFile_mapThriceUnmapOnce) {
|
||||
char *p = (char *)0x000063d646e20000;
|
||||
ASSERT_SYS(0, 3, open("doge", O_RDWR | O_CREAT | O_TRUNC, 0644));
|
||||
ASSERT_SYS (0, 5, write(3, "hello", 5));
|
||||
ASSERT_EQ(p+FRAMESIZE*0, mmap(p+FRAMESIZE*0, FRAMESIZE, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, -1, 0));
|
||||
ASSERT_EQ(p+FRAMESIZE*1, mmap(p+FRAMESIZE*1, 5, PROT_READ, MAP_PRIVATE|MAP_FIXED, 3, 0));
|
||||
ASSERT_EQ(p+FRAMESIZE*3, mmap(p+FRAMESIZE*3, 5, PROT_READ, MAP_PRIVATE|MAP_FIXED, 3, 0));
|
||||
ASSERT_SYS(0, 0, close(3));
|
||||
EXPECT_TRUE(testlib_memoryexists(p+FRAMESIZE*0));
|
||||
EXPECT_TRUE(testlib_memoryexists(p+FRAMESIZE*1));
|
||||
EXPECT_FALSE(testlib_memoryexists(p+FRAMESIZE*2));
|
||||
EXPECT_TRUE(testlib_memoryexists(p+FRAMESIZE*3));
|
||||
EXPECT_SYS(0, 0, munmap(p, FRAMESIZE*5));
|
||||
EXPECT_FALSE(testlib_memoryexists(p+FRAMESIZE*0));
|
||||
EXPECT_FALSE(testlib_memoryexists(p+FRAMESIZE*1));
|
||||
EXPECT_FALSE(testlib_memoryexists(p+FRAMESIZE*2));
|
||||
EXPECT_FALSE(testlib_memoryexists(p+FRAMESIZE*3));
|
||||
}
|
||||
/* TEST(munmap, tinyFile_mapThriceUnmapOnce) { */
|
||||
/* char *p = (char *)0x000063d646e20000; */
|
||||
/* ASSERT_SYS(0, 3, open("doge", O_RDWR | O_CREAT | O_TRUNC, 0644)); */
|
||||
/* ASSERT_SYS (0, 5, write(3, "hello", 5)); */
|
||||
/* ASSERT_EQ(p+granularity*0, mmap(p+granularity*0, granularity, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, -1, 0)); */
|
||||
/* ASSERT_EQ(p+granularity*1, mmap(p+granularity*1, 5, PROT_READ, MAP_PRIVATE|MAP_FIXED, 3, 0)); */
|
||||
/* ASSERT_EQ(p+granularity*3, mmap(p+granularity*3, 5, PROT_READ, MAP_PRIVATE|MAP_FIXED, 3, 0)); */
|
||||
/* ASSERT_SYS(0, 0, close(3)); */
|
||||
/* EXPECT_TRUE(testlib_memoryexists(p+granularity*0)); */
|
||||
/* EXPECT_TRUE(testlib_memoryexists(p+granularity*1)); */
|
||||
/* EXPECT_FALSE(testlib_memoryexists(p+granularity*2)); */
|
||||
/* EXPECT_TRUE(testlib_memoryexists(p+granularity*3)); */
|
||||
/* EXPECT_SYS(0, 0, munmap(p, granularity*5)); */
|
||||
/* EXPECT_FALSE(testlib_memoryexists(p+granularity*0)); */
|
||||
/* EXPECT_FALSE(testlib_memoryexists(p+granularity*1)); */
|
||||
/* EXPECT_FALSE(testlib_memoryexists(p+granularity*2)); */
|
||||
/* EXPECT_FALSE(testlib_memoryexists(p+granularity*3)); */
|
||||
/* } */
|
||||
// clang-format on
|
|
@ -23,6 +23,7 @@
|
|||
#include "libc/mem/mem.h"
|
||||
#include "libc/nexgen32e/kompressor.h"
|
||||
#include "libc/nexgen32e/lz4.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
|
@ -84,7 +85,7 @@ TEST(lz4, zoneFileGmt) {
|
|||
(mapsize = roundup(
|
||||
LZ4_FRAME_BLOCKCONTENTSIZE(lz4check(dict)) +
|
||||
(gmtsize = LZ4_FRAME_BLOCKCONTENTSIZE(lz4check(gmt))),
|
||||
FRAMESIZE)))),
|
||||
__granularity())))),
|
||||
dict)),
|
||||
gmt);
|
||||
ASSERT_BINEQ(
|
||||
|
|
|
@ -63,10 +63,10 @@ TEST(fork, testSharedMemory) {
|
|||
int *sharedvar;
|
||||
int *privatevar;
|
||||
EXPECT_NE(MAP_FAILED,
|
||||
(sharedvar = mmap(NULL, FRAMESIZE, PROT_READ | PROT_WRITE,
|
||||
(sharedvar = mmap(NULL, __granularity(), PROT_READ | PROT_WRITE,
|
||||
MAP_SHARED | MAP_ANONYMOUS, -1, 0)));
|
||||
EXPECT_NE(MAP_FAILED,
|
||||
(privatevar = mmap(NULL, FRAMESIZE, PROT_READ | PROT_WRITE,
|
||||
(privatevar = mmap(NULL, __granularity(), PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)));
|
||||
stackvar = 1;
|
||||
*sharedvar = 1;
|
||||
|
@ -77,18 +77,18 @@ TEST(fork, testSharedMemory) {
|
|||
++stackvar;
|
||||
++*sharedvar;
|
||||
++*privatevar;
|
||||
msync((void *)ROUNDDOWN((intptr_t)&stackvar, FRAMESIZE), FRAMESIZE,
|
||||
MS_SYNC);
|
||||
EXPECT_NE(-1, msync(privatevar, FRAMESIZE, MS_SYNC));
|
||||
EXPECT_NE(-1, msync(sharedvar, FRAMESIZE, MS_SYNC));
|
||||
msync((void *)ROUNDDOWN((intptr_t)&stackvar, __granularity()),
|
||||
__granularity(), MS_SYNC);
|
||||
EXPECT_NE(-1, msync(privatevar, __granularity(), MS_SYNC));
|
||||
EXPECT_NE(-1, msync(sharedvar, __granularity(), MS_SYNC));
|
||||
_exit(0);
|
||||
}
|
||||
EXPECT_NE(-1, waitpid(pid, &ws, 0));
|
||||
EXPECT_EQ(1, stackvar);
|
||||
EXPECT_EQ(2, *sharedvar);
|
||||
EXPECT_EQ(1, *privatevar);
|
||||
EXPECT_NE(-1, munmap(sharedvar, FRAMESIZE));
|
||||
EXPECT_NE(-1, munmap(privatevar, FRAMESIZE));
|
||||
EXPECT_NE(-1, munmap(sharedvar, __granularity()));
|
||||
EXPECT_NE(-1, munmap(privatevar, __granularity()));
|
||||
}
|
||||
|
||||
static volatile bool gotsigusr1;
|
||||
|
|
|
@ -28,11 +28,11 @@
|
|||
int i, *p;
|
||||
|
||||
void SetUp(void) {
|
||||
p = _mapshared(FRAMESIZE);
|
||||
p = _mapshared(__granularity());
|
||||
}
|
||||
|
||||
void TearDown(void) {
|
||||
munmap(p, FRAMESIZE);
|
||||
munmap(p, __granularity());
|
||||
}
|
||||
|
||||
void AtExit3(void) {
|
||||
|
|
|
@ -1,103 +0,0 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 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/intrin/pushpop.internal.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/mem/internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
|
||||
__static_yoink("realloc");
|
||||
|
||||
TEST(grow, testNull_hasAllocatingBehavior) {
|
||||
void *p = NULL;
|
||||
size_t capacity = 0;
|
||||
EXPECT_TRUE(__grow(&p, &capacity, 1, 0));
|
||||
EXPECT_NE(NULL, p);
|
||||
EXPECT_EQ(32, capacity);
|
||||
free(p);
|
||||
}
|
||||
|
||||
TEST(grow, testCapacity_isInUnits_withTerminatorGuarantee) {
|
||||
void *p = NULL;
|
||||
size_t capacity = 0;
|
||||
EXPECT_TRUE(__grow(&p, &capacity, 8, 0));
|
||||
EXPECT_NE(NULL, p);
|
||||
EXPECT_EQ(32 / 8 + 1, capacity);
|
||||
free(p);
|
||||
}
|
||||
|
||||
TEST(grow, testStackMemory_convertsToDynamic) {
|
||||
int A[] = {1, 2, 3};
|
||||
int *p = A;
|
||||
size_t capacity = ARRAYLEN(A);
|
||||
if (!_isheap(p)) {
|
||||
EXPECT_TRUE(__grow(&p, &capacity, sizeof(int), 0));
|
||||
EXPECT_TRUE(_isheap(p));
|
||||
EXPECT_GT(capacity, ARRAYLEN(A));
|
||||
EXPECT_EQ(1, p[0]);
|
||||
EXPECT_EQ(2, p[1]);
|
||||
EXPECT_EQ(3, p[2]);
|
||||
p[0] = 7;
|
||||
EXPECT_EQ(1, A[0]);
|
||||
free(p);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(grow, testGrowth_clearsNewMemory) {
|
||||
size_t i, capacity = 123;
|
||||
char *p = malloc(capacity);
|
||||
memset(p, 'a', capacity);
|
||||
EXPECT_TRUE(__grow(&p, &capacity, 1, 0));
|
||||
EXPECT_GT(capacity, 123);
|
||||
for (i = 0; i < 123; ++i)
|
||||
ASSERT_EQ('a', p[i]);
|
||||
for (i = 123; i < capacity; ++i)
|
||||
ASSERT_EQ(0, p[i]);
|
||||
free(p);
|
||||
}
|
||||
|
||||
TEST(grow, testBonusParam_willGoAboveAndBeyond) {
|
||||
size_t capacity = 32;
|
||||
char *p = malloc(capacity);
|
||||
EXPECT_TRUE(__grow(&p, &capacity, 1, 0));
|
||||
EXPECT_LT(capacity, 1024);
|
||||
free(p);
|
||||
p = malloc((capacity = 32));
|
||||
EXPECT_TRUE(__grow(&p, &capacity, 1, 1024));
|
||||
EXPECT_GT(capacity, 1024);
|
||||
free(p);
|
||||
}
|
||||
|
||||
TEST(grow, testOverflow_returnsFalseAndDoesNotFree) {
|
||||
int A[] = {1, 2, 3};
|
||||
int *p = A;
|
||||
size_t capacity = ARRAYLEN(A);
|
||||
if (!_isheap(p)) {
|
||||
EXPECT_FALSE(__grow(&p, &capacity, pushpop(SIZE_MAX), 0));
|
||||
EXPECT_FALSE(_isheap(p));
|
||||
EXPECT_EQ(capacity, ARRAYLEN(A));
|
||||
EXPECT_EQ(1, p[0]);
|
||||
EXPECT_EQ(2, p[1]);
|
||||
EXPECT_EQ(3, p[2]);
|
||||
}
|
||||
}
|
|
@ -1,395 +0,0 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 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/calls/calls.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/memtrack.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
|
||||
#define OPEN_MAX 16
|
||||
|
||||
#define I(x, y) \
|
||||
{ x, y, 0, (y - x) * FRAMESIZE + FRAMESIZE }
|
||||
|
||||
void SetUpOnce(void) {
|
||||
ASSERT_SYS(0, 0, pledge("stdio rpath", 0));
|
||||
}
|
||||
|
||||
bool AreMemoryIntervalsOk(const struct MemoryIntervals *mm) {
|
||||
/* asan runtime depends on this function */
|
||||
int i;
|
||||
size_t wantsize;
|
||||
for (i = 0; i < mm->i; ++i) {
|
||||
if (mm->p[i].y < mm->p[i].x) {
|
||||
STRACE("AreMemoryIntervalsOk() y should be >= x!");
|
||||
return false;
|
||||
}
|
||||
wantsize = (size_t)(mm->p[i].y - mm->p[i].x) * FRAMESIZE;
|
||||
if (!(wantsize < mm->p[i].size && mm->p[i].size <= wantsize + FRAMESIZE)) {
|
||||
STRACE("AreMemoryIntervalsOk(%p) size is wrong!"
|
||||
" %'zu not within %'zu .. %'zu",
|
||||
(uintptr_t)mm->p[i].x << 16, mm->p[i].size, wantsize,
|
||||
wantsize + FRAMESIZE);
|
||||
return false;
|
||||
}
|
||||
if (i) {
|
||||
if (mm->p[i].h != -1 || mm->p[i - 1].h != -1) {
|
||||
if (mm->p[i].x <= mm->p[i - 1].y) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!(mm->p[i - 1].y + 1 <= mm->p[i].x)) {
|
||||
STRACE("AreMemoryIntervalsOk() out of order or overlap!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool AreMemoryIntervalsEqual(const struct MemoryIntervals *mm1,
|
||||
const struct MemoryIntervals *mm2) {
|
||||
if (mm1->i != mm2->i)
|
||||
return false;
|
||||
if (memcmp(mm1->p, mm2->p, mm1->i * sizeof(*mm2->p)) != 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void PrintMemoryInterval(const struct MemoryIntervals *mm) {
|
||||
int i;
|
||||
for (i = 0; i < mm->i; ++i) {
|
||||
if (i)
|
||||
fprintf(stderr, ",");
|
||||
fprintf(stderr, "{%d,%d}", mm->p[i].x, mm->p[i].y);
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
static void CheckMemoryIntervalsEqual(const struct MemoryIntervals *mm1,
|
||||
const struct MemoryIntervals *mm2) {
|
||||
if (!AreMemoryIntervalsEqual(mm1, mm2)) {
|
||||
kprintf("got:\n");
|
||||
PrintMemoryIntervals(2, mm1);
|
||||
kprintf("want:\n");
|
||||
PrintMemoryIntervals(2, mm2);
|
||||
CHECK(!"memory intervals not equal");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
static void CheckMemoryIntervalsAreOk(const struct MemoryIntervals *mm) {
|
||||
if (!AreMemoryIntervalsOk(mm)) {
|
||||
PrintMemoryInterval(mm);
|
||||
CHECK(!"memory intervals not ok");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
static void RunTrackMemoryIntervalTest(const struct MemoryIntervals t[2], int x,
|
||||
int y, long h) {
|
||||
struct MemoryIntervals *mm;
|
||||
mm = memcpy(memalign(64, sizeof(*t)), t, sizeof(*t));
|
||||
CheckMemoryIntervalsAreOk(mm);
|
||||
CHECK_NE(-1, __track_memory(mm, x, y, h, 0, 0, 0, 0, 0,
|
||||
(y - x) * FRAMESIZE + FRAMESIZE));
|
||||
CheckMemoryIntervalsAreOk(mm);
|
||||
CheckMemoryIntervalsEqual(mm, t + 1);
|
||||
free(mm);
|
||||
}
|
||||
|
||||
static int RunReleaseMemoryIntervalsTest(const struct MemoryIntervals t[2],
|
||||
int x, int y) {
|
||||
int rc;
|
||||
struct MemoryIntervals *mm;
|
||||
mm = memcpy(memalign(64, sizeof(*t)), t, sizeof(*t));
|
||||
CheckMemoryIntervalsAreOk(mm);
|
||||
if ((rc = __untrack_memory(mm, x, y, NULL)) != -1) {
|
||||
CheckMemoryIntervalsAreOk(mm);
|
||||
CheckMemoryIntervalsEqual(t + 1, mm);
|
||||
}
|
||||
free(mm);
|
||||
return rc;
|
||||
}
|
||||
|
||||
TEST(__track_memory, TestEmpty) {
|
||||
static struct MemoryIntervals mm[2] = {
|
||||
{0, OPEN_MAX, 0, {}},
|
||||
{1, OPEN_MAX, 0, {{2, 2, 0, FRAMESIZE}}},
|
||||
};
|
||||
mm[0].p = mm[0].s;
|
||||
mm[1].p = mm[1].s;
|
||||
RunTrackMemoryIntervalTest(mm, 2, 2, 0);
|
||||
}
|
||||
|
||||
TEST(__track_memory, TestFull) {
|
||||
#if 0 // TODO(jart): Find way to re-enable
|
||||
int i;
|
||||
struct MemoryIntervals *mm;
|
||||
mm = calloc(1, sizeof(struct MemoryIntervals));
|
||||
for (i = 0; i < mm->n; ++i) {
|
||||
CheckMemoryIntervalsAreOk(mm);
|
||||
CHECK_NE(-1, __track_memory(mm, i, i, i, 0, 0, 0, 0, 0, 0));
|
||||
CheckMemoryIntervalsAreOk(mm);
|
||||
}
|
||||
CHECK_EQ(-1, __track_memory(mm, i, i, i, 0, 0, 0, 0, 0, 0));
|
||||
CHECK_EQ(ENOMEM, errno);
|
||||
CheckMemoryIntervalsAreOk(mm);
|
||||
free(mm);
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(__track_memory, TestAppend) {
|
||||
static struct MemoryIntervals mm[2] = {
|
||||
{1, OPEN_MAX, 0, {I(2, 2)}},
|
||||
{1, OPEN_MAX, 0, {I(2, 3)}},
|
||||
};
|
||||
mm[0].p = mm[0].s;
|
||||
mm[1].p = mm[1].s;
|
||||
RunTrackMemoryIntervalTest(mm, 3, 3, 0);
|
||||
}
|
||||
|
||||
TEST(__track_memory, TestPrepend) {
|
||||
static struct MemoryIntervals mm[2] = {
|
||||
{1, OPEN_MAX, 0, {I(2, 2)}},
|
||||
{1, OPEN_MAX, 0, {I(1, 2)}},
|
||||
};
|
||||
mm[0].p = mm[0].s;
|
||||
mm[1].p = mm[1].s;
|
||||
RunTrackMemoryIntervalTest(mm, 1, 1, 0);
|
||||
}
|
||||
|
||||
TEST(__track_memory, TestFillHole) {
|
||||
static struct MemoryIntervals mm[2] = {
|
||||
{4, OPEN_MAX, 0, {I(1, 1), I(3, 4), {5, 5, 1, FRAMESIZE}, I(6, 8)}},
|
||||
{3, OPEN_MAX, 0, {I(1, 4), {5, 5, 1, FRAMESIZE}, I(6, 8)}},
|
||||
};
|
||||
mm[0].p = mm[0].s;
|
||||
mm[1].p = mm[1].s;
|
||||
RunTrackMemoryIntervalTest(mm, 2, 2, 0);
|
||||
}
|
||||
|
||||
TEST(__track_memory, TestAppend2) {
|
||||
static struct MemoryIntervals mm[2] = {
|
||||
{1, OPEN_MAX, 0, {I(2, 2)}},
|
||||
{2, OPEN_MAX, 0, {I(2, 2), {3, 3, 1, FRAMESIZE}}},
|
||||
};
|
||||
mm[0].p = mm[0].s;
|
||||
mm[1].p = mm[1].s;
|
||||
RunTrackMemoryIntervalTest(mm, 3, 3, 1);
|
||||
}
|
||||
|
||||
TEST(__track_memory, TestPrepend2) {
|
||||
static struct MemoryIntervals mm[2] = {
|
||||
{1, OPEN_MAX, 0, {I(2, 2)}},
|
||||
{2, OPEN_MAX, 0, {{1, 1, 1, FRAMESIZE}, I(2, 2)}},
|
||||
};
|
||||
mm[0].p = mm[0].s;
|
||||
mm[1].p = mm[1].s;
|
||||
RunTrackMemoryIntervalTest(mm, 1, 1, 1);
|
||||
}
|
||||
|
||||
TEST(__track_memory, TestFillHole2) {
|
||||
static struct MemoryIntervals mm[2] = {
|
||||
{4,
|
||||
OPEN_MAX,
|
||||
0,
|
||||
{
|
||||
I(1, 1),
|
||||
I(3, 4),
|
||||
{5, 5, 1, FRAMESIZE},
|
||||
I(6, 8),
|
||||
}},
|
||||
{5,
|
||||
OPEN_MAX,
|
||||
0,
|
||||
{
|
||||
I(1, 1),
|
||||
{2, 2, 1, FRAMESIZE},
|
||||
{3, 4, 0, FRAMESIZE * 2},
|
||||
{5, 5, 1, FRAMESIZE},
|
||||
{6, 8, 0, FRAMESIZE * 3},
|
||||
}},
|
||||
};
|
||||
mm[0].p = mm[0].s;
|
||||
mm[1].p = mm[1].s;
|
||||
RunTrackMemoryIntervalTest(mm, 2, 2, 1);
|
||||
}
|
||||
|
||||
TEST(__find_memory, Test) {
|
||||
static struct MemoryIntervals mm[1] = {
|
||||
{
|
||||
4,
|
||||
OPEN_MAX,
|
||||
0,
|
||||
{
|
||||
[0] = {1, 1},
|
||||
[1] = {3, 4},
|
||||
[2] = {5, 5, 1},
|
||||
[3] = {6, 8},
|
||||
},
|
||||
},
|
||||
};
|
||||
mm[0].p = mm[0].s;
|
||||
EXPECT_EQ(0, __find_memory(mm, 0));
|
||||
EXPECT_EQ(0, __find_memory(mm, 1));
|
||||
EXPECT_EQ(1, __find_memory(mm, 2));
|
||||
EXPECT_EQ(1, __find_memory(mm, 3));
|
||||
EXPECT_EQ(1, __find_memory(mm, 4));
|
||||
EXPECT_EQ(2, __find_memory(mm, 5));
|
||||
EXPECT_EQ(3, __find_memory(mm, 6));
|
||||
EXPECT_EQ(3, __find_memory(mm, 7));
|
||||
EXPECT_EQ(3, __find_memory(mm, 8));
|
||||
EXPECT_EQ(4, __find_memory(mm, 9));
|
||||
}
|
||||
|
||||
TEST(__untrack_memory, TestEmpty) {
|
||||
static struct MemoryIntervals mm[2] = {
|
||||
{0, OPEN_MAX, 0, {}},
|
||||
{0, OPEN_MAX, 0, {}},
|
||||
};
|
||||
mm[0].p = mm[0].s;
|
||||
mm[1].p = mm[1].s;
|
||||
EXPECT_NE(-1, RunReleaseMemoryIntervalsTest(mm, 2, 2));
|
||||
}
|
||||
|
||||
TEST(__untrack_memory, TestRemoveElement_UsesInclusiveRange) {
|
||||
static struct MemoryIntervals mm[2] = {
|
||||
{3, OPEN_MAX, 0, {I(0, 0), I(2, 2), I(4, 4)}},
|
||||
{2, OPEN_MAX, 0, {I(0, 0), I(4, 4)}},
|
||||
};
|
||||
mm[0].p = mm[0].s;
|
||||
mm[1].p = mm[1].s;
|
||||
EXPECT_NE(-1, RunReleaseMemoryIntervalsTest(mm, 2, 2));
|
||||
}
|
||||
|
||||
TEST(__untrack_memory, TestPunchHole) {
|
||||
static struct MemoryIntervals mm[2] = {
|
||||
{1, OPEN_MAX, 0, {I(0, 9)}},
|
||||
{2, OPEN_MAX, 0, {I(0, 3), I(6, 9)}},
|
||||
};
|
||||
mm[0].p = mm[0].s;
|
||||
mm[1].p = mm[1].s;
|
||||
EXPECT_NE(-1, RunReleaseMemoryIntervalsTest(mm, 4, 5));
|
||||
}
|
||||
|
||||
TEST(__untrack_memory, TestShortenLeft) {
|
||||
if (IsWindows())
|
||||
return;
|
||||
static struct MemoryIntervals mm[2] = {
|
||||
{1, OPEN_MAX, 0, {I(0, 9)}},
|
||||
{1, OPEN_MAX, 0, {I(0, 7)}},
|
||||
};
|
||||
mm[0].p = mm[0].s;
|
||||
mm[1].p = mm[1].s;
|
||||
EXPECT_NE(-1, RunReleaseMemoryIntervalsTest(mm, 8, 9));
|
||||
}
|
||||
|
||||
TEST(__untrack_memory, TestShortenRight) {
|
||||
if (IsWindows())
|
||||
return;
|
||||
static struct MemoryIntervals mm[2] = {
|
||||
{1, OPEN_MAX, 0, {I(0, 9)}},
|
||||
{1, OPEN_MAX, 0, {I(3, 9)}},
|
||||
};
|
||||
mm[0].p = mm[0].s;
|
||||
mm[1].p = mm[1].s;
|
||||
EXPECT_NE(-1, RunReleaseMemoryIntervalsTest(mm, 0, 2));
|
||||
}
|
||||
|
||||
TEST(__untrack_memory, TestShortenLeft2) {
|
||||
if (IsWindows())
|
||||
return;
|
||||
static struct MemoryIntervals mm[2] = {
|
||||
{1, OPEN_MAX, 0, {I(0, 9)}},
|
||||
{1, OPEN_MAX, 0, {I(0, 7)}},
|
||||
};
|
||||
mm[0].p = mm[0].s;
|
||||
mm[1].p = mm[1].s;
|
||||
EXPECT_NE(-1, RunReleaseMemoryIntervalsTest(mm, 8, 11));
|
||||
}
|
||||
|
||||
TEST(__untrack_memory, TestShortenRight2) {
|
||||
if (IsWindows())
|
||||
return;
|
||||
static struct MemoryIntervals mm[2] = {
|
||||
{1, OPEN_MAX, 0, {I(0, 9)}},
|
||||
{1, OPEN_MAX, 0, {I(3, 9)}},
|
||||
};
|
||||
mm[0].p = mm[0].s;
|
||||
mm[1].p = mm[1].s;
|
||||
EXPECT_NE(-1, RunReleaseMemoryIntervalsTest(mm, -3, 2));
|
||||
}
|
||||
|
||||
TEST(__untrack_memory, TestZeroZero) {
|
||||
static struct MemoryIntervals mm[2] = {
|
||||
{1, OPEN_MAX, 0, {I(3, 9)}},
|
||||
{1, OPEN_MAX, 0, {I(3, 9)}},
|
||||
};
|
||||
mm[0].p = mm[0].s;
|
||||
mm[1].p = mm[1].s;
|
||||
EXPECT_NE(-1, RunReleaseMemoryIntervalsTest(mm, 0, 0));
|
||||
}
|
||||
|
||||
TEST(__untrack_memory, TestNoopLeft) {
|
||||
static struct MemoryIntervals mm[2] = {
|
||||
{1, OPEN_MAX, 0, {I(3, 9)}},
|
||||
{1, OPEN_MAX, 0, {I(3, 9)}},
|
||||
};
|
||||
mm[0].p = mm[0].s;
|
||||
mm[1].p = mm[1].s;
|
||||
EXPECT_NE(-1, RunReleaseMemoryIntervalsTest(mm, 1, 2));
|
||||
}
|
||||
|
||||
TEST(__untrack_memory, TestNoopRight) {
|
||||
static struct MemoryIntervals mm[2] = {
|
||||
{1, OPEN_MAX, 0, {I(3, 9)}},
|
||||
{1, OPEN_MAX, 0, {I(3, 9)}},
|
||||
};
|
||||
mm[0].p = mm[0].s;
|
||||
mm[1].p = mm[1].s;
|
||||
EXPECT_NE(-1, RunReleaseMemoryIntervalsTest(mm, 10, 10));
|
||||
}
|
||||
|
||||
TEST(__untrack_memory, TestBigFree) {
|
||||
static struct MemoryIntervals mm[2] = {
|
||||
{2, OPEN_MAX, 0, {I(0, 3), I(6, 9)}},
|
||||
{0, OPEN_MAX, 0, {}},
|
||||
};
|
||||
mm[0].p = mm[0].s;
|
||||
mm[1].p = mm[1].s;
|
||||
EXPECT_NE(-1, RunReleaseMemoryIntervalsTest(mm, INT_MIN, INT_MAX));
|
||||
}
|
||||
|
||||
TEST(__untrack_memory, TestWeirdGap) {
|
||||
static struct MemoryIntervals mm[2] = {
|
||||
{3, OPEN_MAX, 0, {I(10, 10), I(20, 20), I(30, 30)}},
|
||||
{2, OPEN_MAX, 0, {I(10, 10), I(30, 30)}},
|
||||
};
|
||||
mm[0].p = mm[0].s;
|
||||
mm[1].p = mm[1].s;
|
||||
EXPECT_NE(-1, RunReleaseMemoryIntervalsTest(mm, 15, 25));
|
||||
}
|
|
@ -19,6 +19,7 @@
|
|||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/mem/gc.h"
|
||||
#include "libc/mem/mem.h"
|
||||
|
@ -60,7 +61,6 @@ TEST(zipos, test) {
|
|||
for (i = 0; i < n; ++i) {
|
||||
EXPECT_SYS(0, 0, pthread_join(t[i], 0));
|
||||
}
|
||||
__print_maps();
|
||||
}
|
||||
|
||||
TEST(zipos, erofs) {
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/nexgen32e/nexgen32e.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/rand.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
|
@ -168,5 +169,5 @@ BENCH(memcpy, bench) {
|
|||
BB(1023);
|
||||
BB(1024);
|
||||
BB(4096);
|
||||
BB(FRAMESIZE);
|
||||
BB(__granularity());
|
||||
}
|
||||
|
|
|
@ -129,7 +129,7 @@ TEST(sem_timedwait, threads) {
|
|||
|
||||
TEST(sem_timedwait, processes) {
|
||||
int i, r, rc, n = 4, pshared = 1;
|
||||
sem_t *sm = _mapshared(FRAMESIZE), *s[2] = {sm, sm + 1};
|
||||
sem_t *sm = _mapshared(__granularity()), *s[2] = {sm, sm + 1};
|
||||
ASSERT_SYS(0, 0, sem_init(s[0], pshared, 0));
|
||||
ASSERT_SYS(0, 0, sem_init(s[1], pshared, 0));
|
||||
for (i = 0; i < n; ++i) {
|
||||
|
@ -163,5 +163,5 @@ TEST(sem_timedwait, processes) {
|
|||
ASSERT_EQ(0, r);
|
||||
ASSERT_SYS(0, 0, sem_destroy(s[1]));
|
||||
ASSERT_SYS(0, 0, sem_destroy(s[0]));
|
||||
ASSERT_SYS(0, 0, munmap(sm, FRAMESIZE));
|
||||
ASSERT_SYS(0, 0, munmap(sm, __granularity()));
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue