Repository navigation
chore(uniffi): port upstream generator fixes into the forks - #7461
Conversation
Quest-Claim: be82868751423471
Record checked upstream heads, reproduced fixes, tested fork and rust2 drafts, and the local Cargo/review blockers. Leave pin integration and the quest unfinished. Co-Authored-By: GPT-6.1 Sol <noreply@openai.com>
Point the Python/Kotlin/Swift generator at kixelated/uniffi-rs#1's head (running-loop preference) and the Dart generator at kixelated/uniffi-dart#7's head (allocation-failure ownership), add the new fixture to the Nix lock data, and regenerate the committed Dart bindings. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A pin bump in rs/uniffi-bindgen changes the Python, Kotlin, and Swift bindings, but matched none of their modules, so CI checked none of them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts: # quest/m1/vendor-sync/uniffi.md
kixelated/uniffi-dart#7 landed on moq-0.32 and its head 657cbff5 is now tagged, so the flake and README go back to the fork's tag convention. The source hash is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
kixelated
left a comment
There was a problem hiding this comment.
Automated review by review (OpenAI)
Reviewed commit: 1f24fa1aa182e273674d30a51798723361ef37cb.
No actionable bugs found. The direction is sound: port the focused fixes in the generator sources rather than patch each binding or adopt the larger upstream redesign. Python now selects the loop actually awaiting the call; Dart reserves disposal status before relinquishing ownership and unwinds scratch allocations in reverse order. The dispatcher change covers the Python/Kotlin/Swift consumers of the pinned generator, with a targeted selection test. No new public API or wire surface was identified.
Verification: static GitHub inspection of the PR, pinned fork changes, runtime context, and binding-check consumers. No prior published review to carry forward. I did not run generation, builds, tests, fault-injection cases, or Nix checks; the PR's reported results were not independently reproduced.
(Written by OpenAI)
There was a problem hiding this comment.
Important
The root Cargo.lock change does more than move the uniffi rev: it rolls main's dependency upgrades (windows-sys, socket2, getrandom) back across ~17 crates. Details inline.
Reviewed changes
- Fork pin bumps:
rs/uniffi-bindgen/Cargo.tomland the rootCargo.lockmove the uniffi rev88d835d->35209f3;flake.nixanddart/README.mdmove the Dart generator to tagv0.3.1-kixelated.7+v0.32.0. - Dart bindings regenerated:
toRustBuffernow nests theForeignBytesalloc in try/finally, and each of the 50dispose()bodies allocates and frees its ownRustCallStatus, keeping the finalizer attached whencallocfails. - Nix lock fixture:
nix/uniffi-dart-Cargo.lockgains the fork'sinput_scratchtest package. - CI selection:
sh/dispatch.shroutesrs/uniffi-bindgen/changes to the py/kt/swift checks, covered by a newsh/dispatch-query.test.pycase. - Quest:
quest/m1/vendor-sync/uniffi.mdis rewritten to the checked pins and the remaining fork-CI work.
deepseek-v4.1-flash (free via Pullfrog for OSS) | 𝕏
|
No actionable comments were generated in the recent review.
|
…uniffi Resolve Cargo.lock from main and move only the uniffi fork rev, keeping main's dependency versions (windows-sys, socket2, getrandom, toml). Resolve sh/dispatch.sh to main's module() layout with the uniffi-bindgen patterns re-applied to py, kt, and swift. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…uniffi Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
kixelated
left a comment
There was a problem hiding this comment.
Automated review by review (OpenAI)
Reviewed commit: e1a8bab2ec482f76edcbfdc3395bb32fd0d9a016.
No new actionable bugs found. The unrelated lockfile rollback identified in Pullfrog's finding is fixed: relative to the merged base, Cargo.lock now changes only the UniFFI fork revision, retaining main's dependency versions. The generator pin, generated Dart cleanup changes, and selection test remain unchanged; the dispatcher migration preserves Python/Kotlin/Swift generator coverage.
Direction remains sound: preserve main's lockfile and apply the targeted fork update rather than re-resolving unrelated dependencies. Compared with the previous published review and accounted for base merges. Verification was static GitHub inspection; no generation, builds, tests, cargo metadata, or Nix checks were run.
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes
This run re-reviewed the two commits since the prior pullfrog review (1f24fa1aa), both merges of main.
- Restored the root
Cargo.locktomain. Thewindows-sys/socket2/getrandomrollback flagged in the prior review is gone;git diff origin/main -- Cargo.lockis now exactly the 24-line uniffi rev swap (88d835d→35209f3) across the ten uniffi/weedle2 package entries, and the two re-fetched crates keeptoml 1.1.6. - Restored
rs/uniffi-bindgen/Cargo.toml's dev-dependency. The branch-only[lints] workspace = truethat had replaced[dev-dependencies] workspace-hackis gone, so the manifest matchesmainapart from the uniffi rev. - Rewrote the quest Plan to the checked pins and the remaining fork-CI work.
- Clarified the
sh/dispatch.shbinding comment to name which bindings render through the generator fork (no behavior change).
deepseek-v4.1-flash (free via Pullfrog for OSS) | 𝕏

