Skip to content

Parameters becomes a thin facade over the shared string-backed implementation#492

Open
milyin wants to merge 1 commit into
zenoh-flat-transitionfrom
shared-parameters
Open

Parameters becomes a thin facade over the shared string-backed implementation#492
milyin wants to merge 1 commit into
zenoh-flat-transitionfrom
shared-parameters

Conversation

@milyin

@milyin milyin commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

io.zenoh.query.Parameters now delegates every operation to the shared io.zenoh.jni.query.Parameters (ZettaScaleLabs/zenoh-flat-jni#9) — a pure-Kotlin, string-backed mirror of Rust's zenoh-protocol/core/parameters.rs. Companion of eclipse-zenoh/zenoh-kotlin#670: the duplicated per-SDK parsers are gone, construction is infallible on any remote (attacker-controlled) input, and there are zero JNI crossings on the production path.

Behavior changes (all aligning with Rust)

  1. Values are no longer percent-decoded; docs updated (Parameters, Selector).
  2. from(String) never throws; duplicated keys accepted — get returns the FIRST occurrence, toMap keeps the last (Rust's HashMap conversion).
  3. Trailing ;/=/| characters are trimmed at construction (Rust Parameters::from's trim_end_matches).
  4. toString() round-trips the stored string verbatim; insert/remove normalize. Equality is string equality.

Correspondence testing (the pure-JVM rule)

New ParametersCorrespondenceTest drives the shared implementation and the native oracle (parametersGet/Insert/IsWellFormed from ZettaScaleLabs/zenoh-flat#4) over edge shapes + 500 randomized separator-dense inputs. It caught a real rule on the first run: the trailing-separator trim above.

remove is correspondence-exempt: upstream zenoh's parameters::remove has an iterator-consumption bug — find advances past every entry up to and including the first match before filter builds the result, so entries PRECEDING the match are dropped (remove("b=2;a=1;c=3","a") → "c=3"), and removing an absent key erases the whole string (remove("x=1;y=2","missing") → ""). The shared implementation follows the documented “preserving the insertion order” contract instead; nativeRemoveBugCanary pins the buggy native behavior so the exemption is deleted the moment upstream fixes it. Worth reporting to eclipse-zenoh/zenoh.

Folded RX hardening

queryCallbackOf gains defense-in-depth (frees the owned payload/attachment leaves and finalizes the query if decomposition ever throws), and QueryParametersTest sends a=1;a=2;bad=%zz through the raw bindings end to end — completing the malformed-selector-parameters hardening for zenoh-java.

Testing

./gradlew jvmTest: 120 tests, 0 failed (standalone run). Merge order: zenoh-flat#4 → zenoh-flat-jni#9 → this (CI pins bumped).

🤖 Generated with Claude Code

…entation

The per-SDK map-backed parser duplicated zenoh-kotlin's and diverged from
Rust: it percent-decoded values, rejected duplicated keys (throwing on
attacker-controlled selector parameters in the queryable upcall), and
normalized eagerly. io.zenoh.query.Parameters now delegates every operation
to the shared io.zenoh.jni.query.Parameters (zenoh-flat-jni), a pure-Kotlin
string-backed mirror of Rust's zenoh-protocol parameters.rs — construction is
infallible on any input with zero JNI crossings.

Behavior changes, all aligning with Rust: no percent-decoding; from(String)
never throws; duplicated keys accepted with first-match-wins get (last wins
in toMap, as Rust's HashMap conversion); trailing ';'/'='/'|' trimmed at
construction; toString round-trips the stored string; equality is string
equality.

New ParametersCorrespondenceTest validates the shared implementation against
the native parameters_get/insert/is_well_formed oracle (zenoh-flat#4) over
edge shapes and 500 randomized inputs — it caught the trailing-separator trim
rule. remove is correspondence-exempt: upstream zenoh's parameters::remove
has an iterator-consumption bug (find advances past entries preceding the
first match before filter runs, dropping them; removing an absent key erases
everything); the shared implementation follows the documented 'preserving the
insertion order' contract instead, and nativeRemoveBugCanary pins the buggy
native behavior so the exemption is removed when upstream fixes it.

Also folds in the RX hardening that motivated the unification:
queryCallbackOf frees the owned native leaves and finalizes the query if
decomposition ever throws, and QueryParametersTest sends a=1;a=2;bad=%zz
through the raw bindings end to end. CI pins bump to zenoh-flat#4 and
zenoh-flat-jni#9.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant