SRCS=src/arc.c src/defer.c src/eval.c src/framealloc.c src/panic.c src/stacktrack.c src/value_lifetime.c src/value_list.c src/value_move.c src/value_new.c
-HEADERS=src/align.h src/arc.h src/arith.h src/ccera.h src/defer.h src/framealloc.h src/jmp.h src/memutils.h src/panic.h src/return_patch.h src/value_get.h src/value.h src/value_new.h src/value_types.h
+HEADERS=src/align.h src/arc.h src/arith.h src/ccera.h src/defer.h src/framealloc.h src/jmp.h src/memutils.h src/panic.h src/stacktrack.h src/value_get.h src/value.h src/value_new.h src/value_types.h
BUILDDIR=.build
CFLAGS += -finstrument-functions
CFLAGS += -g
CFLAGS += -O3
-CFLAGS += -flto -ffat-lto-objects
+#CFLAGS += -flto -ffat-lto-objects
CFLAGS += -fdiagnostics-color
#CC=clang
-CC=gcc
+#CC=gcc
+CC=cc
-AR=ar
+AR=gcc-ar
MAKEFLAGS += --no-print-directory
/* By: agilliar <agilliar@student.42mulhouse.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2026/04/29 16:08:57 by agilliar #+# #+# */
-/* Updated: 2026/05/13 21:17:24 by agilliar ### ########.fr */
+/* Updated: 2026/05/14 14:58:03 by agilliar ### ########.fr */
/* */
/* ************************************************************************** */
# include "value.h"
# include "arith.h"
# include "arc.h"
+# include "stacktrack.h"
// The expression value is a tuple of an evaluatable and the argument to give it
//
// move is whether said value shall be moved out
//
// This function takes ownership
-t_value expr_eval(t_value val);
+t_value expr_eval(t_value expr);
#endif
/* By: agilliar <agilliar@student.42mulhouse.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2026/05/05 17:31:36 by agilliar #+# #+# */
-/* Updated: 2026/05/12 14:02:39 by agilliar ### ########.fr */
+/* Updated: 2026/05/14 14:49:54 by agilliar ### ########.fr */
/* */
/* ************************************************************************** */
#include "defer.h"
+#include "panic.h"
t_defer_frame *defer_store(void)
{
return (&store);
}
-void defer_pop(bool err)
+void defer_pop(void)
{
t_defer *curr;
curr = defer_store()->frame;
while (curr)
{
- if (err || (!curr->err))
+ if (panicking() || (!curr->err))
curr->f(curr->dat);
curr = curr->prev;
}
+ if (defer_store()->ret_ptr)
+ defer_store()->ret_ptr();
if (defer_store()->prev)
*defer_store() = *defer_store()->prev;
}
-
-__attribute__((used))
-void *defer_pop_ret(void)
-{
- void *ret;
-
- ret = defer_store()->ret_ptr;
- defer_pop(false);
- return (ret);
-}
-
-__attribute__((naked))
-void defer_pop_shim(void)
-{
- asm (
- "pushq %rax\n"
- "pushq %rdx\n"
- "callq defer_pop_ret\n"
- "movq %rax, %rsi\n"
- "popq %rdx\n"
- "popq %rax\n"
- "pushq %rsi\n"
- "ret\n"
- );
-}
/* By: agilliar <agilliar@student.42mulhouse.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2026/05/10 22:08:53 by agilliar #+# #+# */
-/* Updated: 2026/05/13 20:54:16 by agilliar ### ########.fr */
+/* Updated: 2026/05/14 14:57:08 by agilliar ### ########.fr */
/* */
/* ************************************************************************** */
# include <stddef.h>
# include <string.h>
# include "framealloc.h"
-# include "return_patch.h"
# include "memutils.h"
+# include "stacktrack.h"
typedef struct s_defer
{
typedef struct s_defer_frame
{
- void *ret_ptr;
- void *frame_ptr;
+ void (*ret_ptr)(void);
+ size_t stacktrack_pos;
struct s_defer_frame *prev;
t_defer *frame;
} t_defer_frame;
t_defer_frame *defer_store(void);
-void defer_pop(bool err);
-void defer_pop_shim(void)
- __attribute__((naked));
+void defer_pop(void);
-__attribute__((always_inline))
+__attribute__((always_inline, no_instrument_function))
static inline void defer_patch(void)
{
t_defer_frame *prev;
t_defer_frame *curr;
- void *ret;
- if (defer_store()->frame_ptr != __builtin_frame_address(0))
+ if (defer_store()->stacktrack_pos != stacktrack_pos())
{
- ret = __builtin_return_address(0);
- return_patch(&defer_pop_shim);
prev = cera_alloca_align(sizeof(t_defer_frame), alignof(t_defer_frame));
curr = defer_store();
*prev = *curr;
- curr->ret_ptr = ret;
+ curr->ret_ptr = stacktrack_put(&defer_pop);
curr->frame = NULL;
curr->prev = prev;
- defer_store()->frame_ptr = __builtin_frame_address(0);
+ defer_store()->stacktrack_pos = stacktrack_pos();
}
}
-__attribute__((always_inline))
+__attribute__((always_inline, no_instrument_function))
static inline void defer(void *f, void *dat)
{
t_defer *curr;
defer_store()->frame = curr;
}
-__attribute__((always_inline))
+__attribute__((always_inline, no_instrument_function))
static inline void errdefer(void *f, void *dat)
{
t_defer *curr;
defer_store()->frame = curr;
}
-// Defers the given function, alloca-ing size data from the pointer
-// Not necessary for errdefer as the stack variables are still live
-// on panic
-//
-__attribute__((always_inline))
-static inline void *deferc(void *f, void *dat, size_t size)
-{
- void *b;
-
- b = cera_alloca(size);
- cera_memcpy(b, dat, size);
- defer(f, b);
- return (b);
-}
-
#endif
/* By: agilliar <agilliar@student.42mulhouse.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2026/05/04 01:21:34 by agilliar #+# #+# */
-/* Updated: 2026/05/13 22:42:06 by agilliar ### ########.fr */
+/* Updated: 2026/05/14 14:58:19 by agilliar ### ########.fr */
/* */
/* ************************************************************************** */
(void) arg;
(void) exprs;
(void) i;
+ return (value_new_nil());
}
// The expression value is a tuple of an evaluatable and the argument to give it
// move is whether said value shall be moved out
//
// This function takes ownership
-t_value expr_eval(t_value _expr)
+t_value expr_eval(t_value expr)
{
- t_value *expr;
t_value *eval;
t_value arg;
t_value *exprs;
uintptr_t *i;
- expr = deferc(value_drop, &_expr, sizeof(t_value));
- eval = value_list_getu(expr, 0);
- arg = value_take_nil(value_list_getu(expr, 1));
+ defer(value_drop, &expr);
+ eval = value_list_getu(&expr, 0);
+ arg = value_take_nil(value_list_getu(&expr, 1));
exprs = value_list_getu(eval, 0);
i = value_uint(value_list_getu(eval, 1));
(void) exprs;
/* By: agilliar <agilliar@student.42mulhouse.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2026/05/11 19:22:02 by agilliar #+# #+# */
-/* Updated: 2026/05/12 14:01:24 by agilliar ### ########.fr */
+/* Updated: 2026/05/14 14:58:34 by agilliar ### ########.fr */
/* */
/* ************************************************************************** */
#include "framealloc.h"
+#include "stacktrack.h"
t_framealloc *framealloc_store(void)
{
return (&store);
}
+__attribute__((no_instrument_function))
void framealloc_pop(void)
{
t_framealloc *store;
store = framealloc_store();
+ if (store->frame.ret_ptr)
+ store->frame.ret_ptr();
store->frame = *store->frame.prev;
}
-
-__attribute__((used))
-void *framealloc_pop_ret(void)
-{
- void *ret_ptr;
-
- ret_ptr = framealloc_store()->frame.ret_ptr;
- framealloc_pop();
- return (ret_ptr);
-}
-
-__attribute__((naked))
-void framealloc_pop_shim(void)
-{
- asm (
- "pushq %rax\n"
- "pushq %rdx\n"
- "callq framealloc_pop_ret\n"
- "movq %rax, %rsi\n"
- "popq %rdx\n"
- "popq %rax\n"
- "pushq %rsi\n"
- "retq\n"
- );
-}
/* By: agilliar <agilliar@student.42mulhouse.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2026/05/11 19:17:56 by agilliar #+# #+# */
-/* Updated: 2026/05/13 21:16:13 by agilliar ### ########.fr */
+/* Updated: 2026/05/14 14:53:22 by agilliar ### ########.fr */
/* */
/* ************************************************************************** */
# define FRAMEALLOC_H
# include <stddef.h>
-# include "return_patch.h"
# include "align.h"
+# include "stacktrack.h"
# ifndef FRAMEALLOC_SIZE
# define FRAMEALLOC_SIZE 32768
{
size_t used;
struct s_framealloc_frame *prev;
- void *ret_ptr;
- void *frame_ptr;
+ void (*ret_ptr)(void);
+ size_t stacktrack_pos;
} t_framealloc_frame;
typedef struct s_framealloc
} t_framealloc;
t_framealloc *framealloc_store(void);
-void framealloc_pop_shim(void)
- __attribute__((naked));
-void framealloc_pop(void);
+void framealloc_pop(void)
+ __attribute__((no_instrument_function));
-__attribute__((always_inline, malloc, alloc_size(1), alloc_align(2)))
+__attribute__((always_inline, no_instrument_function))
+__attribute__((malloc, alloc_size(1), alloc_align(2)))
static inline void *cera_alloca_align_nopatch(size_t len, size_t align)
{
t_framealloc *store;
return (res);
}
+__attribute__((no_instrument_function))
__attribute__((always_inline))
static inline void cera_alloca_patch(void)
{
t_framealloc *store;
t_framealloc_frame prev_frame;
t_framealloc_frame *frame_p;
- void *ret;
+ void (*ret)(void);
store = framealloc_store();
- if (store->frame.frame_ptr != __builtin_frame_address(0))
+ if (store->frame.stacktrack_pos != stacktrack_pos())
{
- ret = __builtin_return_address(0);
- return_patch(&framealloc_pop_shim);
+ ret = stacktrack_put(&framealloc_pop);
prev_frame = store->frame;
frame_p = cera_alloca_align_nopatch(sizeof(t_framealloc_frame),
alignof(t_framealloc_frame));
*frame_p = prev_frame;
store->frame.prev = frame_p;
store->frame.ret_ptr = ret;
- store->frame.frame_ptr = __builtin_frame_address(0);
+ store->frame.stacktrack_pos = stacktrack_pos();
}
}
-__attribute__((always_inline, malloc, alloc_size(1), alloc_align(2)))
+__attribute__((always_inline, no_instrument_function))
+__attribute__((malloc, alloc_size(1), alloc_align(2)))
static inline void *cera_alloca_align(size_t len, size_t align)
{
cera_alloca_patch();
return (cera_alloca_align_nopatch(len, align));
}
-__attribute__((always_inline, malloc, alloc_size(1)))
+__attribute__((always_inline, no_instrument_function))
+__attribute__((malloc, alloc_size(1)))
static inline void *cera_alloca(size_t len)
{
return (cera_alloca_align(len, 8));
/* By: agilliar <agilliar@student.42mulhouse.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2026/05/10 22:08:02 by agilliar #+# #+# */
-/* Updated: 2026/05/13 16:43:56 by agilliar ### ########.fr */
+/* Updated: 2026/05/14 15:33:06 by agilliar ### ########.fr */
/* */
/* ************************************************************************** */
# include <stddef.h>
+# ifdef __clang__
+
+typedef void *t_jmp[3];
+
+# else
+
typedef size_t t_jmp[3];
+# endif
+
#endif
/* By: agilliar <agilliar@student.42mulhouse.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2026/05/05 15:38:33 by agilliar #+# #+# */
-/* Updated: 2026/05/13 11:34:46 by agilliar ### ########.fr */
+/* Updated: 2026/05/14 15:27:37 by agilliar ### ########.fr */
/* */
/* ************************************************************************** */
return (&store);
}
-__attribute__((returns_nonnull))
void *catch(void *f, void *dat)
{
void *res;
t_panic_info prev;
- cera_alloca_patch();
- defer_patch();
prev = *panic_store();
- panic_store()->frame_ptr = __builtin_frame_address(0);
- if (__builtin_setjmp(&panic_store()->jmp))
+ panic_store()->stacktrack_pos = stacktrack_pos();
+ if (__builtin_setjmp((void *)&panic_store()->jmp))
{
res = panic_store()->data;
*panic_store() = prev;
__attribute__((noreturn, nonnull(1), cold))
void panic(void *err)
{
- while (defer_store()->frame_ptr != panic_store()->frame_ptr)
- defer_pop(true);
- while (framealloc_store()->frame.frame_ptr != panic_store()->frame_ptr)
- framealloc_pop();
+ while (stacktrack_pos() != panic_store()->stacktrack_pos)
+ stacktrack_pop();
panic_store()->data = err;
- __builtin_longjmp(&panic_store()->jmp, 1);
+ __builtin_longjmp((void *)&panic_store()->jmp, 1);
}
bool panicking(void)
/* By: agilliar <agilliar@student.42mulhouse.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2026/05/10 22:11:10 by agilliar #+# #+# */
-/* Updated: 2026/05/13 11:34:25 by agilliar ### ########.fr */
+/* Updated: 2026/05/14 15:09:11 by agilliar ### ########.fr */
/* */
/* ************************************************************************** */
typedef struct s_panic_info
{
- void *data;
- t_jmp jmp;
- void *frame_ptr;
+ void *data;
+ t_jmp jmp;
+ size_t stacktrack_pos;
} t_panic_info;
t_panic_info *panic_store(void);
void panic(void *err)
__attribute__((noreturn, nonnull(1)));
-void *catch(void *f, void *dat)
- __attribute__((returns_nonnull));
+void *catch(void *f, void *dat);
bool panicking(void);
#endif
+++ /dev/null
-/* ************************************************************************** */
-/* */
-/* ::: :::::::: */
-/* return_patch.h :+: :+: :+: */
-/* +:+ +:+ +:+ */
-/* By: agilliar <agilliar@student.42mulhouse.fr> +#+ +:+ +#+ */
-/* +#+#+#+#+#+ +#+ */
-/* Created: 2026/05/11 20:08:23 by agilliar #+# #+# */
-/* Updated: 2026/05/12 08:54:17 by agilliar ### ########.fr */
-/* */
-/* ************************************************************************** */
-
-#ifndef RETURN_PATCH_H
-# define RETURN_PATCH_H
-
-__attribute__((always_inline))
-static inline void return_patch(void *p)
-{
- void **frame_addr;
-
- frame_addr = __builtin_frame_address(0);
- frame_addr[1] = p;
-}
-
-#endif
/* By: agilliar <agilliar@student.42mulhouse.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2026/05/14 12:00:36 by agilliar #+# #+# */
-/* Updated: 2026/05/14 13:11:24 by agilliar ### ########.fr */
+/* Updated: 2026/05/14 15:33:45 by agilliar ### ########.fr */
/* */
/* ************************************************************************** */
#include <stdbool.h>
#include <stddef.h>
-#define RETFUNC_STACK_HEIGHT 1024
+#include "stacktrack.h"
-void ***retfunc_store(void)
+__attribute__((no_instrument_function))
+static t_stacktrack_store *stacktrack_store(void)
{
- static __thread void *stack[RETFUNC_STACK_HEIGHT];
- static __thread void **store = stack;
+ static __thread t_stacktrack_store store;
return (&store);
}
+__attribute__((no_instrument_function))
+void *stacktrack_put(void *next)
+{
+ void *prev;
+ t_stacktrack_store *store;
+
+ store = stacktrack_store();
+ prev = store->stack[store->pos];
+ store->stack[store->pos] = next;
+ return (prev);
+}
+
+__attribute__((no_instrument_function))
+size_t stacktrack_pos(void)
+{
+ return (stacktrack_store()->pos);
+}
+
__attribute__((no_instrument_function))
void __cyg_profile_func_enter(void *this_fn, void *call_site)
{
- void **store;
+ t_stacktrack_store *store;
(void) this_fn;
(void) call_site;
- store = retfunc_store();
- (*store)++;
- if (**store)
+ store = stacktrack_store();
+ store->pos++;
+ if (store->stack[store->pos])
__builtin_unreachable();
}
__attribute__((no_instrument_function))
void __cyg_profile_func_exit(void *this_fn, void *call_site)
{
- void **store;
+ t_stacktrack_store *store;
+ size_t pos;
(void) this_fn;
(void) call_site;
- store = retfunc_store();
- if (**store)
- ((void (*)(void))**store)();
- **store = NULL;
- (*store)--;
+ store = stacktrack_store();
+ pos = store->pos;
+ if (store->stack[pos])
+ {
+ ((void (*)(void))store->stack[pos])();
+ store->stack[pos] = NULL;
+ }
+ store->pos--;
}
--- /dev/null
+/* ************************************************************************** */
+/* */
+/* ::: :::::::: */
+/* stacktrack.h :+: :+: :+: */
+/* +:+ +:+ +:+ */
+/* By: agilliar <agilliar@student.42mulhouse.fr> +#+ +:+ +#+ */
+/* +#+#+#+#+#+ +#+ */
+/* Created: 2026/05/14 13:42:09 by agilliar #+# #+# */
+/* Updated: 2026/05/14 15:04:54 by agilliar ### ########.fr */
+/* */
+/* ************************************************************************** */
+
+#ifndef STACKTRACK_H
+# define STACKTRACK_H
+
+# define STACKTRACK_STACK_HEIGHT 1023
+
+# include <stddef.h>
+
+typedef struct s_stacktrack_store
+{
+ size_t pos;
+ void (*stack[STACKTRACK_STACK_HEIGHT])(void);
+} t_stacktrack_store;
+
+size_t stacktrack_pos(void)
+ __attribute__((no_instrument_function));
+
+void *stacktrack_put(void *next)
+ __attribute__((no_instrument_function));
+
+void __cyg_profile_func_exit(void *this_fn, void *call_site)
+ __attribute__((no_instrument_function));
+
+__attribute__((always_inline, no_instrument_function))
+static inline void stacktrack_pop(void)
+{
+ __cyg_profile_func_exit(NULL, NULL);
+}
+
+#endif
/* By: agilliar <agilliar@student.42mulhouse.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2026/04/30 17:19:58 by agilliar #+# #+# */
-/* Updated: 2026/05/12 14:07:55 by agilliar ### ########.fr */
+/* Updated: 2026/05/14 15:45:14 by agilliar ### ########.fr */
/* */
/* ************************************************************************** */
defer(free, s);
char *s2 = malloc(strlen(orig) + 1);
defer(free, s2);
+ strcpy(s2, orig);
+ printf("%s\n", s2);
panic("error!");
+ printf("%s\n", s2);
}
int main(void)
char *orig = "hello cera!";
char *s = malloc(strlen(orig) + 1);
- cera_alloca_align(10, 30);
+ cera_alloca_align(10, 32);
defer(free, s);
msg = catch(main2, orig);
if (msg)