this repo has no description
at fixPythonPipStalling 244 lines 6.7 kB view raw
1#include <errno.h> 2#include <stdlib.h> 3#include <string.h> 4#include <unistd.h> 5#include <sys/cdefs.h> 6#include <sys/mman.h> 7#include <mach/vm_page_size.h> 8#include <os/overflow.h> 9 10#ifdef __LP64__ 11#define GMALLOC_MAGIC 0xdeadbeefdeadbeef 12#else 13#define GMALLOC_MAGIC 0xdeadbeef 14#endif 15 16struct gmalloc_header { 17 size_t magic; 18 size_t size; 19 void *mmap_base; 20 size_t mmap_size; 21 size_t magic_again; 22}; 23 24static int gmalloc_protect_before; 25static int gmalloc_fill_space; 26static int gmalloc_allow_reads; 27static int gmalloc_strict_size; 28static int gmalloc_check_header = 1; 29 30void __malloc_init(const char *apple[]) { 31 (void) apple; 32 33 if (getenv("MALLOC_PROTECT_BEFORE")) gmalloc_protect_before = 1; 34 if (getenv("MALLOC_FILL_SPACE")) gmalloc_fill_space = 1; 35 if (getenv("MALLOC_ALLOW_READS")) gmalloc_allow_reads = 1; 36 if (getenv("MALLOC_STRICT_SIZE")) gmalloc_strict_size = 1; 37 38 const char *check_header = getenv("MALLOC_CHECK_HEADER"); 39 if (check_header && (!strcmp(check_header, "0") || !strcmp(check_header, "NO"))) { 40 gmalloc_check_header = 0; 41 } 42} 43 44static inline size_t round_up(size_t size, size_t increment) { 45 if ((size & (increment - 1)) == 0) { 46 return size; 47 } 48 return (size | (increment - 1)) + 1; 49} 50 51static inline void *round_down(void *address, size_t align) { 52 uintptr_t v = (uintptr_t) address; 53 return (void *) (v & ~(align - 1)); 54} 55 56static struct gmalloc_header *header_for_ptr(void *ptr) { 57 return (struct gmalloc_header *) ((char *) ptr - sizeof(struct gmalloc_header)); 58} 59 60static void *do_alloc(size_t payload_size, size_t align) { 61 // Decide how much memory we're going to allocate, 62 // not counting the guard page. 63 size_t accessible_size = round_up(payload_size, align); 64 if (gmalloc_protect_before) { 65 // In protect-before mode, the header will reside 66 // on the guard page, so need to add it here. 67 } else { 68 accessible_size += sizeof(struct gmalloc_header); 69 } 70 accessible_size = round_up(accessible_size, vm_page_size); 71 72 void *mmap_base = mmap( 73 NULL, accessible_size + vm_page_size, 74 PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, 75 -1, 0 76 ); 77 if (mmap_base == MAP_FAILED) { 78 return NULL; 79 } 80 81 void *guard = gmalloc_protect_before ? mmap_base : mmap_base + accessible_size; 82 void *accessible = gmalloc_protect_before ? mmap_base + vm_page_size : mmap_base; 83 void *payload = gmalloc_protect_before ? accessible : accessible + accessible_size - payload_size; 84 payload = round_down(payload, align); 85 86 if (gmalloc_fill_space) { 87 memset(accessible, 0x55, accessible_size); 88 } 89 90 struct gmalloc_header *header = header_for_ptr(payload); 91 header->magic = header->magic_again = GMALLOC_MAGIC; 92 header->size = payload_size; 93 header->mmap_base = mmap_base; 94 header->mmap_size = accessible_size + vm_page_size; 95 96 int guard_page_prot = gmalloc_allow_reads ? PROT_READ : PROT_NONE; 97 int rc = mprotect(guard, vm_page_size, guard_page_prot); 98 if (rc < 0) { 99 int saved_errno = errno; 100 munmap(mmap_base, accessible_size + vm_page_size); 101 errno = saved_errno; 102 return NULL; 103 } 104 105 return payload; 106} 107 108void *aligned_alloc(size_t align, size_t size) { 109 void *ptr = do_alloc(size, align); 110 111 if (ptr == NULL) { 112 int saved_errno = errno; 113 const char msg[] = "Failed to alloc: "; 114 write(2, msg, sizeof(msg) - 1); 115 // Do not use strerror(), because it allocates. 116 extern const char *const sys_errlist[]; 117 write(2, sys_errlist[saved_errno], strlen(sys_errlist[saved_errno])); 118 write(2, "\n", 1); 119 120 errno = saved_errno; 121 return NULL; 122 } 123 124 return ptr; 125} 126 127void *malloc(size_t size) { 128 return aligned_alloc(gmalloc_strict_size ? 1 : 16, size); 129} 130 131int posix_memalign(void **ptr, size_t align, size_t size) { 132 *ptr = aligned_alloc(align, size); 133 if (*ptr == NULL) { 134 return ENOMEM; 135 } 136 return 0; 137} 138 139void *calloc(size_t num, size_t size) { 140 void *ptr = malloc(num * size); 141 memset(ptr, 0, num * size); 142 return ptr; 143} 144 145static void unlock_and_check_header(const struct gmalloc_header *header) { 146 if (gmalloc_protect_before && !gmalloc_allow_reads) { 147 mprotect(round_down((void *) header, vm_page_size), vm_page_size, PROT_READ); 148 } 149 150 if (!gmalloc_check_header) { 151 return; 152 } 153 154 if (header->magic != GMALLOC_MAGIC || header->magic_again != GMALLOC_MAGIC) { 155 abort(); 156 } 157} 158 159void free(void *ptr) { 160 if (ptr == NULL) { 161 return; 162 } 163 164 struct gmalloc_header *header = header_for_ptr(ptr); 165 unlock_and_check_header(header); 166 167 munmap(header->mmap_base, header->mmap_size); 168} 169 170void *realloc(void *old_ptr, size_t new_size) { 171 size_t size_to_copy; 172 if (old_ptr == NULL) { 173 size_to_copy = 0; 174 } else { 175 struct gmalloc_header *header = header_for_ptr(old_ptr); 176 unlock_and_check_header(header); 177 size_to_copy = header->size; 178 } 179 if (size_to_copy > new_size) { 180 size_to_copy = new_size; 181 } 182 183 void *new_ptr = malloc(new_size); 184 if (new_ptr == NULL) { 185 return NULL; 186 } 187 memcpy(new_ptr, old_ptr, size_to_copy); 188 free(old_ptr); 189 190 return new_ptr; 191} 192 193void *reallocarray(void *old_ptr, size_t num, size_t size) __DARWIN_EXTSN(reallocarray); 194void *reallocarray(void *old_ptr, size_t num, size_t size) { 195 size_t new_size; 196 if (os_mul_overflow(num, size, &new_size)) { 197 errno = ENOMEM; 198 return NULL; 199 } 200 return realloc(old_ptr, new_size); 201} 202 203void *reallocarrayf(void *old_ptr, size_t num, size_t size) __DARWIN_EXTSN(reallocarrayf); 204void *reallocarrayf(void *old_ptr, size_t num, size_t size) { 205 size_t new_size; 206 if (os_mul_overflow(num, size, &new_size)) { 207 errno = ENOMEM; 208 return NULL; 209 } 210 void *new_ptr = realloc(old_ptr, new_size); 211 if (new_ptr == NULL) { 212 free(old_ptr); 213 } 214 return new_ptr; 215} 216 217// Zone versions 218typedef void malloc_zone_t; 219void *malloc_zone_malloc(malloc_zone_t *zone, size_t size) { 220 (void) zone; 221 return malloc(size); 222} 223 224void *malloc_zone_calloc(malloc_zone_t *zone, size_t num, size_t size) { 225 (void) zone; 226 return calloc(num, size); 227} 228 229void *malloc_zone_realloc(malloc_zone_t *zone, void *ptr, size_t size) { 230 (void) zone; 231 return realloc(ptr, size); 232} 233 234void *malloc_zone_memalign(malloc_zone_t *zone, size_t align, size_t size) { 235 (void) zone; 236 void *ptr; 237 posix_memalign(&ptr, align, size); 238 return ptr; 239} 240 241void malloc_zone_free(malloc_zone_t *zone, void *ptr) { 242 (void) zone; 243 free(ptr); 244}