Skip to content

Commit b818d67

Browse files
authored
Merge pull request #119 from sysprog21/validate-closures
Prevent crashes from invalid closures in work/timeout queues
2 parents cbfc915 + cd2830b commit b818d67

File tree

3 files changed

+62
-1
lines changed

3 files changed

+62
-1
lines changed

src/timeout.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,13 @@ void _twin_run_timeout(void)
5050
twin_timeout_t *first = (twin_timeout_t *) _twin_queue_set_order(&head);
5151
for (timeout = first; timeout && twin_time_compare(now, >=, timeout->time);
5252
timeout = (twin_timeout_t *) timeout->queue.order) {
53+
/* Validate closure pointer before executing timeout callback */
54+
if (!twin_pointer_valid(timeout->closure)) {
55+
/* Invalid closure pointer, remove this timeout */
56+
_twin_queue_delete(&head, &timeout->queue);
57+
continue;
58+
}
59+
5360
delay = (*timeout->proc)(now, timeout->closure);
5461
if (delay >= 0) {
5562
timeout->time = twin_now() + delay;
@@ -68,6 +75,12 @@ twin_timeout_t *twin_set_timeout(twin_timeout_proc_t timeout_proc,
6875
if (!timeout)
6976
return NULL;
7077

78+
/* Basic validation of closure pointer at scheduling time */
79+
if (closure && !twin_pointer_valid(closure)) {
80+
free(timeout);
81+
return NULL;
82+
}
83+
7184
if (!start)
7285
start = twin_now();
7386
timeout->delay = delay;

src/twin_private.h

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -810,4 +810,38 @@ void twin_custom_widget_destroy(twin_custom_widget_t *custom);
810810
/* Path convex hull computation */
811811
twin_path_t *twin_path_convex_hull(twin_path_t *path);
812812

813+
/*
814+
* Memory pointer validation
815+
*
816+
* This defines the minimum valid pointer address for closure validation.
817+
* Different environments have different memory layouts:
818+
*
819+
* - Unix-like systems (Linux/BSD/macOS/Solaris): First 4KB (0x1000) typically
820+
* unmapped
821+
* - Windows: First 64KB (0x10000) reserved
822+
* - Bare-metal: May have valid memory starting at 0x0
823+
*/
824+
#ifndef TWIN_POINTER_MIN_VALID
825+
#if defined(_WIN32) || defined(_WIN64)
826+
#define TWIN_POINTER_MIN_VALID 0x10000 /* Windows: 64KB */
827+
#elif defined(__unix__) || defined(__unix) || defined(unix) || \
828+
(defined(__APPLE__) && defined(__MACH__)) || defined(__linux__) || \
829+
defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || \
830+
defined(__DragonFly__) || defined(__sun) || defined(__HAIKU__) || \
831+
defined(__ANDROID__)
832+
#define TWIN_POINTER_MIN_VALID 0x1000 /* Unix-like: 4KB */
833+
#else
834+
#define TWIN_POINTER_MIN_VALID 0x100 /* Bare-metal/embedded: 256 bytes */
835+
#endif
836+
#endif
837+
838+
/*
839+
* Validate a pointer for basic sanity
840+
* Returns true if the pointer appears to be valid
841+
*/
842+
static inline bool twin_pointer_valid(const void *ptr)
843+
{
844+
return ptr && (uintptr_t) ptr >= TWIN_POINTER_MIN_VALID;
845+
}
846+
813847
#endif /* _TWIN_PRIVATE_H_ */

src/work.c

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,17 @@ void _twin_run_work(void)
3232
twin_work_t *first;
3333

3434
first = (twin_work_t *) _twin_queue_set_order(&head);
35-
for (work = first; work; work = (twin_work_t *) work->queue.order)
35+
for (work = first; work; work = (twin_work_t *) work->queue.order) {
36+
/* Validate closure pointer before executing callback */
37+
if (!twin_pointer_valid(work->closure)) {
38+
/* Invalid closure pointer, remove this work item */
39+
_twin_queue_delete(&head, &work->queue);
40+
continue;
41+
}
42+
3643
if (!(*work->proc)(work->closure))
3744
_twin_queue_delete(&head, &work->queue);
45+
}
3846
_twin_queue_review_order(&first->queue);
3947
}
4048

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

57+
/* Basic validation of closure pointer at scheduling time */
58+
if (closure && !twin_pointer_valid(closure)) {
59+
free(work);
60+
return NULL;
61+
}
62+
4963
work->proc = work_proc;
5064
work->priority = priority;
5165
work->closure = closure;

0 commit comments

Comments
 (0)