backend-drm: Fix double-free of pending state in error path

drm_pending_state_apply_atomic is supposed to leave pending_state
untouched if called as a test-only and that test fails, as per the docs
for drm_pending_state_test. If it gets as far as doing the atomic test
and it fails, it doesn't free pending_state. However if it fails to even
compile the state for the atomic test (for example, if a particular
property is not implemented in the driver for a particular plane), it
frees pending_state. In this case, drm_output_propose_state will free
the contained drm_output_state again, typically leading to a segfault.

Treat failing to compile the state for the atomic test in the same way
as successfully running the atomic test but it failing.

Signed-off-by: Ray Smith <rsmith@brightsign.biz>
This commit is contained in:
Ray Smith 2025-10-08 17:18:57 +01:00 committed by Daniel Stone
parent 847952b711
commit 930f768bdb

View file

@ -1625,7 +1625,10 @@ drm_pending_state_apply_atomic(struct drm_pending_state *pending_state,
if (ret != 0) {
weston_log("atomic: couldn't compile atomic state\n");
goto out;
if (mode == DRM_STATE_TEST_ONLY)
goto out_test_only;
else
goto out;
}
if (may_tear)
tear_flag = DRM_MODE_PAGE_FLIP_ASYNC;
@ -1643,12 +1646,8 @@ drm_pending_state_apply_atomic(struct drm_pending_state *pending_state,
if (ret == 0)
drm_pending_state_clear_tearing(pending_state);
}
/* Test commits do not take ownership of the state; return
* without freeing here. */
if (mode == DRM_STATE_TEST_ONLY) {
drmModeAtomicFree(req);
return ret;
}
if (mode == DRM_STATE_TEST_ONLY)
goto out_test_only;
if (ret != 0) {
wl_list_for_each(output_state, &pending_state->output_list, link)
@ -1669,8 +1668,11 @@ drm_pending_state_apply_atomic(struct drm_pending_state *pending_state,
assert(wl_list_empty(&pending_state->output_list));
out:
drmModeAtomicFree(req);
drm_pending_state_free(pending_state);
/* Test commits do not take ownership of the state; return
* without freeing here. */
out_test_only:
drmModeAtomicFree(req);
return ret;
}