feat(preload): assemble LIBVA_DRIVERS_PATH for libva's driver search - #24
Merged
Conversation
libva never opens its driver by soname. va_openDriver() constructs <dir>/<name>_drv_video.so and opens that absolute path, walking LIBVA_DRIVERS_PATH or a VA_DRIVERS_PATH compiled into whichever libva runs. A bundled libva therefore carries its build host's dri layout into a process running on a different one, and no library path can correct it, because no soname lookup ever happens. The preload now assembles the list: when libva.so.2 is in the process, every host <libdir>/dri found on LD_LIBRARY_PATH and in the conventional directories is APPENDED to LIBVA_DRIVERS_PATH, behind anything already set. A process that never loads libva is untouched, and the bundle's own lib/dri is never added: a bundle that ships VA drivers manages the variable itself. The scan runs once from the constructor and again after every successful dlopen until libva turns up, which is what covers the gstreamer shape, where libva enters as a dependency of a dlopened plugin. The guard means settled, not ran: latching it on 'libva absent' disarmed the late-load case and was measured doing so before E97 passed. Measured as E95 through E100 in experiments/30-run-tests.sh, on the glibc 2.31 floor. Built from main the section scores 2 of 6; with the change 6 of 6, and the whole evidence table is 59/59 with every prior prediction still held. E99 pins the bundle exclusion by turning the absence into a word, the way E85 does. The first E97 draft also measured a general interposer property, now in docs/traps.md: a dlopen through an interposer consults the interposer's own RUNPATH, not the calling binary's, so a soname reachable only through the caller's runpath stops resolving under the preload. docs/integrating.md gains the VA-API section and states what stays UNVERIFIED: a real iHD_drv_video.so or i965_drv_video.so across a libc boundary. That needs a host with one installed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What and why
VA-API was classified an unmeasured plugin boundary (
tools/plugin_boundaries.py:88): bundledlibva.so.2dlopens<name>_drv_video.sofrom the host. On the way to measuring it, one half of the problem turned out to be unfixable by the existing mechanism and is repaired here.libvanever opens its driver by soname.va_openDriver()(va/va.c) colon-splitsLIBVA_DRIVERS_PATH(or aVA_DRIVERS_PATHcompiled into the running libva) and opens the constructed absolute path. A bundled libva carries its build host's dri layout, and no--library-pathcan correct that, because no soname lookup ever happens.The change
src/cross-libc-dlopen.cgains a guardedLIBVA_DRIVERS_PATHassembler:dl_iterate_phdrfor soname prefixlibva.so., from the constructor (startup-linked libva: ffmpeg, mpv, browsers) and after every successful interposeddlopenuntil it fires (libva entering as a dependency of a dlopened plugin: gstreamer's va plugin). Either route has fired beforevaInitializecan read the variable.<dir>/driunder the process'sLD_LIBRARY_PATH(host entries, via the existingis_host_library_pathboundary) and the conventional libdirs (triplet, lib64, lib, local). Never$APPDIR/lib/dri: a bundle that ships VA drivers manages the variable itself, and its entries stay ahead of anything appended here.CROSS_LIBC_DLOPEN=0andCROSS_LIBC_DLOPEN_DRYRUN=1(reports, does not set), oneCROSS_LIBC_DLOPEN_DEBUGline naming the final value.docs/conventions/code.md): appending directories to a search list is not searching it. libva does its own searching from the result.The guard is "settled", not "ran" — measured, not designed
The first revision latched the guard when the constructor found no libva, which permanently disarmed the post-dlopen scan; E97 failed exactly that way and the fix is in the comment. The scan re-runs per successful dlopen until libva turns up.
The case (FAILS before, PASSES after)
Section Q of
experiments/30-run-tests.sh, E95 through E100: a fakelibva.so.2implementingva_openDriver's contract, stand-in drivers that answer with the directory they were built for, and the answer round-tripped through the driver's own function, so a pass is not "a string appeared".mainCROSS_LIBC_DLOPEN=0Full evidence table on this branch: 59/59 on x86-64 (
debian:bullseye-slim, glibc 2.31), every prior prediction still held.A finding on the way (docs/traps.md)
An interposed
dlopenconsults the interposer'sDT_RPATH/DT_RUNPATH, not the calling binary's. A soname reachable only through the caller's own runpath stops resolving under the preload. The trap entry names the two ways out (library path, or dlopen an object that NEEDs it).Documentation
docs/integrating.md: a VA-API section under "Per target".iHD_drv_video.soori965_drv_video.socarried across a libc boundary. That needs a host with one installed; E95-E100 measure the search-list half with a stand-in driver.Reconciliation owed at close-out
docs/report/08-test-results.mdTier 1 says 53/53 on x86-64 and 50/50 on aarch64, citing its CI run. This branch makes the x86-64 total 59; the aarch64 total needs CI's run before the report is updated, and the six new cases are architecture-independent C, so no skip path was added.