From e63bfd4dde9affbe94c4b530a16a93b01293d942 Mon Sep 17 00:00:00 2001 From: claude-noether Date: Thu, 14 May 2026 08:57:18 +0000 Subject: [PATCH] =?UTF-8?q?iter18=20=CE=B1-21=20(TEST):=20heap-persist=20H?= =?UTF-8?q?EVC=20controls=20past=20IOC=5FQUEUE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Static storage for sps/pps/decode_params/scaling_matrix + no-free for slice_params_array. Tests the kernel-defers-compound-copy hypothesis from iter17 P7 finding. If hashes change -> mechanism 3 confirmed; will refactor to per-surface heap allocation. If hashes unchanged -> mechanism 3 disproved; iter19 explores mechanisms 1/2/5. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/h265.c | 38 +++++++++++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/src/h265.c b/src/h265.c index ba764ee..dd5104e 100644 --- a/src/h265.c +++ b/src/h265.c @@ -526,10 +526,28 @@ int h265_set_controls(struct request_data *driver_data, bool iqmatrix_set = surface_object->params.h265.iqmatrix_set; unsigned int num_slices = surface_object->params.h265.num_slices; - struct v4l2_ctrl_hevc_sps sps; - struct v4l2_ctrl_hevc_pps pps; - struct v4l2_ctrl_hevc_decode_params decode_params; - struct v4l2_ctrl_hevc_scaling_matrix scaling_matrix; + /* + * iter18 α-21: heap-allocate the HEVC control structs (was stack + * locals) to preserve pointer lifetime past MEDIA_REQUEST_IOC_QUEUE. + * + * iter17 kernel pr_info found: rkvdec sees all-zero SPS/PPS/decode_params + * for libva HEVC despite the userspace strace showing correct + * S_EXT_CTRLS payload bytes. Hypothesis: kernel defers + * copy_from_user for compound controls with which=REQUEST_VAL until + * IOC_QUEUE actually runs. Libva's stack locals are freed when + * h265_set_controls returns — before EndPicture's IOC_QUEUE fires. + * + * Quick-test with `static` storage: same struct shape, pointer + * persists indefinitely. If this fixes Bug 5, the leading hypothesis + * is confirmed; will refactor to heap-allocate per-surface in a + * follow-up commit. The static approach IS NOT THREAD-SAFE if libva + * ever has concurrent h265 decode contexts; current campaign single- + * codec single-context isn't impacted. + */ + static struct v4l2_ctrl_hevc_sps sps; + static struct v4l2_ctrl_hevc_pps pps; + static struct v4l2_ctrl_hevc_decode_params decode_params; + static struct v4l2_ctrl_hevc_scaling_matrix scaling_matrix; struct v4l2_ctrl_hevc_slice_params *slice_params_array = NULL; struct v4l2_ext_control controls[5]; @@ -627,7 +645,17 @@ int h265_set_controls(struct request_data *driver_data, surface_object->request_fd, controls, n); - free(slice_params_array); + /* + * iter18 α-21: do NOT free slice_params_array here. The kernel may + * defer copy_from_user for compound controls with which=REQUEST_VAL + * until MEDIA_REQUEST_IOC_QUEUE runs in EndPicture — after this + * function returns. Freeing here = stale pointer = kernel reads zero. + * + * Leak this per call for now; if α-21 succeeds we'll refactor to + * either store on surface_object (freed at DestroySurfaces) or + * use a per-context arena that recycles between frames. + */ + (void)slice_params_array; /* deliberately leaked: see comment above */ if (rc < 0) return VA_STATUS_ERROR_OPERATION_FAILED;