Unix cache signals lose their structure argument and are rejected by AT-SPI
I maintainer di solito rispondono entro 1 giorno
Una pull request collegata è già stata integrata.
- #819 di @luccahuguet — integrata
Valutazione
- Difficoltà
- 3/5
- Tempo stimato
- Mezza giornata
- Idoneità per principianti
- 18/100
- Tipo di issue
- Bug
- Chiarezza
- Specificata chiaramente
- Stato di attività
- Attiva
- Stack tecnologico
- linux, rust
- Ambito
- desktop-dev
Direzione di ricerca
The bug is in the emit_cache_signal helper in adapters/unix/src/atspi/bus.rs, which passes the structure as the message body instead of wrapping it in a one-element tuple. The regression test from the issue, cache_signals_preserve_struct_arguments, needs a private bus, so run it with dbus-run-session -- cargo test --locked -p accesskit_unix ... -- --ignored. Done means the encoded SIGNATURE header matches the expected struct signatures. PR #819 already proposes this fix, so check it before starting.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
The Unix adapter emits AddAccessible and RemoveAccessible with flattened D-Bus signatures. Each signal should contain one structure argument, but the shared emit_cache_signal helper passes that structure directly as the message body.
Reproduced on upstream commit 466e24e252103f4d82bd6fbab98141b551e46e0c, using its unchanged lockfile: accesskit_unix 0.24.0, zbus 5.19.0, zvariant 5.15.0, and Rust 1.87.0 on x86_64 Linux.
| Signal | Expected wire signature | Observed wire signature |
|---|---|---|
| AddAccessible | ((so)(so)(so)iiassusau) |
(so)(so)(so)iiassusau |
| RemoveAccessible | (so) |
so |
GNOME AT-SPI 2.58.1 rejects the malformed AddAccessible signature; its RemoveAccessible handler likewise requires (so).
To reproduce, save the regression patch below as regression-only.patch and apply it to that upstream commit, then run:
dbus-run-session -- cargo test --locked -p accesskit_unix \
cache_signals_preserve_struct_arguments -- --ignored
The test calls the production helper on a private bus and checks the encoded D-Bus SIGNATURE header and round-tripped values. It fails with the original helper and passes after the two-line correction below. Inspecting only zbus's parsed signature can hide the missing structure boundary.
The proposed correction in PR #819 is to pass &(body,) to emit_signal, with the generic bound changed from DynamicType to Type so the tuple can be serialized. No dependency or lockfile changes are needed.
We also verified the backported correction in our Venus terminal client on native Wayland with Orca 49.4 and AT-SPI 2.58.1. Previously Orca retained stale focus and reported “No selected text” after returning from scrollback despite a valid selection. With the correction it reported the exact selected text é 界 without a focus-repair action. Those native checks used accesskit_unix 0.22.1, zbus 5.18.0, and zvariant 5.13.1; current upstream was verified at the wire level.
regression-only.patch (test only; production helper unchanged)
diff --git a/adapters/unix/src/atspi/bus.rs b/adapters/unix/src/atspi/bus.rs
index 3368185..ca9857d 100644
--- a/adapters/unix/src/atspi/bus.rs
+++ b/adapters/unix/src/atspi/bus.rs
@@ -523,3 +523,74 @@ where
Err(_) => Ok(default),
}
}
+
+#[cfg(all(test, not(feature = "tokio")))]
+mod tests {
+ use super::*;
+ use atspi::CacheItem;
+ use futures_lite::StreamExt;
+ use zbus::{MatchRule, MessageStream, message::Type};
+
+ fn assert_wire_signature(message: &zbus::Message, signature: &str) {
+ let bytes = message.data().bytes();
+ let length = bytes[12..16].try_into().unwrap();
+ let length = match bytes[0] {
+ b'l' => u32::from_le_bytes(length),
+ b'B' => u32::from_be_bytes(length),
+ _ => panic!("invalid D-Bus byte order"),
+ } as usize;
+ // Inspect the encoded header: zbus normalizes outer parentheses when reading it.
+ let mut field = vec![8, 1, b'g', 0, signature.len() as u8];
+ field.extend_from_slice(signature.as_bytes());
+ field.push(0);
+ assert!(
+ bytes[16..16 + length]
+ .windows(field.len())
+ .any(|w| w == field)
+ );
+ }
+
+ #[test]
+ #[ignore = "requires a private D-Bus session; run with dbus-run-session"]
+ fn cache_signals_preserve_struct_arguments() {
+ futures_lite::future::block_on(async {
+ let conn = Connection::session().await.unwrap();
+ let rule = MatchRule::builder()
+ .msg_type(Type::Signal)
+ .interface("org.a11y.atspi.Cache")
+ .unwrap()
+ .path(cache_path())
+ .unwrap()
+ .build();
+ let mut signals = MessageStream::for_match_rule(rule, &conn, Some(2))
+ .await
+ .unwrap();
+ let executor = Executor::new();
+ let bus = Bus {
+ conn: conn.clone(),
+ _task: executor.spawn(std::future::pending(), "unused"),
+ socket_proxy: SocketProxy::new(&conn).await.unwrap(),
+ desktop: Arc::new(OnceLock::new()),
+ };
+ let item = CacheItem::default();
+ bus.emit_cache_signal("AddAccessible", &item).await.unwrap();
+ let added = signals.next().await.unwrap().unwrap();
+ assert_eq!(added.header().member().unwrap().as_str(), "AddAccessible");
+ assert_wire_signature(&added, "((so)(so)(so)iiassusau)");
+ let (received,): (CacheItem,) = added.body().deserialize().unwrap();
+ assert_eq!(received, item);
+
+ bus.emit_cache_signal("RemoveAccessible", &item.object)
+ .await
+ .unwrap();
+ let removed = signals.next().await.unwrap().unwrap();
+ assert_eq!(
+ removed.header().member().unwrap().as_str(),
+ "RemoveAccessible"
+ );
+ assert_wire_signature(&removed, "(so)");
+ let (received,): (ObjectRefOwned,) = removed.body().deserialize().unwrap();
+ assert_eq!(received, item.object);
+ });
+ }
+}
- Lingua principale
- Rust
- Stelle
- 1.5k
- Fork
- 122
- Merge medio
- 1h 7m
- PR unite (30g)
- 18
Preparare l'ambiente
- Nessun Dockerfile né file Docker Compose
- Nessun modello di pull request
- Leggi la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di AccessKit/accesskit
-
Document sub-treesAperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 75/100
I maintainer di solito rispondono entro 1 giorno
-
Document `Role::ColorWell`Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
I maintainer di solito rispondono entro 1 giorno
-
Crash on macOS when the subclassing adapter is dropped while the view has key-value observersForse già presa @RXNova l’ha presa 1 giorno fa. Aperta
Difficoltà 3/5 1-2 giorni Idoneità per principianti 35/100
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 3/5 1-2 giorni Idoneità per principianti 68/100
AccessKit/accesskit#802 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 5/5 Più di una settimana Idoneità per principianti 35/100
AccessKit/accesskit#778 · 24 commenti ·
I maintainer di solito rispondono entro 1 giorno
Tutte le issue di AccessKit/accesskit
Issue simili
-
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 75/100
RustCrypto/SSH#596 ·
-
proxy: SQL-over-HTTP turns empty arrays into [""] or [false], or HTTP 500 for int and float arraysAperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 83/100
neondatabase/neon#12965 ·
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
goauthentik/authentik#26867 ·
I maintainer di solito rispondono entro 1 giorno
-
api bug macos maintainer-needed p2 triaged
Difficoltà 2/5 1-3 ore Idoneità per principianti 66/100
I maintainer di solito rispondono entro 1 giorno
-
area::tern difficulty::easy good first issue kind::cleanup triage::ready
Difficoltà 1/5 1-3 ore Idoneità per principianti 88/100