Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions src/timeout.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,13 @@ void _twin_run_timeout(void)
twin_timeout_t *first = (twin_timeout_t *) _twin_queue_set_order(&head);
for (timeout = first; timeout && twin_time_compare(now, >=, timeout->time);
timeout = (twin_timeout_t *) timeout->queue.order) {
/* Validate closure pointer before executing timeout callback */
if (!twin_pointer_valid(timeout->closure)) {
/* Invalid closure pointer, remove this timeout */
_twin_queue_delete(&head, &timeout->queue);
continue;
}

delay = (*timeout->proc)(now, timeout->closure);
if (delay >= 0) {
timeout->time = twin_now() + delay;
Expand All @@ -68,6 +75,12 @@ twin_timeout_t *twin_set_timeout(twin_timeout_proc_t timeout_proc,
if (!timeout)
return NULL;

/* Basic validation of closure pointer at scheduling time */
if (closure && !twin_pointer_valid(closure)) {
free(timeout);
return NULL;
}

if (!start)
start = twin_now();
timeout->delay = delay;
Expand Down
34 changes: 34 additions & 0 deletions src/twin_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -810,4 +810,38 @@ void twin_custom_widget_destroy(twin_custom_widget_t *custom);
/* Path convex hull computation */
twin_path_t *twin_path_convex_hull(twin_path_t *path);

/*
* Memory pointer validation
*
* This defines the minimum valid pointer address for closure validation.
* Different environments have different memory layouts:
*
* - Unix-like systems (Linux/BSD/macOS/Solaris): First 4KB (0x1000) typically
* unmapped
* - Windows: First 64KB (0x10000) reserved
* - Bare-metal: May have valid memory starting at 0x0
*/
#ifndef TWIN_POINTER_MIN_VALID
#if defined(_WIN32) || defined(_WIN64)
#define TWIN_POINTER_MIN_VALID 0x10000 /* Windows: 64KB */
#elif defined(__unix__) || defined(__unix) || defined(unix) || \
(defined(__APPLE__) && defined(__MACH__)) || defined(__linux__) || \
defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || \
defined(__DragonFly__) || defined(__sun) || defined(__HAIKU__) || \
defined(__ANDROID__)
#define TWIN_POINTER_MIN_VALID 0x1000 /* Unix-like: 4KB */
#else
#define TWIN_POINTER_MIN_VALID 0x100 /* Bare-metal/embedded: 256 bytes */
#endif
#endif

/*
* Validate a pointer for basic sanity
* Returns true if the pointer appears to be valid
*/
static inline bool twin_pointer_valid(const void *ptr)
{
return ptr && (uintptr_t) ptr >= TWIN_POINTER_MIN_VALID;
}

#endif /* _TWIN_PRIVATE_H_ */
16 changes: 15 additions & 1 deletion src/work.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,17 @@ void _twin_run_work(void)
twin_work_t *first;

first = (twin_work_t *) _twin_queue_set_order(&head);
for (work = first; work; work = (twin_work_t *) work->queue.order)
for (work = first; work; work = (twin_work_t *) work->queue.order) {
/* Validate closure pointer before executing callback */
if (!twin_pointer_valid(work->closure)) {
/* Invalid closure pointer, remove this work item */
_twin_queue_delete(&head, &work->queue);
continue;
}

if (!(*work->proc)(work->closure))
_twin_queue_delete(&head, &work->queue);
}
_twin_queue_review_order(&first->queue);
}

Expand All @@ -46,6 +54,12 @@ twin_work_t *twin_set_work(twin_work_proc_t work_proc,
if (!work)
return NULL;

/* Basic validation of closure pointer at scheduling time */
if (closure && !twin_pointer_valid(closure)) {
free(work);
return NULL;
}

work->proc = work_proc;
work->priority = priority;
work->closure = closure;
Expand Down