Problem
The recurring UniFFI audit found correctness fixes missing from MoQ's pinned generators and from rust2's imports: Python awaits a call on the configured fallback loop instead of the running one, and Dart leaks input scratch or loses a native handle when an allocation fails.
Approach
moq-0.32as merge commits:rs/uniffi-bindgento kixelated/uniffi-rs#1's head35209f3f, and the Nix Dart generator plusdart/README.mdto tagv0.3.1-kixelated.7+v0.32.0, which points at kixelated/uniffi-dart#7's head657cbff5.input_scratchfixture tonix/uniffi-dart-Cargo.lock(MoQ's three Dart patches still apply) and regeneratedart/moq_ffi.Cargo.lockkeeps main's resolution and moves only the uniffi fork rev (88d835d→35209f3, 24 lines). An earlier rewrite here rolled back main'swindows-sys/socket2/getrandomupgrades; pullfrog flagged it and the merge ofmainrestored them.rs/uniffi-bindgen/changes insh/dispatch.sh. Those bindings render through that crate, but a pin bump there matched none of their modules, so CI would have checked none of them.moq-dev/rust2#364 (merged) mirrors both ports, so the rust2 switch keeps them.
Impact
toRustBufferand the 50dispose()bodies; Python's generatedAsync.pyprefers the running loop. Kotlin, Swift, Go, and C++ output is unchanged.Alternatives
Do not adopt upstream main's parser/JNI/generator redesign. Go and C++ upstream heads have not changed; Kotlin's checksum fix is already in the pin. The quest records why callback/custom-type/default/recursion changes have no current generated MoQ consumer. No dependency bumps.
Decisions
Settled by the maintainer on 2026-11-02:
c2593169andce8fa314. GitHub's compare shows35209f3fand657cbff50 commits behindmoq-0.32. uniffi-rs#1 had no checks. uniffi-dart#7'sTesting(futures_test.dart: sleep) andTest Downstream(bdk-dart, rust-payjoin) failures match the same failures on the fork's earlier PRs (for example theerror-displayrun on 2026-09-29), whileNixandLintspassed.657cbff5asv0.3.1-kixelated.7+v0.32.0(annotated, like.6) and switchflake.nix(rev = "v${version}") anddart/README.mdback to the tag. The prefetched tag hash issha256-uSApyCocEhADWu8Koj5vXIt0fMYQVjnBVKctDWQHqLM=, unchanged./quest-merge.Choice made without asking: main's moq-dev/moq#7568 added the uniffi-dart fork-CI cleanup to this quest. It needs its own fork PR and merge, so this PR leaves it as the quest's remaining work instead of deleting the quest. That also keeps this run's checked commits in the quest for the next run.
Validation
quest gate nix develop -c just ci origin/mainone1a8bab2(after mergingmainat608e6342): every selected module passes, includingrs,py,kt,go,c,cpp,obs_compile,js,gh,quest, the rs/py/js/gh tests, anddart, which regeneratesdart/moq_ffifrom the tagged generator and leaves the tree clean. The exception ischeck flake. It fails building nixpkgs'github-runner(unshare: write failed /proc/self/uid_map: Operation not permitted) on this host, andchecks.x86_64-linux.github-runner-vmevaluates to the same4izikpkp…-vm-test-run-github-runner-vm.drvonorigin/mainand this head, so this PR doesn't cause it.cargo metadata --lockedaccepts the mergedCargo.lock.git diff origin/main -- Cargo.lockis only the uniffi rev lines.CHECK_MODULES="py kt swift go c cpp dart obs_compile" just ci --allall passed (swift skips off macOS),just test interop --allgave 183 PASS / 0 FAIL, andsh/dispatch-query.test.py's new generator-pin selection test passed.CI
The
Checkfailure one1a8bab2(run 41497117863) is a pre-existing use-after-free in a moq-c test onmain. This PR doesn't cause it.moq-c test::follow_delivers_the_instance_again_after_an_endprintedtest ... ok, then the process aborted:corrupted size vs. prev_size(SIGABRT). That is glibc detecting heap corruption after the test body passed.gated_callback(rs/moq-c/src/test.rs, added in moq-dev/moq#5886) runs on the runtime thread. It sendscodeongate.tx, and only then locksgate.hold. For the terminal0aftermoq_origin_follow_cancel, the test thread can receive that0and rundrop((run, dynamic, served, gate))while the callback is still about to lock the mutex inside the freedBox<Gate>.moq_origin_request's contract (rs/moq-c/src/api.rs:2384) keepsuser_datavalid only until the terminal callback, so the test frees it too early.origin/main(5e327b55).sendand thelockand ran the test under valgrind. It reportsInvalid read/Invalid write of size 8inmoq::test::gated_callback, at addresses16..32 bytes inside a block of size 40 free'd. The freeing stack isdrop_glue::<Box<moq::test::Gate>>from the test'sdrop((run, dynamic, served, gate)).cargo tree -p moq-c -e normal,dev,buildcontains nounifficrate. This PR's rootCargo.lockdiff only moves the uniffi fork rev. The rest of the diff is Dart, Nix,sh/, and quest files, none of which moq-c builds.gated_callback, so it doesn't fix this. The fix is to movegate.hold.lock().unwrap().take()beforegate.tx.send(code), so the callback touches nothing inGateafter its last send. That's left as a follow-up outside this PR's scope.I reran the failed job without waiting on it. The other failed
Check(run 41497068881) was cancelled when a newer push superseded it.Review
quest review --base origin/main, round 1 (new session) on71b8425702b64178d7fa6611338724d31b2d487d: 0 findings. The heade1a8bab2ec482f76edcbfdc3395bb32fd0d9a016adds only a conflict-free merge ofmain, so per the guide that round still covers it, and the checks above ran on it.Cargo.lockrollback is fixed (replied and resolved). CodeRabbit and the OpenAI review reported nothing actionable.35209f3f, fix(dart): retain ownership through allocation failures kixelated/uniffi-dart#7657cbff5, and rust2#364832a146adirectly. Each matches its upstream commit apart from naming and comments. No findings; the records are in each PR body.Follow-ups
gated_callbackshould takeholdbefore sending. It is the only test callback that touchesuser_dataafter a send;channel_callback,state_callback, andprotocol_callbacksend last.TestingandTest Downstream) is already planned in the quest; its next PR is a kixelated/uniffi-dart PR.check flakecan't build nixpkgs'github-runneron hosts where the Nix sandbox can't writeuid_map. The existingMOQ_USERNS_UNAVAILABLEprobe insh/dispatch.shpasses there, so the local gate fails rather than skipping. Worth a quest to make the probe match what the build needs.clippy.toml, which fails rust2's Clippy withdisallowed_types; scratch clones of other workspaces need an emptyclippy.tomlabove them, or should live elsewhere.(Written by Claude Opus 5.5)