@@ -222,6 +222,9 @@ static struct {
222222/* Stack size for each hart coroutine (1MB - increased for complex execution) */
223223#define CORO_STACK_SIZE (1024 * 1024)
224224
225+ /* Stack canary value for overflow detection */
226+ #define STACK_CANARY_VALUE 0xDEADBEEFCAFEBABEULL
227+
225228/* Sentinel value for current_hart when no coroutine is running */
226229#define CORO_HART_ID_IDLE UINT32_MAX
227230
@@ -241,6 +244,26 @@ static inline void coro_clear_running_state(void)
241244 tls_running_coro = NULL ;
242245}
243246
247+ /* Get pointer to stack canary (placed at bottom of stack buffer) */
248+ static inline uint64_t * coro_get_canary_ptr (coro_t * co )
249+ {
250+ return (uint64_t * ) co -> stack_base ;
251+ }
252+
253+ /* Check for stack overflow by verifying the canary value in stack buffer */
254+ static inline void coro_check_stack (coro_t * co )
255+ {
256+ uint64_t * canary_ptr = coro_get_canary_ptr (co );
257+ if (* canary_ptr != STACK_CANARY_VALUE ) {
258+ fprintf (stderr ,
259+ "FATAL: Stack overflow detected in coroutine! "
260+ "Expected canary=0x%llx, got=0x%llx at %p\n" ,
261+ (unsigned long long ) STACK_CANARY_VALUE ,
262+ (unsigned long long ) * canary_ptr , (void * ) canary_ptr );
263+ abort ();
264+ }
265+ }
266+
244267/* Forward declarations */
245268
246269#ifdef CORO_USE_ASM
@@ -483,12 +506,22 @@ bool coro_create_hart(uint32_t hart_id, void (*func)(void *), void *hart)
483506 return false;
484507 }
485508
486- /* Initialize context */
509+ /* Place canary at bottom of stack buffer (first 8 bytes)
510+ * Stack grows downward from top, so overflow will hit canary first */
511+ uint64_t * canary_ptr = coro_get_canary_ptr (co );
512+ * canary_ptr = STACK_CANARY_VALUE ;
513+
514+ /* Adjust usable stack to skip canary area
515+ * Stack starts after the canary (bottom + sizeof(uint64_t)) */
516+ void * usable_stack_base = (uint8_t * ) co -> stack_base + sizeof (uint64_t );
517+ size_t usable_stack_size = co -> stack_size - sizeof (uint64_t );
518+
519+ /* Initialize context with adjusted stack bounds */
487520#ifdef CORO_USE_ASM
488- make_context (co , & co -> context -> ctx , co -> stack_base , co -> stack_size );
521+ make_context (co , & co -> context -> ctx , usable_stack_base , usable_stack_size );
489522#else
490- if (make_context (co , & co -> context -> ctx , co -> stack_base , co -> stack_size ) !=
491- 0 ) {
523+ if (make_context (co , & co -> context -> ctx , usable_stack_base ,
524+ usable_stack_size ) != 0 ) {
492525 free (co -> stack_base );
493526 free (co -> context );
494527 free (co );
@@ -520,9 +553,15 @@ void coro_resume_hart(uint32_t hart_id)
520553 return ;
521554 }
522555
556+ /* Check for stack overflow before resuming */
557+ coro_check_stack (co );
558+
523559 coro_state .current_hart = hart_id ;
524560 co -> state = CORO_STATE_RUNNING ;
525561 jump_into (co );
562+
563+ /* Check for stack overflow after returning from coroutine */
564+ coro_check_stack (co );
526565}
527566
528567void coro_yield (void )
0 commit comments