iter18 α-21 (TEST): heap-persist HEVC controls past IOC_QUEUE

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) <noreply@anthropic.com>
This commit is contained in:
claude-noether
2026-05-14 08:57:18 +00:00
parent 111f8bac8f
commit e63bfd4dde
+33 -5
View File
@@ -526,10 +526,28 @@ int h265_set_controls(struct request_data *driver_data,
bool iqmatrix_set = surface_object->params.h265.iqmatrix_set; bool iqmatrix_set = surface_object->params.h265.iqmatrix_set;
unsigned int num_slices = surface_object->params.h265.num_slices; unsigned int num_slices = surface_object->params.h265.num_slices;
struct v4l2_ctrl_hevc_sps sps; /*
struct v4l2_ctrl_hevc_pps pps; * iter18 α-21: heap-allocate the HEVC control structs (was stack
struct v4l2_ctrl_hevc_decode_params decode_params; * locals) to preserve pointer lifetime past MEDIA_REQUEST_IOC_QUEUE.
struct v4l2_ctrl_hevc_scaling_matrix scaling_matrix; *
* 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_ctrl_hevc_slice_params *slice_params_array = NULL;
struct v4l2_ext_control controls[5]; struct v4l2_ext_control controls[5];
@@ -627,7 +645,17 @@ int h265_set_controls(struct request_data *driver_data,
surface_object->request_fd, surface_object->request_fd,
controls, n); 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) if (rc < 0)
return VA_STATUS_ERROR_OPERATION_FAILED; return VA_STATUS_ERROR_OPERATION_FAILED;