From: Axy Date: Mon, 11 May 2026 16:18:46 +0000 (+0200) Subject: Broken impl but patching works X-Git-Url: https://git.uwuaxy.net/?a=commitdiff_plain;h=9aa4be07c4fabebf49f506ae68ed21c3c5aac075;p=axy%2Fft%2Fc-cera.git Broken impl but patching works --- diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..3550a30 --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use flake diff --git a/.gitignore b/.gitignore index e6c1414..a9c38b7 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,6 @@ *.a .norm a.out -a.out +vgcore.* +.direnv +.norm_fail diff --git a/Makefile b/Makefile index b8aa594..275ecad 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,8 @@ NAME=ccera.a -SRCS=src/arc.c src/defer2.c src/defer.c src/eval.c src/panic.c src/value_destroy.c src/value_get.c src/value_lifetime.c src/value_new.c src/value_readf.c +SRCS=src/arc.c src/defer.c src/eval.c src/jmp.c src/panic.c src/value_destroy.c src/value_get.c src/value_lifetime.c src/value_new.c src/value_readf.c -HEADERS=src/ccera.h +HEADERS=src/ccera.h src/defer.h src/jmp.h src/panic.h BUILDDIR=.build @@ -10,11 +10,12 @@ THIS=Makefile OBJS=${SRCS:src/%.c=${BUILDDIR}/%.o} -# no malloc leak detection as our union shenanigans trigger false positives -CFLAGS=-Wall -Wextra -Werror -g -pthread -flto -ffat-lto-objects -fanalyzer -Wno-analyzer-malloc-leak -CFLAGS += -O3 +CFLAGS=-Wall -Wextra -Werror -pthread -std=gnu23 +CFLAGS += -g +#CFLAGS += -O3 +#CFLAGS += -flto -ffat-lto-objects -CC=gcc +CC=clang AR=ar @@ -59,7 +60,7 @@ build-watch: watch -c -n 1 make a.out: test.c ${NAME} ${THIS} - ${CC} ${CFLAGS} ccera.a test.c + ${CC} ${CFLAGS} test.c ccera.a test: a.out valgrind ./a.out diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..25f9b72 --- /dev/null +++ b/flake.lock @@ -0,0 +1,27 @@ +{ + "nodes": { + "nixpkgs": { + "locked": { + "lastModified": 1778274207, + "narHash": "sha256-I4puXmX1iovcCHZlRmztO3vW0mAbbRvq4F8wgIMQ1MM=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "b3da656039dc7a6240f27b2ef8cc6a3ef3bccae7", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "nixpkgs": "nixpkgs" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..cc7ca1f --- /dev/null +++ b/flake.nix @@ -0,0 +1,22 @@ +{ + description = "Cera in C!"; + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; + }; + outputs = + { + nixpkgs, + ... + }: + let + system = "x86_64-linux"; + pkgs = import nixpkgs { inherit system; }; + in + { + devShells."${system}".default = pkgs.mkShell { + packages = with pkgs; [ + clang + ]; + }; + }; +} diff --git a/src/ccera.h b/src/ccera.h index 6c5b13d..06a714f 100644 --- a/src/ccera.h +++ b/src/ccera.h @@ -6,7 +6,7 @@ /* By: agilliar +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2026/04/29 16:08:57 by agilliar #+# #+# */ -/* Updated: 2026/05/06 18:37:26 by agilliar ### ########.fr */ +/* Updated: 2026/05/10 22:11:53 by agilliar ### ########.fr */ /* */ /* ************************************************************************** */ @@ -15,6 +15,11 @@ # include # include +# include + +# include "jmp.h" +# include "defer.h" +# include "panic.h" # if UINTPTR_MAX != 0xFFFFFFFFFFFFFFFF # error "Platform's pointers are not 64 bits" @@ -23,50 +28,6 @@ typedef uintptr_t t_usize; typedef intptr_t t_isize; -struct s_defer_pair -{ - void (*f)(void *); - void *dat; - bool err; -}; - -# define MAX_DEFERS 8 - -typedef struct s_defer -{ - struct s_defer *prev; - struct s_defer *next; - t_usize len; - struct s_defer_pair defers[MAX_DEFERS]; -} t_defer; - -__attribute__((__always_inline__)) -inline void *foo(void) -{ - return (__builtin_alloca(10)); -} - -void defer_new(t_defer *store); -void defer_delete(t_defer *store); -void defer_re(t_defer *store); - -void defer(void *f, void *dat); -void errdefer(void *f, void *dat); -void defer_exit(t_defer *until); - -typedef struct s_panic_info -{ - void *data; - intptr_t jmp[5]; - t_defer *defer; -} t_panic_info; - -void *catch(void (f)(void *), void *dat); - -void panic(void *err) - __attribute__((noreturn, nonnull(1))); -bool panicking(void); - typedef union u_value t_value; typedef t_value (*t_builtin)(t_value); diff --git a/src/defer.c b/src/defer.c index 55b8a8f..f1fe0e3 100644 --- a/src/defer.c +++ b/src/defer.c @@ -6,67 +6,86 @@ /* By: agilliar +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2026/05/05 17:31:36 by agilliar #+# #+# */ -/* Updated: 2026/05/06 18:37:20 by agilliar ### ########.fr */ +/* Updated: 2026/05/11 04:13:54 by agilliar ### ########.fr */ /* */ /* ************************************************************************** */ -#include "ccera.h" -#include +#include "defer.h" +#include -t_defer **defer_store(void); +static_assert((sizeof(t_defer_frame)) == 32); +#define T_DEFER_FRAME_SIZE "32" -void defer(void *f, void *dat) -{ - t_defer *store; +static_assert((alignof(t_defer_frame)) == 8); +#define T_DEFER_FRAME_ALIGN "8" - store = *defer_store(); - if (store->len == MAX_DEFERS) - { - ((void (*)(void *))f)(dat); - panic("Maximum defers exeeded in scope"); - } - store->defers[store->len].f = f; - store->defers[store->len].dat = dat; - store->defers[store->len].err = false; - store->len++; -} +asm ( + ".globl _defer_store\n" + ".section .tbss,\"awT\",@nobits\n" + ".align " T_DEFER_FRAME_ALIGN "\n" + ".type _defer_store, @object\n" + ".size _defer_store, " T_DEFER_FRAME_SIZE "\n" + "_defer_store:\n" + ".zero " T_DEFER_FRAME_SIZE "\n" + ".text\n" + ); -void errdefer(void *f, void *dat) -{ - t_defer *store; +// TODO: impl +// +//typedef struct s_defer_frame +//{ +// void *ret_ptr; +// void *stack_ptr; +// struct s_defer_frame *prev; +// t_defer *frame; +//} t_defer_frame; - store = *defer_store(); - if (store->len == MAX_DEFERS) - { - ((void (*)(void *))f)(dat); - panic("Maximum defers exeeded in scope"); - } - store->defers[store->len].f = f; - store->defers[store->len].dat = dat; - store->defers[store->len].err = true; - store->len++; +__attribute__((naked)) +void defer_unpatch_exit(void) +{ + asm ( + "movq %%rax, %%rdi\n" + "movq %%rdx, %%rsi\n" + "movq %%rsp, %%rdx\n" + "movq %%fs:_defer_store@TPOFF+%c0, %%rsp\n" + "pushq %%rdi\n" + "pushq %%rsi\n" + "pushq %%rdx\n" + "pushq %%fs:_defer_store@TPOFF+%c1\n" + "callq defer_pop_frame\n" + "popq %%rdi\n" + "popq %%rsi\n" + "popq %%rdx\n" + "popq %%rax\n" + "movq %%rsi, %%rsp\n" + "movq %%rdi, -8(%%rsp)\n" + "jmpq *%%rdi\n" + :: + "n" (offsetof(t_defer_frame, stack_ptr)), + "n" (offsetof(t_defer_frame, ret_ptr))); } -void defer_exit(t_defer *until) +// TODO: impl +//typedef struct s_defer +//{ +// struct s_defer *prev; +// void (*f)(void *); +// void *dat; +// bool err; +//} t_defer; + +__attribute__((used)) +void defer_pop_frame(bool err) { - t_usize i; - t_defer *store; - struct s_defer_pair curr; + t_defer *curr; - store = *defer_store(); - while (store) + curr = defer_store()->frame; + while (curr) { - i = 0; - while (i < store->len) - { - curr = store->defers[i++]; - if (!panicking() && curr.err) - continue ; - curr.f(curr.dat); - } - if (store == until) - break ; - store = store->prev; + if (err || (!curr->err)) + curr->f(curr->dat); + curr = curr->prev; } - *defer_store() = store; + if (defer_store()->prev) + *defer_store() = *defer_store()->prev; } diff --git a/src/defer.h b/src/defer.h new file mode 100644 index 0000000..6e3e62b --- /dev/null +++ b/src/defer.h @@ -0,0 +1,106 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* defer.h :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: agilliar +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2026/05/10 22:08:53 by agilliar #+# #+# */ +/* Updated: 2026/05/11 04:46:59 by agilliar ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#ifndef DEFER_H +# define DEFER_H + +# include + +typedef struct s_defer +{ + struct s_defer *prev; + void (*f)(void *); + void *dat; + bool err; +} t_defer; + +typedef struct s_defer_frame +{ + void *ret_ptr; + void *stack_ptr; + struct s_defer_frame *prev; + t_defer *frame; +} t_defer_frame; + +__attribute__((always_inline)) +static inline t_defer_frame *defer_store(void) +{ + extern __thread t_defer_frame _defer_store; + + return (&_defer_store); +} +void defer_unpatch_exit(void) + __attribute__((naked)); + +// Store current rsp + red zone, aligned down to stack align +// No clang 22, so no __builtin_stack_address +__attribute__((always_inline)) +static inline void defer_stack_update(void) +{ + void *addr; + + asm ("leaq -128(%%rsp), %0\n" : "=r" (addr)); + //defer_store()->stack_ptr = __builtin_align_down(addr, 16); + defer_store()->stack_ptr = (void *)((unsigned long long )addr & ~16ull); +} + +__attribute__((always_inline)) +static inline void defer_patch(void) +{ + void *ret_ptr; + t_defer_frame *prev; + t_defer_frame *curr; + + ret_ptr = __builtin_return_address(0); + if (&defer_unpatch_exit != ret_ptr) + { + asm ("movq %0, 8(%%rbp)\n" : : "r" (&defer_unpatch_exit)); + prev = __builtin_alloca(sizeof(t_defer_frame)); + curr = defer_store(); + *prev = *curr; + curr->ret_ptr = ret_ptr; + curr->frame = NULL; + } + defer_stack_update(); + ret_ptr = __builtin_return_address(0); + __builtin_assume(&defer_unpatch_exit == ret_ptr); +} + +__attribute__((always_inline)) +static inline void defer(void *f, void *dat) +{ + t_defer *curr; + + curr = __builtin_alloca(sizeof(t_defer)); + defer_patch(); + curr->prev = defer_store()->frame; + curr->f = f; + curr->dat = dat; + curr->err = false; + defer_store()->frame = curr; +} + +__attribute__((always_inline)) +static inline void errdefer(void *f, void *dat) +{ + t_defer *curr; + + curr = __builtin_alloca(sizeof(t_defer)); + defer_patch(); + curr->prev = defer_store()->frame; + curr->f = f; + curr->dat = dat; + curr->err = true; + defer_store()->frame = curr; +} + +#endif diff --git a/src/defer2.c b/src/defer2.c deleted file mode 100644 index 9a85883..0000000 --- a/src/defer2.c +++ /dev/null @@ -1,47 +0,0 @@ -/* ************************************************************************** */ -/* */ -/* ::: :::::::: */ -/* defer2.c :+: :+: :+: */ -/* +:+ +:+ +:+ */ -/* By: agilliar +#+ +:+ +#+ */ -/* +#+#+#+#+#+ +#+ */ -/* Created: 2026/05/06 02:23:38 by agilliar #+# #+# */ -/* Updated: 2026/05/06 02:32:07 by agilliar ### ########.fr */ -/* */ -/* ************************************************************************** */ - -#include "ccera.h" -#include - -t_defer **defer_store(void) -{ - static __thread t_defer *store = NULL; - - return (&store); -} - -void defer_new(t_defer *store) -{ - store->len = 0; - store->prev = *defer_store(); - if (store->prev) - store->prev->next = store; - store->next = NULL; - *defer_store() = store; -} - -void defer_delete(t_defer *store) -{ - if (store == *defer_store()) - *defer_store() = store->prev; - if (store->next) - store->next->prev = store->prev; - if (store->prev) - store->prev->next = store->next; -} - -void defer_re(t_defer *store) -{ - defer_delete(store); - defer_new(store); -} diff --git a/src/jmp.c b/src/jmp.c new file mode 100644 index 0000000..6771dba --- /dev/null +++ b/src/jmp.c @@ -0,0 +1,46 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* jmp.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: agilliar +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2026/05/10 06:19:18 by agilliar #+# #+# */ +/* Updated: 2026/05/11 04:24:42 by agilliar ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include +#include "jmp.h" + +__attribute__((returns_twice, naked)) +bool cera_setjmp(void *buf[2]) +{ + asm ( + "movq %%rbp, %c0(%%rdi)\n" + "movq %%rsp, %c1(%%rdi)\n" + "movq 0(%%rsp), %%rax\n" + "movq %%rax, %c2(%%rdi)\n" + "xorq %%rax, %%rax\n" + "retq\n" + :: + "n" (offsetof(t_jmp, base)), + "n" (offsetof(t_jmp, top)), + "n" (offsetof(t_jmp, ret))); +} + +__attribute__((noreturn, naked)) +void cera_longjmp(void *buf[2]) +{ + asm ( + "movq %c0(%%rdi), %%rbp\n" + "movq %c1(%%rdi), %%rsp\n" + "movq %c2(%%rdi), %%rax\n" + "movq %%rax, 0(%%rsp)\n" + "movl $1, %%eax\n" + "retq\n" + :: + "n" (offsetof(t_jmp, base)), + "n" (offsetof(t_jmp, top)), + "n" (offsetof(t_jmp, ret))); +} diff --git a/src/jmp.h b/src/jmp.h new file mode 100644 index 0000000..841045c --- /dev/null +++ b/src/jmp.h @@ -0,0 +1,33 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* jmp.h :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: agilliar +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2026/05/10 22:08:02 by agilliar #+# #+# */ +/* Updated: 2026/05/11 01:43:42 by agilliar ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#ifndef JMP_H +# define JMP_H + +// We are storing the return address so as to always return to the right +// function, as a defer might have patched the return address of any later +// stack frames +// Clang's impl would doom us +typedef struct s_jmp +{ + void *base; + void *top; + void *ret; +} t_jmp; + +bool cera_setjmp(void *buf[2]) + __attribute__((returns_twice, naked)); + +void cera_longjmp(void *buf[2]) + __attribute__((noreturn, naked)); + +#endif diff --git a/src/panic.c b/src/panic.c index 1b9fe7c..eb1eb10 100644 --- a/src/panic.c +++ b/src/panic.c @@ -6,23 +6,21 @@ /* By: agilliar +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2026/05/05 15:38:33 by agilliar #+# #+# */ -/* Updated: 2026/05/05 21:25:00 by agilliar ### ########.fr */ +/* Updated: 2026/05/11 02:26:13 by agilliar ### ########.fr */ /* */ /* ************************************************************************** */ #include "ccera.h" -#include -#include -#include -static t_panic_info *panic_store(void) +/* +t_panic_info *panic_store(void) { static __thread t_panic_info store; return (&store); } -void *catch(void (f)(void *), void *dat) +void *catch(void *f, void *dat) { void *res; t_defer defer_store; @@ -37,7 +35,7 @@ void *catch(void (f)(void *), void *dat) *panic_store() = prev; return (res); } - f(dat); + ((void (*)(void *))f)(dat); *panic_store() = prev; return (NULL); } @@ -54,3 +52,4 @@ bool panicking(void) { return (panic_store()->data != NULL); } +*/ diff --git a/src/panic.h b/src/panic.h new file mode 100644 index 0000000..abee2f6 --- /dev/null +++ b/src/panic.h @@ -0,0 +1,28 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* panic.h :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: agilliar +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2026/05/10 22:11:10 by agilliar #+# #+# */ +/* Updated: 2026/05/10 22:11:44 by agilliar ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#ifndef PANIC_H +# define PANIC_H + +typedef struct s_panic_info +{ + void *data; + void *jmp[2]; + t_defer *defer; +} t_panic_info; + +void *catch(void *f, void *dat); +void panic(void *err) + __attribute__((noreturn, nonnull(1))); +bool panicking(void); + +#endif diff --git a/src/value_get.c b/src/value_get.c index 43e3a19..7583e39 100644 --- a/src/value_get.c +++ b/src/value_get.c @@ -6,12 +6,11 @@ /* By: agilliar +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2026/04/30 17:27:40 by agilliar #+# #+# */ -/* Updated: 2026/05/05 21:32:17 by agilliar ### ########.fr */ +/* Updated: 2026/05/06 19:28:43 by agilliar ### ########.fr */ /* */ /* ************************************************************************** */ #include "ccera.h" -#include struct s_value_builtin *value_builtin_get(t_value value) { diff --git a/src/value_lifetime.c b/src/value_lifetime.c index c2850cb..08927c3 100644 --- a/src/value_lifetime.c +++ b/src/value_lifetime.c @@ -6,12 +6,11 @@ /* By: agilliar +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2026/05/04 02:05:48 by agilliar #+# #+# */ -/* Updated: 2026/05/05 20:37:17 by agilliar ### ########.fr */ +/* Updated: 2026/05/06 19:29:20 by agilliar ### ########.fr */ /* */ /* ************************************************************************** */ #include "ccera.h" -#include #include t_value value_copy(t_value value) diff --git a/test.c b/test.c index 1cc25a9..373e1aa 100644 --- a/test.c +++ b/test.c @@ -6,14 +6,16 @@ /* By: agilliar +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2026/04/30 17:19:58 by agilliar #+# #+# */ -/* Updated: 2026/05/06 17:58:12 by agilliar ### ########.fr */ +/* Updated: 2026/05/11 04:12:03 by agilliar ### ########.fr */ /* */ /* ************************************************************************** */ #include "src/ccera.h" #include #include +#include +/* void main2(void *s) { t_defer defer_store __attribute__((cleanup(defer_exit))); @@ -46,13 +48,20 @@ void main2(void *s) int main(void) { - char *b = foo(); - b[0] = 'a'; - b[1] = '\0'; - printf("%s\n", b); - if (char *err = catch(main2, "Hello cera!")) + char *err = catch(main2, "hello cera"); + if (err) { printf("%s\n", err); return (1); } } +*/ + +int main(void) +{ + char *orig = "hello cera!"; + char *s = malloc(strlen(orig) + 1); + defer(free, s); + char *s2 = malloc(strlen(orig) + 1); + defer(free, s2); +} diff --git a/vgcore.2443515 b/vgcore.2443515 deleted file mode 100644 index 51ffaba..0000000 Binary files a/vgcore.2443515 and /dev/null differ