malloc+debug.ha (2003B)
1 // SPDX-License-Identifier: MPL-2.0 2 // (c) Hare authors <https://harelang.org> 3 4 // This is a very simple "debug" allocator which works by allocating only via 5 // mmap and returning pointers to the end of the segment such that any writes 6 // beyond the end will cause an immediate segfault to occur. 7 // 8 // Ultimately, this should be replaced with a much more sophisticated debugging 9 // allocator. 10 let pagesz: size = 4096; 11 12 def AUXV_PAGESZ: u64 = 6; 13 14 type auxv64 = struct { 15 a_type: u64, 16 union { 17 a_val: u64, 18 a_ptr: *opaque, 19 a_fnc: *fn() void, 20 } 21 }; 22 23 @init fn init() void = { 24 let i = 0; 25 for (envp[i] != null) { 26 i += 1; 27 }; 28 let auxv = &envp[i + 1]: *[*]auxv64; 29 for (let i = 0z; auxv[i].a_type != 0; i += 1) { 30 if (auxv[i].a_type == AUXV_PAGESZ) { 31 pagesz = auxv[i].a_val: size; 32 break; 33 }; 34 }; 35 }; 36 37 export fn malloc(n: size) nullable *opaque = { 38 if (n == 0) { 39 return null; 40 }; 41 let z = n + size(*opaque) + size(size); 42 if (z % pagesz != 0) { 43 z += pagesz - z % pagesz; 44 }; 45 let seg = match (segmalloc(z)) { 46 case null => 47 return null; 48 case let ptr: *opaque => 49 yield ptr; 50 }; 51 let user = &(seg: *[*]u8)[z - n]; 52 let segptr = &(user: *[*]*opaque)[-1]; 53 let szptr = &(segptr: *[*]size)[-1]; 54 *segptr = seg; 55 *szptr = n; 56 return user; 57 }; 58 59 export @symbol("rt.free") fn free_(_p: nullable *opaque) void = { 60 if (_p != null) { 61 let user = _p: *opaque; 62 let segptr = &(user: *[*]*opaque)[-1]; 63 let szptr = &(segptr: *[*]size)[-1]; 64 let z = *szptr + size(*opaque) + size(size); 65 if (z % pagesz != 0) { 66 z += pagesz - z % pagesz; 67 }; 68 segfree(*segptr, z); 69 }; 70 }; 71 72 export fn realloc(user: nullable *opaque, n: size) nullable *opaque = { 73 if (n == 0) { 74 free(user); 75 return null; 76 } else if (user == null) { 77 return malloc(n); 78 }; 79 80 let user = user: *opaque; 81 let segptr = &(user: *[*]*opaque)[-1]; 82 let szptr = &(segptr: *[*]size)[-1]; 83 let z = *szptr; 84 85 let new = malloc(n); 86 if (new != null) { 87 memcpy(new: *opaque, user, if (z < n) z else n); 88 free(user); 89 }; 90 91 return new; 92 };