Unix cache signals lose their structure argument and are rejected by AT-SPI
Les mainteneurs répondent en général sous 1 jour
Une pull request liée a déjà été fusionnée.
- #819 par @luccahuguet — fusionnée
Évaluation
- Difficulté
- 3/5
- Temps estimé
- Une demi-journée
- Accessibilité débutants
- 18/100
- Type d'issue
- Bug
- Clarté
- Clairement spécifiée
- Activité
- Active
- Stack technique
- linux, rust
- Domaine
- desktop-dev
Piste de recherche
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.
Rédigé par le modèle d'indexation à partir du texte de l'issue.
Description
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);
+ });
+ }
+}
- Langage dominant
- Rust
- Étoiles
- 1.5k
- Forks
- 133
- Merge moyen
- 16 h 45 min
- PR mergées (30 j)
- 12
Préparer son environnement
- Aucun Dockerfile ni fichier Docker Compose
- Aucun modèle de pull request
- Lire le guide de contribution
Par où commencer
- Lisez l'issue en entier, puis le guide de contribution du projet.
- Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
- Forkez le dépôt et travaillez sur une branche.
- Ouvrez une pull request qui référence le numéro de l'issue.
Autres issues de AccessKit/accesskit
-
Difficulté 2/5 1-3 heures Accessibilité débutants 78/100
Les mainteneurs répondent en général sous 1 jour
-
Document sub-treesOuverte
Difficulté 2/5 1-3 heures Accessibilité débutants 75/100
Les mainteneurs répondent en général sous 1 jour
-
Document `Role::ColorWell`Ouverte
Difficulté 2/5 1-3 heures Accessibilité débutants 72/100
Les mainteneurs répondent en général sous 1 jour
-
Difficulté 4/5 3-5 jours Accessibilité débutants 56/100
Les mainteneurs répondent en général sous 1 jour
-
Difficulté 5/5 Plus d'une semaine Accessibilité débutants 35/100
Les mainteneurs répondent en général sous 1 jour
Toutes les issues de AccessKit/accesskit
Issues similaires
-
Difficulté 2/5 1-3 heures Accessibilité débutants 76/100
Les mainteneurs répondent en général sous 2 jours
-
Difficulté 2/5 1-3 heures Accessibilité débutants 86/100
nervosnetwork/fiber#1723 ·
Les mainteneurs répondent en général sous 2 jours
-
Difficulté 2/5 1-3 heures Accessibilité débutants 69/100
Les mainteneurs répondent en général sous 1 jour
-
needs triage
Difficulté 2/5 1-3 heures Accessibilité débutants 71/100
pbakaus/impeccable#1314 ·
Les mainteneurs répondent en général sous 1 jour
-
marmite skill: `curl ... | sh` is the first install method, bypassing review and integrity checksOuverte
Difficulté 1/5 1-3 heures Accessibilité débutants 78/100
rochacbruno/marmite#565 ·