Skip to content

Commit bb10925

Browse files
authored
Merge pull request #105 from sysprog21/coro-safety
Add stack overflow detection for coroutines
2 parents 8f0c958 + 5093626 commit bb10925

File tree

1 file changed

+43
-4
lines changed

1 file changed

+43
-4
lines changed

coro.c

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -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

528567
void coro_yield(void)

0 commit comments

Comments
 (0)