8#include <sys/syscall.h>
10static _Thread_local
volatile unsigned tls_value;
12static int allocator_current(
void) {
14 unsigned char* allocation = malloc(192 * 1024);
15 CHECK(allocation != NULL);
16 for (
size_t n = 0; n < 192 * 1024; ++n)
17 allocation[n] = (
unsigned char)(n * 17 + 0x39);
18 unsigned char* grown = realloc(allocation, 384 * 1024);
21 for (
size_t n = 0; n < 192 * 1024; ++n)
22 CHECK(allocation[n] == (
unsigned char)(n * 17 + 0x39));
23 CHECK(ml_limit(16 * 1024 * 1024) == 0 && ml_unprivileged() == 0);
24 CHECK(mlockall(MCL_CURRENT | MCL_ONFAULT) == 0);
25 CHECK(mlockall(MCL_CURRENT) == 0);
26 CHECK(allocation[0] == 0x39 && allocation[ml_page] == (
unsigned char)(ml_page * 17 + 0x39));
33static int initial_stack(
void) {
35 volatile unsigned char storage[3 * ml_page];
36 volatile unsigned char* aligned =
37 (
volatile unsigned char*)(((uintptr_t)storage + ml_page - 1) & ~(uintptr_t)(ml_page - 1));
38 void* managed = MAP_FAILED;
40 aligned[ml_page] = 0x68;
41 managed = mmap(NULL, ml_page, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
42 CHECK(managed != MAP_FAILED && ml_limit(2 * ml_page) == 0);
43 CHECK(mlock((
void*)aligned, 2 * ml_page) == 0);
45 CHECK(mlock(managed, ml_page) == -1 && errno == ENOMEM);
46 CHECK(munlock((
void*)aligned, ml_page) == 0 && mlock(managed, ml_page) == 0);
47 CHECK(aligned[0] == 0x47 && aligned[ml_page] == 0x68);
50 if (managed != MAP_FAILED)
51 munmap(managed, ml_page);
55static void* touch_tls(
void* argument) {
57 return (
void*)(uintptr_t)(tls_value != 0x69 || argument != (
void*)1);
60static int future_thread(
void) {
63 pthread_attr_t attributes;
64 int attributes_live = 0;
67 CHECK(pthread_attr_init(&attributes) == 0);
69 CHECK(pthread_attr_setstacksize(&attributes, 32 * ml_page) == 0);
70 CHECK(pthread_create(&thread, &attributes, touch_tls, (
void*)1) == 0);
72 CHECK(pthread_join(thread, &result) == 0);
74 CHECK(result == NULL && ml_limit(ml_page) == 0);
75 CHECK(mlockall(MCL_FUTURE | MCL_ONFAULT) == 0);
76 int created = pthread_create(&thread, &attributes, touch_tls, (
void*)1);
79 CHECK(created == EAGAIN);
80 CHECK(munlockall() == 0);
81 CHECK(pthread_create(&thread, &attributes, touch_tls, (
void*)1) == 0);
83 CHECK(pthread_join(thread, &result) == 0);
85 CHECK(result == NULL);
89 pthread_join(thread, NULL);
91 pthread_attr_destroy(&attributes);
95static int future_heap(
void) {
97 unsigned char* managed = MAP_FAILED;
98 size_t managed_length = 0;
99 CHECK(ml_limit(2 * ml_page) == 0);
100 uintptr_t original = (uintptr_t)syscall(SYS_brk, 0);
101 CHECK(original && original != UINTPTR_MAX && original < UINTPTR_MAX - 5 * ml_page);
102 uintptr_t start = (original + ml_page - 1) & ~(uintptr_t)(ml_page - 1);
103 CHECK((uintptr_t)syscall(SYS_brk, start) == start);
104 CHECK(mlockall(MCL_FUTURE | MCL_ONFAULT) == 0);
105 CHECK((uintptr_t)syscall(SYS_brk, start + 1) == start + 1);
106 CHECK((uintptr_t)syscall(SYS_brk, start + ml_page - 1) == start + ml_page - 1);
107 uintptr_t accepted = start + ml_page + 1;
108 CHECK((uintptr_t)syscall(SYS_brk, accepted) == accepted);
110 CHECK((uintptr_t)syscall(SYS_brk, start + 2 * ml_page + 1) == accepted && errno == 0);
111 CHECK((uintptr_t)syscall(SYS_brk, 0) == accepted);
112 volatile unsigned char* bytes = (
volatile unsigned char*)start;
113 CHECK(bytes[0] == 0 && bytes[ml_page] == 0);
115 bytes[ml_page] = 0x76;
116 CHECK(munlock((
void*)start, ml_page) == 0);
117 CHECK((uintptr_t)syscall(SYS_brk, start + 2 * ml_page + 1) == start + 2 * ml_page + 1);
118 CHECK(bytes[0] == 0x53 && bytes[ml_page] == 0x76 && bytes[2 * ml_page] == 0);
119 CHECK(munlockall() == 0);
120 CHECK((uintptr_t)syscall(SYS_brk, start + 4 * ml_page) == start + 4 * ml_page);
121 bytes[2 * ml_page] = 0x29;
122 bytes[3 * ml_page] = 0x64;
123 CHECK(mlock((
void*)start, 2 * ml_page) == 0);
124 managed = mmap(NULL, 3 * ml_page, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
125 CHECK(managed != MAP_FAILED);
126 managed_length = 3 * ml_page;
128 CHECK(mlock(managed, ml_page) == -1 && errno == ENOMEM);
129 CHECK(munmap(managed + 2 * ml_page, ml_page) == 0);
130 managed_length = 2 * ml_page;
131 CHECK(bytes[0] == 0x53 && bytes[ml_page] == 0x76 && bytes[2 * ml_page] == 0x29 &&
132 bytes[3 * ml_page] == 0x64);
134 CHECK(mlock(managed, ml_page) == -1 && errno == ENOMEM);
137 CHECK(munmap((
void*)(start + ml_page), ml_page) == 0);
138 unsigned char resident;
140 CHECK(mincore((
void*)(start + ml_page), ml_page, &resident) == -1 && errno == ENOMEM);
141 CHECK(bytes[0] == 0x53 && bytes[2 * ml_page] == 0x29 && bytes[3 * ml_page] == 0x64);
142 CHECK(mlock(managed, ml_page) == 0);
144 CHECK(mlock((
void*)(start + 2 * ml_page), ml_page) == -1 && errno == ENOMEM);
145 CHECK(munmap((
void*)start, ml_page) == 0);
146 CHECK(mlock((
void*)(start + 2 * ml_page), ml_page) == 0);
148 CHECK(mlock(managed + ml_page, ml_page) == -1 && errno == ENOMEM);
149 CHECK(bytes[2 * ml_page] == 0x29 && bytes[3 * ml_page] == 0x64);
150 CHECK(munmap((
void*)(start + 3 * ml_page), ml_page) == 0);
152 CHECK(mincore((
void*)(start + 3 * ml_page), ml_page, &resident) == -1 && errno == ENOMEM);
153 CHECK(bytes[2 * ml_page] == 0x29);
155 CHECK(mlock(managed + ml_page, ml_page) == -1 && errno == ENOMEM);
159 if (managed != MAP_FAILED)
160 munmap(managed, managed_length);
165 return allocator_current() || initial_stack() || future_thread() || future_heap();