commit 3dd966977c33a89c9bb85662a4e131f892125d9b
parent ed9142ac20ea3f6bed3bc6d6f78acca6d82f7ec3
Author: Drew DeVault <sir@cmpwn.com>
Date: Wed, 1 Jan 2025 20:00:58 +0100
rt: add heap management utilities
This allows modules like debug:: to use a dedicated heap, so that they
can have access to alloc/insert/etc and work reliably when providing
debugging tools for misbehaving programs which might have, for example,
trashed the default heap.
Signed-off-by: Drew DeVault <sir@cmpwn.com>
Diffstat:
16 files changed, 113 insertions(+), 60 deletions(-)
diff --git a/debug/abort.ha b/debug/abort.ha
@@ -16,6 +16,8 @@ fn debug_abort(
col: u64,
msg: str,
) never = {
+ begin_fatal();
+
fmt::errorfln("Abort: {}:{}:{}: {}", *path, line, col, msg): void;
const self = match (image::self()) {
diff --git a/debug/fault.ha b/debug/fault.ha
@@ -26,7 +26,7 @@ def ALTSTACK_SIZE: size = 16384;
};
fn signal_handler(sig: sig, info: *signal::siginfo, uctx: *opaque) void = {
- signal::resetall();
+ begin_fatal();
const ip = uctx_ip(uctx);
const sp = uctx_sp(uctx);
diff --git a/debug/malloc+libc.ha b/debug/malloc+libc.ha
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: MPL-2.0
+// (c) Hare authors <https://harelang.org>
+
+use unix::signal;
+
+fn begin_fatal() void = {
+ signal::resetall();
+};
+
+fn begin_altheap() nullable *opaque = {
+ return null; // no-op on +libc
+};
+
+fn end_altheap(restore: nullable *opaque) void = {
+ void; // no-op on +libc
+};
diff --git a/debug/malloc.ha b/debug/malloc.ha
@@ -0,0 +1,26 @@
+// SPDX-License-Identifier: MPL-2.0
+// (c) Hare authors <https://harelang.org>
+
+use rt;
+use unix::signal;
+
+let heap = rt::EMPTY_HEAP;
+
+// Reconfigure the process to handle a fatal condition, such as a segfault, as
+// safely as possible. Resets all signals (in case of faults in debug::) and
+// configures the runtime to use the debug heap (in case of heap overflow or
+// similar faults in the user program).
+fn begin_fatal() void = {
+ signal::resetall();
+ rt::setheap(&heap);
+};
+
+// Enables the debug:: heap.
+fn begin_altheap() *rt::memory_heap = {
+ return rt::setheap(&heap);
+};
+
+// Restores the original heap corresponding to [[begin_altheap]].
+fn end_altheap(restore: *rt::memory_heap) void = {
+ rt::setheap(restore);
+};
diff --git a/debug/traces.ha b/debug/traces.ha
@@ -30,6 +30,9 @@ export fn trace_store(frame: stackframe) u64 = {
static let pc: []uintptr = [];
pc = pc[..0];
+ const prev_heap = begin_altheap();
+ defer end_altheap(prev_heap);
+
const hash = fnv::fnv64a();
for (true) {
hash::write(&hash, &frame_pc(frame): *[size(uintptr)]u8);
diff --git a/makefiles/freebsd.aarch64.mk b/makefiles/freebsd.aarch64.mk
@@ -4,7 +4,7 @@ TDENV = env HARE_TD_rt=$(HARECACHE)/rt.td HARE_TD_types=$(HARECACHE)/types.td HA
RTSCRIPT = rt/+freebsd/hare.sc
OBJS = $(HARECACHE)/rt.o $(HARECACHE)/types.o $(HARECACHE)/bytes.o $(HARECACHE)/encoding_utf8.o $(HARECACHE)/sort_cmp.o $(HARECACHE)/strings.o $(HARECACHE)/ascii.o $(HARECACHE)/errors.o $(HARECACHE)/io.o $(HARECACHE)/bufio.o $(HARECACHE)/crypto_math.o $(HARECACHE)/endian.o $(HARECACHE)/hash.o $(HARECACHE)/crypto_sha256.o $(HARECACHE)/math.o $(HARECACHE)/memio.o $(HARECACHE)/path.o $(HARECACHE)/time.o $(HARECACHE)/fs.o $(HARECACHE)/types_c.o $(HARECACHE)/os.o $(HARECACHE)/strconv.o $(HARECACHE)/fmt.o $(HARECACHE)/encoding_hex.o $(HARECACHE)/sort.o $(HARECACHE)/hare_lex.o $(HARECACHE)/hare_ast.o $(HARECACHE)/hare_parse.o $(HARECACHE)/hare_unparse.o $(HARECACHE)/hare_module.o $(HARECACHE)/unix.o $(HARECACHE)/unix_signal.o $(HARECACHE)/os_exec.o $(HARECACHE)/shlex.o $(HARECACHE)/unix_tty.o $(HARECACHE)/cmd_hare_build.o $(HARECACHE)/dirs.o $(HARECACHE)/getopt.o $(HARECACHE)/cmd_hare.o
-rt_ha = rt/+aarch64/arch_jmp.ha rt/+aarch64/cpuid.ha rt/+freebsd/+aarch64.ha rt/+freebsd/env.ha rt/+freebsd/errno.ha rt/+freebsd/initfini.ha rt/+freebsd/platform_abort.ha rt/+freebsd/platformstart-libc.ha rt/+freebsd/segmalloc.ha rt/+freebsd/signal.ha rt/+freebsd/socket.ha rt/+freebsd/start.ha rt/+freebsd/syscallno.ha rt/+freebsd/syscalls.ha rt/+freebsd/types.ha rt/abort.ha rt/ensure.ha rt/fenv_defs.ha rt/jmp.ha rt/malloc.ha rt/memcpy.ha rt/memfunc_ptr.ha rt/memmove.ha rt/memset.ha rt/strcmp.ha rt/u64tos.ha rt/unknown_errno.ha
+rt_ha = rt/+aarch64/arch_jmp.ha rt/+aarch64/cpuid.ha rt/+freebsd/+aarch64.ha rt/+freebsd/env.ha rt/+freebsd/errno.ha rt/+freebsd/initfini.ha rt/+freebsd/platform_abort.ha rt/+freebsd/platformstart-libc.ha rt/+freebsd/segmalloc.ha rt/+freebsd/signal.ha rt/+freebsd/socket.ha rt/+freebsd/start.ha rt/+freebsd/syscallno.ha rt/+freebsd/syscalls.ha rt/+freebsd/types.ha rt/abort.ha rt/ensure.ha rt/fenv_defs.ha rt/heap-libc.ha rt/jmp.ha rt/malloc.ha rt/memcpy.ha rt/memfunc_ptr.ha rt/memmove.ha rt/memset.ha rt/strcmp.ha rt/u64tos.ha rt/unknown_errno.ha
$(HARECACHE)/rt.ssa: $(rt_ha)
@mkdir -p -- "$(HARECACHE)"
@printf 'HAREC\t%s\n' "$@"
diff --git a/makefiles/freebsd.riscv64.mk b/makefiles/freebsd.riscv64.mk
@@ -4,7 +4,7 @@ TDENV = env HARE_TD_rt=$(HARECACHE)/rt.td HARE_TD_types=$(HARECACHE)/types.td HA
RTSCRIPT = rt/+freebsd/hare.sc
OBJS = $(HARECACHE)/rt.o $(HARECACHE)/types.o $(HARECACHE)/bytes.o $(HARECACHE)/encoding_utf8.o $(HARECACHE)/sort_cmp.o $(HARECACHE)/strings.o $(HARECACHE)/ascii.o $(HARECACHE)/errors.o $(HARECACHE)/io.o $(HARECACHE)/bufio.o $(HARECACHE)/crypto_math.o $(HARECACHE)/endian.o $(HARECACHE)/hash.o $(HARECACHE)/crypto_sha256.o $(HARECACHE)/math.o $(HARECACHE)/memio.o $(HARECACHE)/path.o $(HARECACHE)/time.o $(HARECACHE)/fs.o $(HARECACHE)/types_c.o $(HARECACHE)/os.o $(HARECACHE)/strconv.o $(HARECACHE)/fmt.o $(HARECACHE)/encoding_hex.o $(HARECACHE)/sort.o $(HARECACHE)/hare_lex.o $(HARECACHE)/hare_ast.o $(HARECACHE)/hare_parse.o $(HARECACHE)/hare_unparse.o $(HARECACHE)/hare_module.o $(HARECACHE)/unix.o $(HARECACHE)/unix_signal.o $(HARECACHE)/os_exec.o $(HARECACHE)/shlex.o $(HARECACHE)/unix_tty.o $(HARECACHE)/cmd_hare_build.o $(HARECACHE)/dirs.o $(HARECACHE)/getopt.o $(HARECACHE)/cmd_hare.o
-rt_ha = rt/+freebsd/+riscv64.ha rt/+freebsd/env.ha rt/+freebsd/errno.ha rt/+freebsd/initfini.ha rt/+freebsd/platform_abort.ha rt/+freebsd/platformstart-libc.ha rt/+freebsd/segmalloc.ha rt/+freebsd/signal.ha rt/+freebsd/socket.ha rt/+freebsd/start.ha rt/+freebsd/syscallno.ha rt/+freebsd/syscalls.ha rt/+freebsd/types.ha rt/+riscv64/arch_jmp.ha rt/+riscv64/cpuid.ha rt/abort.ha rt/ensure.ha rt/fenv_defs.ha rt/jmp.ha rt/malloc.ha rt/memcpy.ha rt/memfunc_ptr.ha rt/memmove.ha rt/memset.ha rt/strcmp.ha rt/u64tos.ha rt/unknown_errno.ha
+rt_ha = rt/+freebsd/+riscv64.ha rt/+freebsd/env.ha rt/+freebsd/errno.ha rt/+freebsd/initfini.ha rt/+freebsd/platform_abort.ha rt/+freebsd/platformstart-libc.ha rt/+freebsd/segmalloc.ha rt/+freebsd/signal.ha rt/+freebsd/socket.ha rt/+freebsd/start.ha rt/+freebsd/syscallno.ha rt/+freebsd/syscalls.ha rt/+freebsd/types.ha rt/+riscv64/arch_jmp.ha rt/+riscv64/cpuid.ha rt/abort.ha rt/ensure.ha rt/fenv_defs.ha rt/heap-libc.ha rt/jmp.ha rt/malloc.ha rt/memcpy.ha rt/memfunc_ptr.ha rt/memmove.ha rt/memset.ha rt/strcmp.ha rt/u64tos.ha rt/unknown_errno.ha
$(HARECACHE)/rt.ssa: $(rt_ha)
@mkdir -p -- "$(HARECACHE)"
@printf 'HAREC\t%s\n' "$@"
diff --git a/makefiles/freebsd.x86_64.mk b/makefiles/freebsd.x86_64.mk
@@ -4,7 +4,7 @@ TDENV = env HARE_TD_rt=$(HARECACHE)/rt.td HARE_TD_types=$(HARECACHE)/types.td HA
RTSCRIPT = rt/+freebsd/hare.sc
OBJS = $(HARECACHE)/rt.o $(HARECACHE)/types.o $(HARECACHE)/bytes.o $(HARECACHE)/encoding_utf8.o $(HARECACHE)/sort_cmp.o $(HARECACHE)/strings.o $(HARECACHE)/ascii.o $(HARECACHE)/errors.o $(HARECACHE)/io.o $(HARECACHE)/bufio.o $(HARECACHE)/crypto_math.o $(HARECACHE)/endian.o $(HARECACHE)/hash.o $(HARECACHE)/crypto_sha256.o $(HARECACHE)/math.o $(HARECACHE)/memio.o $(HARECACHE)/path.o $(HARECACHE)/time.o $(HARECACHE)/fs.o $(HARECACHE)/types_c.o $(HARECACHE)/os.o $(HARECACHE)/strconv.o $(HARECACHE)/fmt.o $(HARECACHE)/encoding_hex.o $(HARECACHE)/sort.o $(HARECACHE)/hare_lex.o $(HARECACHE)/hare_ast.o $(HARECACHE)/hare_parse.o $(HARECACHE)/hare_unparse.o $(HARECACHE)/hare_module.o $(HARECACHE)/unix.o $(HARECACHE)/unix_signal.o $(HARECACHE)/os_exec.o $(HARECACHE)/shlex.o $(HARECACHE)/unix_tty.o $(HARECACHE)/cmd_hare_build.o $(HARECACHE)/dirs.o $(HARECACHE)/getopt.o $(HARECACHE)/cmd_hare.o
-rt_ha = rt/+freebsd/+x86_64.ha rt/+freebsd/env.ha rt/+freebsd/errno.ha rt/+freebsd/initfini.ha rt/+freebsd/platform_abort.ha rt/+freebsd/platformstart-libc.ha rt/+freebsd/segmalloc.ha rt/+freebsd/signal.ha rt/+freebsd/socket.ha rt/+freebsd/start.ha rt/+freebsd/syscallno.ha rt/+freebsd/syscalls.ha rt/+freebsd/types.ha rt/+x86_64/arch_jmp.ha rt/+x86_64/cpuid.ha rt/abort.ha rt/ensure.ha rt/fenv_defs.ha rt/jmp.ha rt/malloc.ha rt/memcpy.ha rt/memfunc_ptr.ha rt/memmove.ha rt/memset.ha rt/strcmp.ha rt/u64tos.ha rt/unknown_errno.ha
+rt_ha = rt/+freebsd/+x86_64.ha rt/+freebsd/env.ha rt/+freebsd/errno.ha rt/+freebsd/initfini.ha rt/+freebsd/platform_abort.ha rt/+freebsd/platformstart-libc.ha rt/+freebsd/segmalloc.ha rt/+freebsd/signal.ha rt/+freebsd/socket.ha rt/+freebsd/start.ha rt/+freebsd/syscallno.ha rt/+freebsd/syscalls.ha rt/+freebsd/types.ha rt/+x86_64/arch_jmp.ha rt/+x86_64/cpuid.ha rt/abort.ha rt/ensure.ha rt/fenv_defs.ha rt/heap-libc.ha rt/jmp.ha rt/malloc.ha rt/memcpy.ha rt/memfunc_ptr.ha rt/memmove.ha rt/memset.ha rt/strcmp.ha rt/u64tos.ha rt/unknown_errno.ha
$(HARECACHE)/rt.ssa: $(rt_ha)
@mkdir -p -- "$(HARECACHE)"
@printf 'HAREC\t%s\n' "$@"
diff --git a/makefiles/linux.aarch64.mk b/makefiles/linux.aarch64.mk
@@ -4,7 +4,7 @@ TDENV = env HARE_TD_rt=$(HARECACHE)/rt.td HARE_TD_types=$(HARECACHE)/types.td HA
RTSCRIPT = rt/+linux/hare.sc
OBJS = $(HARECACHE)/rt.o $(HARECACHE)/types.o $(HARECACHE)/bytes.o $(HARECACHE)/encoding_utf8.o $(HARECACHE)/sort_cmp.o $(HARECACHE)/strings.o $(HARECACHE)/ascii.o $(HARECACHE)/errors.o $(HARECACHE)/io.o $(HARECACHE)/bufio.o $(HARECACHE)/crypto_math.o $(HARECACHE)/endian.o $(HARECACHE)/hash.o $(HARECACHE)/crypto_sha256.o $(HARECACHE)/math.o $(HARECACHE)/memio.o $(HARECACHE)/path.o $(HARECACHE)/format_elf.o $(HARECACHE)/linux.o $(HARECACHE)/types_c.o $(HARECACHE)/linux_vdso.o $(HARECACHE)/time.o $(HARECACHE)/fs.o $(HARECACHE)/os.o $(HARECACHE)/strconv.o $(HARECACHE)/fmt.o $(HARECACHE)/encoding_hex.o $(HARECACHE)/sort.o $(HARECACHE)/hare_lex.o $(HARECACHE)/hare_ast.o $(HARECACHE)/hare_parse.o $(HARECACHE)/hare_unparse.o $(HARECACHE)/hare_module.o $(HARECACHE)/unix.o $(HARECACHE)/unix_signal.o $(HARECACHE)/os_exec.o $(HARECACHE)/shlex.o $(HARECACHE)/unix_tty.o $(HARECACHE)/cmd_hare_build.o $(HARECACHE)/dirs.o $(HARECACHE)/getopt.o $(HARECACHE)/cmd_hare.o
-rt_ha = rt/+aarch64/arch_jmp.ha rt/+aarch64/cpuid.ha rt/+linux/+aarch64.ha rt/+linux/env.ha rt/+linux/errno.ha rt/+linux/initfini.ha rt/+linux/platform_abort.ha rt/+linux/platformstart-libc.ha rt/+linux/prctl.ha rt/+linux/segmalloc.ha rt/+linux/signal.ha rt/+linux/socket.ha rt/+linux/start.ha rt/+linux/stat.ha rt/+linux/syscallno+aarch64.ha rt/+linux/syscalls.ha rt/+linux/types.ha rt/abort.ha rt/ensure.ha rt/fenv_defs.ha rt/jmp.ha rt/malloc.ha rt/memcpy.ha rt/memfunc_ptr.ha rt/memmove.ha rt/memset.ha rt/strcmp.ha rt/u64tos.ha rt/unknown_errno.ha
+rt_ha = rt/+aarch64/arch_jmp.ha rt/+aarch64/cpuid.ha rt/+linux/+aarch64.ha rt/+linux/env.ha rt/+linux/errno.ha rt/+linux/initfini.ha rt/+linux/platform_abort.ha rt/+linux/platformstart-libc.ha rt/+linux/prctl.ha rt/+linux/segmalloc.ha rt/+linux/signal.ha rt/+linux/socket.ha rt/+linux/start.ha rt/+linux/stat.ha rt/+linux/syscallno+aarch64.ha rt/+linux/syscalls.ha rt/+linux/types.ha rt/abort.ha rt/ensure.ha rt/fenv_defs.ha rt/heap-libc.ha rt/jmp.ha rt/malloc.ha rt/memcpy.ha rt/memfunc_ptr.ha rt/memmove.ha rt/memset.ha rt/strcmp.ha rt/u64tos.ha rt/unknown_errno.ha
$(HARECACHE)/rt.ssa: $(rt_ha)
@mkdir -p -- "$(HARECACHE)"
@printf 'HAREC\t%s\n' "$@"
diff --git a/makefiles/linux.riscv64.mk b/makefiles/linux.riscv64.mk
@@ -4,7 +4,7 @@ TDENV = env HARE_TD_rt=$(HARECACHE)/rt.td HARE_TD_types=$(HARECACHE)/types.td HA
RTSCRIPT = rt/+linux/hare.sc
OBJS = $(HARECACHE)/rt.o $(HARECACHE)/types.o $(HARECACHE)/bytes.o $(HARECACHE)/encoding_utf8.o $(HARECACHE)/sort_cmp.o $(HARECACHE)/strings.o $(HARECACHE)/ascii.o $(HARECACHE)/errors.o $(HARECACHE)/io.o $(HARECACHE)/bufio.o $(HARECACHE)/crypto_math.o $(HARECACHE)/endian.o $(HARECACHE)/hash.o $(HARECACHE)/crypto_sha256.o $(HARECACHE)/math.o $(HARECACHE)/memio.o $(HARECACHE)/path.o $(HARECACHE)/format_elf.o $(HARECACHE)/linux.o $(HARECACHE)/types_c.o $(HARECACHE)/linux_vdso.o $(HARECACHE)/time.o $(HARECACHE)/fs.o $(HARECACHE)/os.o $(HARECACHE)/strconv.o $(HARECACHE)/fmt.o $(HARECACHE)/encoding_hex.o $(HARECACHE)/sort.o $(HARECACHE)/hare_lex.o $(HARECACHE)/hare_ast.o $(HARECACHE)/hare_parse.o $(HARECACHE)/hare_unparse.o $(HARECACHE)/hare_module.o $(HARECACHE)/unix.o $(HARECACHE)/unix_signal.o $(HARECACHE)/os_exec.o $(HARECACHE)/shlex.o $(HARECACHE)/unix_tty.o $(HARECACHE)/cmd_hare_build.o $(HARECACHE)/dirs.o $(HARECACHE)/getopt.o $(HARECACHE)/cmd_hare.o
-rt_ha = rt/+linux/+riscv64.ha rt/+linux/env.ha rt/+linux/errno.ha rt/+linux/initfini.ha rt/+linux/platform_abort.ha rt/+linux/platformstart-libc.ha rt/+linux/prctl.ha rt/+linux/segmalloc.ha rt/+linux/signal.ha rt/+linux/socket.ha rt/+linux/start.ha rt/+linux/stat.ha rt/+linux/syscallno+riscv64.ha rt/+linux/syscalls.ha rt/+linux/types.ha rt/+riscv64/arch_jmp.ha rt/+riscv64/cpuid.ha rt/abort.ha rt/ensure.ha rt/fenv_defs.ha rt/jmp.ha rt/malloc.ha rt/memcpy.ha rt/memfunc_ptr.ha rt/memmove.ha rt/memset.ha rt/strcmp.ha rt/u64tos.ha rt/unknown_errno.ha
+rt_ha = rt/+linux/+riscv64.ha rt/+linux/env.ha rt/+linux/errno.ha rt/+linux/initfini.ha rt/+linux/platform_abort.ha rt/+linux/platformstart-libc.ha rt/+linux/prctl.ha rt/+linux/segmalloc.ha rt/+linux/signal.ha rt/+linux/socket.ha rt/+linux/start.ha rt/+linux/stat.ha rt/+linux/syscallno+riscv64.ha rt/+linux/syscalls.ha rt/+linux/types.ha rt/+riscv64/arch_jmp.ha rt/+riscv64/cpuid.ha rt/abort.ha rt/ensure.ha rt/fenv_defs.ha rt/heap-libc.ha rt/jmp.ha rt/malloc.ha rt/memcpy.ha rt/memfunc_ptr.ha rt/memmove.ha rt/memset.ha rt/strcmp.ha rt/u64tos.ha rt/unknown_errno.ha
$(HARECACHE)/rt.ssa: $(rt_ha)
@mkdir -p -- "$(HARECACHE)"
@printf 'HAREC\t%s\n' "$@"
diff --git a/makefiles/linux.x86_64.mk b/makefiles/linux.x86_64.mk
@@ -4,7 +4,7 @@ TDENV = env HARE_TD_rt=$(HARECACHE)/rt.td HARE_TD_types=$(HARECACHE)/types.td HA
RTSCRIPT = rt/+linux/hare.sc
OBJS = $(HARECACHE)/rt.o $(HARECACHE)/types.o $(HARECACHE)/bytes.o $(HARECACHE)/encoding_utf8.o $(HARECACHE)/sort_cmp.o $(HARECACHE)/strings.o $(HARECACHE)/ascii.o $(HARECACHE)/errors.o $(HARECACHE)/io.o $(HARECACHE)/bufio.o $(HARECACHE)/crypto_math.o $(HARECACHE)/endian.o $(HARECACHE)/hash.o $(HARECACHE)/crypto_sha256.o $(HARECACHE)/math.o $(HARECACHE)/memio.o $(HARECACHE)/path.o $(HARECACHE)/format_elf.o $(HARECACHE)/linux.o $(HARECACHE)/types_c.o $(HARECACHE)/linux_vdso.o $(HARECACHE)/time.o $(HARECACHE)/fs.o $(HARECACHE)/os.o $(HARECACHE)/strconv.o $(HARECACHE)/fmt.o $(HARECACHE)/encoding_hex.o $(HARECACHE)/sort.o $(HARECACHE)/hare_lex.o $(HARECACHE)/hare_ast.o $(HARECACHE)/hare_parse.o $(HARECACHE)/hare_unparse.o $(HARECACHE)/hare_module.o $(HARECACHE)/unix.o $(HARECACHE)/unix_signal.o $(HARECACHE)/os_exec.o $(HARECACHE)/shlex.o $(HARECACHE)/unix_tty.o $(HARECACHE)/cmd_hare_build.o $(HARECACHE)/dirs.o $(HARECACHE)/getopt.o $(HARECACHE)/cmd_hare.o
-rt_ha = rt/+linux/+x86_64.ha rt/+linux/env.ha rt/+linux/errno.ha rt/+linux/initfini.ha rt/+linux/platform_abort.ha rt/+linux/platformstart-libc.ha rt/+linux/prctl.ha rt/+linux/segmalloc.ha rt/+linux/signal.ha rt/+linux/socket.ha rt/+linux/start.ha rt/+linux/stat.ha rt/+linux/syscallno+x86_64.ha rt/+linux/syscalls.ha rt/+linux/types.ha rt/+x86_64/arch_jmp.ha rt/+x86_64/cpuid.ha rt/abort.ha rt/ensure.ha rt/fenv_defs.ha rt/jmp.ha rt/malloc.ha rt/memcpy.ha rt/memfunc_ptr.ha rt/memmove.ha rt/memset.ha rt/strcmp.ha rt/u64tos.ha rt/unknown_errno.ha
+rt_ha = rt/+linux/+x86_64.ha rt/+linux/env.ha rt/+linux/errno.ha rt/+linux/initfini.ha rt/+linux/platform_abort.ha rt/+linux/platformstart-libc.ha rt/+linux/prctl.ha rt/+linux/segmalloc.ha rt/+linux/signal.ha rt/+linux/socket.ha rt/+linux/start.ha rt/+linux/stat.ha rt/+linux/syscallno+x86_64.ha rt/+linux/syscalls.ha rt/+linux/types.ha rt/+x86_64/arch_jmp.ha rt/+x86_64/cpuid.ha rt/abort.ha rt/ensure.ha rt/fenv_defs.ha rt/heap-libc.ha rt/jmp.ha rt/malloc.ha rt/memcpy.ha rt/memfunc_ptr.ha rt/memmove.ha rt/memset.ha rt/strcmp.ha rt/u64tos.ha rt/unknown_errno.ha
$(HARECACHE)/rt.ssa: $(rt_ha)
@mkdir -p -- "$(HARECACHE)"
@printf 'HAREC\t%s\n' "$@"
diff --git a/makefiles/netbsd.aarch64.mk b/makefiles/netbsd.aarch64.mk
@@ -4,7 +4,7 @@ TDENV = env HARE_TD_rt=$(HARECACHE)/rt.td HARE_TD_types=$(HARECACHE)/types.td HA
RTSCRIPT = rt/+netbsd/hare.sc
OBJS = $(HARECACHE)/rt.o $(HARECACHE)/types.o $(HARECACHE)/bytes.o $(HARECACHE)/encoding_utf8.o $(HARECACHE)/sort_cmp.o $(HARECACHE)/strings.o $(HARECACHE)/ascii.o $(HARECACHE)/errors.o $(HARECACHE)/io.o $(HARECACHE)/bufio.o $(HARECACHE)/crypto_math.o $(HARECACHE)/endian.o $(HARECACHE)/hash.o $(HARECACHE)/crypto_sha256.o $(HARECACHE)/math.o $(HARECACHE)/memio.o $(HARECACHE)/path.o $(HARECACHE)/time.o $(HARECACHE)/fs.o $(HARECACHE)/types_c.o $(HARECACHE)/os.o $(HARECACHE)/strconv.o $(HARECACHE)/fmt.o $(HARECACHE)/encoding_hex.o $(HARECACHE)/sort.o $(HARECACHE)/hare_lex.o $(HARECACHE)/hare_ast.o $(HARECACHE)/hare_parse.o $(HARECACHE)/hare_unparse.o $(HARECACHE)/hare_module.o $(HARECACHE)/unix.o $(HARECACHE)/unix_signal.o $(HARECACHE)/os_exec.o $(HARECACHE)/shlex.o $(HARECACHE)/unix_tty.o $(HARECACHE)/cmd_hare_build.o $(HARECACHE)/dirs.o $(HARECACHE)/getopt.o $(HARECACHE)/cmd_hare.o
-rt_ha = rt/+aarch64/arch_jmp.ha rt/+aarch64/cpuid.ha rt/+netbsd/env.ha rt/+netbsd/errno.ha rt/+netbsd/initfini.ha rt/+netbsd/platform_abort.ha rt/+netbsd/platformstart-libc.ha rt/+netbsd/segmalloc.ha rt/+netbsd/signal.ha rt/+netbsd/socket.ha rt/+netbsd/start.ha rt/+netbsd/syscallno.ha rt/+netbsd/syscalls.ha rt/+netbsd/sysctl.ha rt/+netbsd/types.ha rt/abort.ha rt/ensure.ha rt/fenv_defs.ha rt/jmp.ha rt/malloc.ha rt/memcpy.ha rt/memfunc_ptr.ha rt/memmove.ha rt/memset.ha rt/strcmp.ha rt/u64tos.ha rt/unknown_errno.ha
+rt_ha = rt/+aarch64/arch_jmp.ha rt/+aarch64/cpuid.ha rt/+netbsd/env.ha rt/+netbsd/errno.ha rt/+netbsd/initfini.ha rt/+netbsd/platform_abort.ha rt/+netbsd/platformstart-libc.ha rt/+netbsd/segmalloc.ha rt/+netbsd/signal.ha rt/+netbsd/socket.ha rt/+netbsd/start.ha rt/+netbsd/syscallno.ha rt/+netbsd/syscalls.ha rt/+netbsd/sysctl.ha rt/+netbsd/types.ha rt/abort.ha rt/ensure.ha rt/fenv_defs.ha rt/heap-libc.ha rt/jmp.ha rt/malloc.ha rt/memcpy.ha rt/memfunc_ptr.ha rt/memmove.ha rt/memset.ha rt/strcmp.ha rt/u64tos.ha rt/unknown_errno.ha
$(HARECACHE)/rt.ssa: $(rt_ha)
@mkdir -p -- "$(HARECACHE)"
@printf 'HAREC\t%s\n' "$@"
diff --git a/makefiles/netbsd.riscv64.mk b/makefiles/netbsd.riscv64.mk
@@ -4,7 +4,7 @@ TDENV = env HARE_TD_rt=$(HARECACHE)/rt.td HARE_TD_types=$(HARECACHE)/types.td HA
RTSCRIPT = rt/+netbsd/hare.sc
OBJS = $(HARECACHE)/rt.o $(HARECACHE)/types.o $(HARECACHE)/bytes.o $(HARECACHE)/encoding_utf8.o $(HARECACHE)/sort_cmp.o $(HARECACHE)/strings.o $(HARECACHE)/ascii.o $(HARECACHE)/errors.o $(HARECACHE)/io.o $(HARECACHE)/bufio.o $(HARECACHE)/crypto_math.o $(HARECACHE)/endian.o $(HARECACHE)/hash.o $(HARECACHE)/crypto_sha256.o $(HARECACHE)/math.o $(HARECACHE)/memio.o $(HARECACHE)/path.o $(HARECACHE)/time.o $(HARECACHE)/fs.o $(HARECACHE)/types_c.o $(HARECACHE)/os.o $(HARECACHE)/strconv.o $(HARECACHE)/fmt.o $(HARECACHE)/encoding_hex.o $(HARECACHE)/sort.o $(HARECACHE)/hare_lex.o $(HARECACHE)/hare_ast.o $(HARECACHE)/hare_parse.o $(HARECACHE)/hare_unparse.o $(HARECACHE)/hare_module.o $(HARECACHE)/unix.o $(HARECACHE)/unix_signal.o $(HARECACHE)/os_exec.o $(HARECACHE)/shlex.o $(HARECACHE)/unix_tty.o $(HARECACHE)/cmd_hare_build.o $(HARECACHE)/dirs.o $(HARECACHE)/getopt.o $(HARECACHE)/cmd_hare.o
-rt_ha = rt/+netbsd/env.ha rt/+netbsd/errno.ha rt/+netbsd/initfini.ha rt/+netbsd/platform_abort.ha rt/+netbsd/platformstart-libc.ha rt/+netbsd/segmalloc.ha rt/+netbsd/signal.ha rt/+netbsd/socket.ha rt/+netbsd/start.ha rt/+netbsd/syscallno.ha rt/+netbsd/syscalls.ha rt/+netbsd/sysctl.ha rt/+netbsd/types.ha rt/+riscv64/arch_jmp.ha rt/+riscv64/cpuid.ha rt/abort.ha rt/ensure.ha rt/fenv_defs.ha rt/jmp.ha rt/malloc.ha rt/memcpy.ha rt/memfunc_ptr.ha rt/memmove.ha rt/memset.ha rt/strcmp.ha rt/u64tos.ha rt/unknown_errno.ha
+rt_ha = rt/+netbsd/env.ha rt/+netbsd/errno.ha rt/+netbsd/initfini.ha rt/+netbsd/platform_abort.ha rt/+netbsd/platformstart-libc.ha rt/+netbsd/segmalloc.ha rt/+netbsd/signal.ha rt/+netbsd/socket.ha rt/+netbsd/start.ha rt/+netbsd/syscallno.ha rt/+netbsd/syscalls.ha rt/+netbsd/sysctl.ha rt/+netbsd/types.ha rt/+riscv64/arch_jmp.ha rt/+riscv64/cpuid.ha rt/abort.ha rt/ensure.ha rt/fenv_defs.ha rt/heap-libc.ha rt/jmp.ha rt/malloc.ha rt/memcpy.ha rt/memfunc_ptr.ha rt/memmove.ha rt/memset.ha rt/strcmp.ha rt/u64tos.ha rt/unknown_errno.ha
$(HARECACHE)/rt.ssa: $(rt_ha)
@mkdir -p -- "$(HARECACHE)"
@printf 'HAREC\t%s\n' "$@"
diff --git a/makefiles/netbsd.x86_64.mk b/makefiles/netbsd.x86_64.mk
@@ -4,7 +4,7 @@ TDENV = env HARE_TD_rt=$(HARECACHE)/rt.td HARE_TD_types=$(HARECACHE)/types.td HA
RTSCRIPT = rt/+netbsd/hare.sc
OBJS = $(HARECACHE)/rt.o $(HARECACHE)/types.o $(HARECACHE)/bytes.o $(HARECACHE)/encoding_utf8.o $(HARECACHE)/sort_cmp.o $(HARECACHE)/strings.o $(HARECACHE)/ascii.o $(HARECACHE)/errors.o $(HARECACHE)/io.o $(HARECACHE)/bufio.o $(HARECACHE)/crypto_math.o $(HARECACHE)/endian.o $(HARECACHE)/hash.o $(HARECACHE)/crypto_sha256.o $(HARECACHE)/math.o $(HARECACHE)/memio.o $(HARECACHE)/path.o $(HARECACHE)/time.o $(HARECACHE)/fs.o $(HARECACHE)/types_c.o $(HARECACHE)/os.o $(HARECACHE)/strconv.o $(HARECACHE)/fmt.o $(HARECACHE)/encoding_hex.o $(HARECACHE)/sort.o $(HARECACHE)/hare_lex.o $(HARECACHE)/hare_ast.o $(HARECACHE)/hare_parse.o $(HARECACHE)/hare_unparse.o $(HARECACHE)/hare_module.o $(HARECACHE)/unix.o $(HARECACHE)/unix_signal.o $(HARECACHE)/os_exec.o $(HARECACHE)/shlex.o $(HARECACHE)/unix_tty.o $(HARECACHE)/cmd_hare_build.o $(HARECACHE)/dirs.o $(HARECACHE)/getopt.o $(HARECACHE)/cmd_hare.o
-rt_ha = rt/+netbsd/+x86_64.ha rt/+netbsd/env.ha rt/+netbsd/errno.ha rt/+netbsd/initfini.ha rt/+netbsd/platform_abort.ha rt/+netbsd/platformstart-libc.ha rt/+netbsd/segmalloc.ha rt/+netbsd/signal.ha rt/+netbsd/socket.ha rt/+netbsd/start.ha rt/+netbsd/syscallno.ha rt/+netbsd/syscalls.ha rt/+netbsd/sysctl.ha rt/+netbsd/types.ha rt/+x86_64/arch_jmp.ha rt/+x86_64/cpuid.ha rt/abort.ha rt/ensure.ha rt/fenv_defs.ha rt/jmp.ha rt/malloc.ha rt/memcpy.ha rt/memfunc_ptr.ha rt/memmove.ha rt/memset.ha rt/strcmp.ha rt/u64tos.ha rt/unknown_errno.ha
+rt_ha = rt/+netbsd/+x86_64.ha rt/+netbsd/env.ha rt/+netbsd/errno.ha rt/+netbsd/initfini.ha rt/+netbsd/platform_abort.ha rt/+netbsd/platformstart-libc.ha rt/+netbsd/segmalloc.ha rt/+netbsd/signal.ha rt/+netbsd/socket.ha rt/+netbsd/start.ha rt/+netbsd/syscallno.ha rt/+netbsd/syscalls.ha rt/+netbsd/sysctl.ha rt/+netbsd/types.ha rt/+x86_64/arch_jmp.ha rt/+x86_64/cpuid.ha rt/abort.ha rt/ensure.ha rt/fenv_defs.ha rt/heap-libc.ha rt/jmp.ha rt/malloc.ha rt/memcpy.ha rt/memfunc_ptr.ha rt/memmove.ha rt/memset.ha rt/strcmp.ha rt/u64tos.ha rt/unknown_errno.ha
$(HARECACHE)/rt.ssa: $(rt_ha)
@mkdir -p -- "$(HARECACHE)"
@printf 'HAREC\t%s\n' "$@"
diff --git a/rt/heap-libc.ha b/rt/heap-libc.ha
@@ -0,0 +1,56 @@
+// SPDX-License-Identifier: MPL-2.0
+// (c) Hare authors <https://harelang.org>
+
+// A group of blocks that were allocated together.
+export type chunk = union {
+ padding: size, // TODO: track number of active allocations here
+ data: [*]u8,
+};
+
+// Metadata for a block.
+export type meta = struct {
+ union {
+ sz: size,
+ next: uintptr,
+ },
+ user: [*]u8,
+};
+
+export type memory_heap = struct {
+ // Number of allocations currently in flight.
+ cur_allocs: size,
+ // Freelists for blocks up to 2048 bytes.
+ bins: [9]nullable *meta,
+ // The chunk to allocate from if there are no blocks available in the
+ // right freelist.
+ cur_chunk: (*chunk, size),
+};
+
+// An empty memory heap, used to initialize a [[memory_heap]] for use with
+// [[setheap]].
+export def EMPTY_HEAP = memory_heap {
+ cur_allocs = 0,
+ bins = [null...],
+ cur_chunk = (null: *chunk, CHUNKSZ),
+};
+
+let static_heap = EMPTY_HEAP;
+let heap = &static_heap;
+
+// Switches the internal runtime allocator to a new memory heap. The caller
+// should provision a [[memory_heap]] initialized to [[EMPTY_HEAP]] somehow
+// (statically, or in a second memory_heap, or even on the stack if you're brave
+// enough) and pass it to this function to enable it. Returns a pointer to the
+// heap which was previously in use, should you wish to restore it later.
+//
+// The caller is responsible for ensuring that any use of free() or delete()
+// makes use of an object which was allocated (via alloc(), insert(), or
+// append()) from the same heap.
+//
+// This function is designed for debugging use, and exists in particular to
+// satisfy the needs of [[debug::]].
+export fn setheap(new_heap: *memory_heap) *memory_heap = {
+ const old = heap;
+ heap = new_heap;
+ return old;
+};
diff --git a/rt/malloc.ha b/rt/malloc.ha
@@ -5,21 +5,6 @@
// Appel, Andrew W., and David A. Naumann. "Verified sequential malloc/free"
// but with logarithmic bin sizing and additional safety checks. Not thread-safe
-// A group of blocks that were allocated together.
-export type chunk = union {
- padding: size, // TODO: track number of active allocations here
- data: [*]u8,
-};
-
-// Metadata for a block.
-export type meta = struct {
- union {
- sz: size,
- next: uintptr,
- },
- user: [*]u8,
-};
-
// Size of the header/footer for allocations.
def META: size = size(size);
@@ -37,41 +22,6 @@ def CHUNKSZ: size = 1 << 21;
// Byte to fill allocations with while they're not in use.
def POISON: u8 = 0x69;
-export type memory_heap = struct {
- // Number of allocations currently in flight.
- cur_allocs: size,
- // Freelists for blocks up to 2048 bytes.
- bins: [9]nullable *meta,
- // The chunk to allocate from if there are no blocks available in the
- // right freelist.
- cur_chunk: (*chunk, size),
-};
-
-let static_heap = memory_heap {
- cur_allocs = 0,
- bins = [null...],
- cur_chunk = (null: *chunk, CHUNKSZ),
-};
-
-let heap = &static_heap;
-
-export fn newheap() memory_heap = {
- // Re-initializes the heap from scratch, abandoning all prior memory
- // allocations and returning the previous heap.
- //
- // This function is designed to be called by debug:: in a scenario where
- // the heap has been corrupted. It abandons the corrupt heap and
- // prepares a fresh heap which debug:: can use to allocate memory for
- // any operations it needs to perform during clean-up.
- const old = *heap;
- *heap = memory_heap {
- cur_allocs = 0,
- bins = [null...],
- cur_chunk = (null: *chunk, CHUNKSZ),
- };
- return old;
-};
-
// Allocates n bytes of memory and returns a pointer to them, or null if there
// is insufficient memory.
export fn malloc(n: size) nullable *opaque = {