Skip to content

Commit 3a95678

Browse files
authored
Merge pull request #121 from sysprog21/fix-widget-memory
Fix use-after-free in custom widget destruction
2 parents 3f83361 + 30f9dfb commit 3a95678

File tree

1 file changed

+26
-0
lines changed

1 file changed

+26
-0
lines changed

src/widget.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,9 @@ static void unregister_custom_widget(twin_widget_t *widget)
320320
custom_widget_map_t **prev = &custom_widget_map;
321321
custom_widget_map_t *entry = custom_widget_map;
322322

323+
if (!widget)
324+
return;
325+
323326
while (entry) {
324327
if (entry->widget == widget) {
325328
*prev = entry->next;
@@ -334,6 +337,26 @@ static void unregister_custom_widget(twin_widget_t *widget)
334337
static twin_dispatch_result_t custom_widget_dispatch(twin_widget_t *widget,
335338
twin_event_t *event)
336339
{
340+
/* Handle destroy events specially to ensure proper cleanup order */
341+
if (event->kind == TwinEventDestroy) {
342+
/* Find and call user dispatch first if it exists */
343+
custom_widget_map_t *entry = custom_widget_map;
344+
while (entry) {
345+
if (entry->widget == widget) {
346+
if (entry->user_dispatch)
347+
entry->user_dispatch(widget, event);
348+
break;
349+
}
350+
entry = entry->next;
351+
}
352+
353+
/* Unregister from custom widget map before base destruction */
354+
unregister_custom_widget(widget);
355+
356+
/* Now call base widget dispatch to complete destruction */
357+
return _twin_widget_dispatch(widget, event);
358+
}
359+
337360
/* First call the base widget dispatch to handle standard widget behavior */
338361
twin_dispatch_result_t result = _twin_widget_dispatch(widget, event);
339362
if (result == TwinDispatchDone)
@@ -396,6 +419,9 @@ void twin_custom_widget_destroy(twin_custom_widget_t *custom)
396419
return;
397420

398421
if (custom->widget) {
422+
/* Unregister from dispatch map (idempotent if already done during
423+
* TwinEventDestroy)
424+
*/
399425
unregister_custom_widget(custom->widget);
400426
/* Note: widget destruction should be handled by the parent/container */
401427
}

0 commit comments

Comments
 (0)