Skip to content

Commit 8e55e93

Browse files
author
Mariotaku
committed
fix(apps): look up controller by uuid in async pcmanager callbacks
The three pcmanager async callbacks (host_info_cb, send_wol_cb, quitgame_cb) received the apps_fragment pointer through their userdata, but the fragment can be destroyed while the worker request is still in flight (WOL waits 30+s for the host; Quit takes 1-5s; navigating away or forgetting the host destroys the fragment in the meantime). host_info_cb and send_wol_cb guarded with "if (controller \!= current_instance) return", which avoids the deref but still loads the freed pointer for the comparison — technically UB and an ASan/UBSan trip wire. quitgame_cb had no guard at all and went straight to controller->quit_progress and controller->applist; if the fragment was gone, the deref crashed. apploader's async callbacks don't have this issue because apploader_destroy zeros its callback table before unref; pcmanager has no equivalent invalidation hook. Switch all three call sites to pass NULL as userdata and look the fragment up via the static current_instance pointer + uuid match in the callback. current_instance is written from on_view_created and cleared in on_destroy_view (same LVGL/UI thread as the bus delivery), so no cross-thread race. No memory is ever read through the dangling userdata pointer.
1 parent 0392c71 commit 8e55e93

1 file changed

Lines changed: 17 additions & 10 deletions

File tree

src/app/ui/launcher/apps.controller.c

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ static void on_view_created(lv_fragment_t *self, lv_obj_t *view) {
256256

257257
const SERVER_STATE *state = pcmanager_state(pcmanager, &controller->uuid);
258258
if (state != NULL && state->code != SERVER_STATE_QUERYING) {
259-
pcmanager_request_update(pcmanager, &controller->uuid, host_info_cb, controller);
259+
pcmanager_request_update(pcmanager, &controller->uuid, host_info_cb, NULL);
260260
if (state->code == SERVER_STATE_AVAILABLE) {
261261
apploader_load(controller->apploader);
262262
}
@@ -342,21 +342,25 @@ static void on_host_removed(const uuidstr_t *uuid, void *userdata) {
342342
}
343343

344344
static void host_info_cb(int result, const char *error, const uuidstr_t *uuid, void *userdata) {
345-
apps_fragment_t *controller = (apps_fragment_t *) userdata;
346-
if (controller != current_instance) { return; }
345+
LV_UNUSED(userdata);
346+
apps_fragment_t *controller = current_instance;
347+
if (controller == NULL) { return; }
348+
if (!uuidstr_t_equals_t(&controller->uuid, uuid)) { return; }
347349
if (!controller->base.managed->obj_created) { return; }
348350
lv_btnmatrix_clear_btn_ctrl_all(controller->actions, LV_BTNMATRIX_CTRL_DISABLED);
349351
}
350352

351353
static void send_wol_cb(int result, const char *error, const uuidstr_t *uuid, void *userdata) {
352-
apps_fragment_t *controller = (apps_fragment_t *) userdata;
353-
if (controller != current_instance) { return; }
354+
LV_UNUSED(userdata);
355+
apps_fragment_t *controller = current_instance;
356+
if (controller == NULL) { return; }
357+
if (!uuidstr_t_equals_t(&controller->uuid, uuid)) { return; }
354358
if (!controller->base.managed->obj_created) { return; }
355359
lv_btnmatrix_clear_btn_ctrl_all(controller->actions, LV_BTNMATRIX_CTRL_DISABLED);
356360
const SERVER_STATE *state = pcmanager_state(pcmanager, &controller->uuid);
357361
if (state == NULL) { return; }
358362
if (state->code & SERVER_STATE_ONLINE || result != GS_OK) { return; }
359-
pcmanager_request_update(pcmanager, &controller->uuid, host_info_cb, controller);
363+
pcmanager_request_update(pcmanager, &controller->uuid, host_info_cb, NULL);
360364
}
361365

362366
static void update_view_state(apps_fragment_t *controller) {
@@ -601,7 +605,7 @@ static void launcher_toggle_hidden(apps_fragment_t *controller, const apploader_
601605

602606
static void launcher_quit_game(apps_fragment_t *controller) {
603607
controller->quit_progress = progress_dialog_create(locstr("Quitting game..."));
604-
pcmanager_quitapp(pcmanager, &controller->uuid, quitgame_cb, controller);
608+
pcmanager_quitapp(pcmanager, &controller->uuid, quitgame_cb, NULL);
605609
}
606610

607611
static int adapter_item_count(lv_obj_t *grid, void *data) {
@@ -651,7 +655,10 @@ static void applist_focus_leave(lv_event_t *event) {
651655
}
652656

653657
static void quitgame_cb(int result, const char *error, const uuidstr_t *uuid, void *userdata) {
654-
apps_fragment_t *controller = userdata;
658+
LV_UNUSED(userdata);
659+
apps_fragment_t *controller = current_instance;
660+
if (controller == NULL) { return; }
661+
if (!uuidstr_t_equals_t(&controller->uuid, uuid)) { return; }
655662
if (controller->quit_progress) {
656663
lv_msgbox_close(controller->quit_progress);
657664
controller->quit_progress = NULL;
@@ -683,13 +690,13 @@ static void actions_click_cb(lv_event_t *event) {
683690
static void action_cb_wol(apps_fragment_t *controller, lv_obj_t *buttons, uint16_t index) {
684691
LV_UNUSED(index);
685692
lv_btnmatrix_set_btn_ctrl_all(buttons, LV_BTNMATRIX_CTRL_DISABLED);
686-
pcmanager_send_wol(pcmanager, &controller->uuid, send_wol_cb, controller);
693+
pcmanager_send_wol(pcmanager, &controller->uuid, send_wol_cb, NULL);
687694
}
688695

689696
static void action_cb_host_reload(apps_fragment_t *controller, lv_obj_t *buttons, uint16_t index) {
690697
LV_UNUSED(index);
691698
lv_btnmatrix_set_btn_ctrl_all(buttons, LV_BTNMATRIX_CTRL_DISABLED);
692-
pcmanager_request_update(pcmanager, &controller->uuid, host_info_cb, controller);
699+
pcmanager_request_update(pcmanager, &controller->uuid, host_info_cb, NULL);
693700
}
694701

695702
static void action_cb_pair(apps_fragment_t *controller, lv_obj_t *buttons, uint16_t index) {

0 commit comments

Comments
 (0)