fix: bind symbols via @Native, restore Flutter compatibility (0.4.1) - #14
Merged
Conversation
Two fixes, both surfaced by smoke-testing the Flutter example. Flutter compatibility. hooks ^2.1.0 requires meta ^1.19.0, but flutter_test from the Flutter SDK pins meta 1.18.0 on 3.44.x. Every Flutter app depends on flutter_test, so 0.4.0 could not be resolved by any of them — the bundled example included, which is how this was found. Widening to hooks '>=1.0.2 <3.0.0' and code_assets '>=1.0.0 <2.0.0' resolves to 2.1.0/1.2.1 standalone and 1.0.2/1.0.0 under an older Flutter; the build hook is source-compatible with both majors. pana still scores 160/160, since a standalone resolve still picks the latest. Native symbol resolution. hook/build.dart already published libappstream.so as a code asset, but the VM consults its asset table only for @Native declarations, so that asset was built and then never used. bindings.dart instead searched for the library at runtime. The symbols are now @Native externals bound to @DefaultAsset, and the search chain is gone. That chain was ~180 lines: a /proc/self/maps scan, a glob through .dart_tool/hooks_runner internals, and paths derived from Platform.script, the executable, and the current directory. The CWD-relative entries meant the process would load libappstream.so from ./lib, ./build, or ./src/build — so running an application from a directory an attacker could write to was enough to get a library of their choosing loaded. Removing them closes that. Comments in hook/build.dart and lib/src/appstream_native.dart described the @Native mechanism as though it already existed; they are now accurate. README documents how the library is located and what embedders outside the bundle, such as ivi-homescreen, need on LD_LIBRARY_PATH. The public API is unchanged: AppstreamBindings lives in lib/src/, is not exported, and appears only as a local in a private function. Verified on three runtimes over the real 48 MB Flathub catalog: dart run/dart test (45/45), the Flutter example under GTK on wayland-0, and the same example on ivi-homescreen on wayland-0 — both importing all 4677 components. Parse throughput is unchanged (416/411 ms with @Native vs 414/409 ms before); the FFI boundary is crossed twice per parse and components stream over the Dart port, so binding mechanism cannot move it. clang-tidy clean, clang-format applied last, 149/149 C++ tests, dart analyze --fatal-infos clean, publish dry-run 0 warnings.
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.
Two fixes, both surfaced by actually smoke-testing the Flutter example. 0.4.1.
1. Published 0.4.0 is unusable from Flutter
Every Flutter app depends on
flutter_test, so no Flutter project on an SDK pinningmeta 1.18.0(3.44.x) can depend on appstream_dart 0.4.0 at all. The bundled example is one of them — that is how this was found. CI missed it because its Flutter job runs 3.47.0.Widening to
hooks: '>=1.0.2 <3.0.0'andcode_assets: '>=1.0.0 <2.0.0'fixes it. Verified resolution in both directions:dart pub getThe build hook is source-compatible with both majors, and pana still scores 160/160 — a standalone resolve still picks the latest, which is what that check measures.
2. The code asset was built and never used
hook/build.dartpublishedlibappstream.soas a code asset, but the VM consults its asset table only for@Nativedeclarations — a plainDynamicLibrary.open(name)never sees it. Sobindings.dartcompensated with a seven-step runtime search. Comments inhook/build.dartandlib/src/appstream_native.dartclaimed@Nativewas already in use; it was not.Symbols are now
@Nativeexternals bound to@DefaultAsset, and the search chain is deleted (~180 lines): a/proc/self/mapsscan, a glob through.dart_tool/hooks_runner/internals, and candidates derived fromPlatform.script, the executable, and the CWD.Security note: those CWD-relative candidates meant the process would load
libappstream.sofrom./lib,./build, or./src/build. Running an application from a directory an attacker can write to was enough to get a library of their choosing loaded. Removing them closes that.The public API is unchanged —
AppstreamBindingslives inlib/src/, is not exported, and appears only as a local inside a private function.Verification
Exercised on three runtimes against the real 48 MB Flathub catalog, not just unit tests:
dart run/dart test— 45/45Resolution goes through
NativeAssetsManifest.json, which maps the asset to the plain sonamelibappstream.so, so the finaldlopenuses the system loader. GTK works via the runner'sRPATH=$ORIGIN/lib; embedders whose binary sits outside the bundle need it onLD_LIBRARY_PATH. The README now documents this, including thatflutter build bundledoes not do Linux native-asset packaging — useflutter build linux.Performance is unchanged, measured rather than assumed:
@NativeDynamicLibrary.lookupFunctionExpected: the FFI boundary is crossed twice per parse, and components stream back over the Dart port via
Dart_PostCObject_DL, so the binding mechanism cannot move throughput. Argument passing, port protocol, andSQLITE_TRANSIENThandling are byte-identical.clang-tidy clean, clang-format applied last, 149/149 C++ tests,
dart analyze --fatal-infosclean,dart pub publish --dry-run0 warnings.Relationship to open PRs
Independent of #12 and #13 (disjoint files); merges in any order.