B.2 (ion page fault) : pas fixable dans ce repo. Source d'ion clonée depuis upstream et inspectée : pas de commit récent visant ce pattern de crash, binaire stripped sur l'image (impossible de mapper RIP=0x2335ae à une fonction sans non-stripped build). Rapport upstream-ready rédigé dans docs/phase13-1-c-ion-bug-b2-upstream.md, à coller sur gitlab.redox-os.org/redox-os/ion quand on aura un compte. Bonus diagnostic noté : warning relibc « Cancellation for unknown id » apparaît juste avant le crash ion, peut être lié à un side-effect dans procmgr (à investiguer côté relibc aussi). Workaround documenté pour utilisateurs : quitter les clients background AVANT le serveur Wayland (ESC sur le client, puis Ctrl+Q sur le compo). B.4 (image étroite) : run-qemu.sh warn maintenant si harddrive.img < 4 GiB, avec les commandes de resize prêtes à copier-coller. Continue sans bloquer (image actuelle de l'utilisateur fait 10 GiB, no-op pour notre setup, mais utile pour quelqu'un qui clone le repo et utilise l'image desktop par défaut de Redox.) Leyoda 2026 – GPLv3
6.2 KiB
Bug B.2 — Rapport pour upstream Redox ion
Document produit le 2026-05-16 dans le cadre de
phase13-1-c-cursor.md. À copier-coller (en traduisant en anglais) dans une issue surgitlab.redox-os.org/redox-os/ion/-/issuesquand on aura un compte.
Title
ion: page fault 0x70 when a background job dies on broken pipe (Wayland client + compositor scenario)
Environment
- Redox image : harddrive.img du 2026-05-08 (build x86_64 desktop, rebuild depuis
redox-srcla veille) - ion : version embarquée dans cette image (binaire stripped, source upstream synced via cookbook recipe
core/ion) - QEMU :
qemu-system-x86_64avec-enable-kvm -cpu host -k frsur Linux host (CachyOS 7.0.8) - Repro : 100 % reproductible sur 3 sessions distinctes avec reboot frais entre chaque
Symptôme
Quand un job background termine sur Broken pipe (ex: client Wayland dont le compositor vient de fermer son socket), ion crashe avec un page fault à l'adresse 0x70. Le kernel logue UNHANDLED EXCEPTION pour le process ion. Le shell devient indisponible jusqu'au prochain login.
ion: ([Page fault: 0000000000000070 US
RFLAG: 0000000000010212
CS: 000000000000002b
RIP: 00000000002335ae
RSP: 0000000000bb0e60
SS: 0000000000000023
FSBASE 000000000092b000
GSBASE 0000000000000000
KGSBASE ffff80007fed8000
RAX: 0000000000000070 <-- valeur fautive = offset du field
RCX: 0000000000000000
RDX: 0000000000233550
RDI: 0000000000000001
RSI: 00000000006c9970
R8: 0000000000000000
R9: 0000000000000000
R10: 0000000000000000
R11: 0000000000000008
RBX: 000000000092b000
RBP: 0000000000bb0e70
R12: 000000000092acc8
R13: 00000000006afe20
R14: 0000000000000001
R15: 00000000006afe20
FP 0000000000bb0e70: PC 0000000000f27745
FP 0000000000bb0f40: PC 0000000000f0a167
FP 0000000000bb0f70: PC 0000000000f0a02d
FP 0000000000bb0ff0: PC 0000000000eabd43
<Invalid next frame pointer 0x0000000000000000; stack walk ended>
FP ffff80001798fe80: PC ffffffff8008a42d
kernel::arch::x86_shared::interrupt::exception::page::inner
FP ffff80001798ff50: PC ffffffff80087ee7
kernel::arch::x86_shared::interrupt::exception::page
0000000000bb0e70: GUARD PAGE
kernel::context::signal:INFO -- UNHANDLED EXCEPTION, CPU #3, PID 45, NAME /usr/bin/ion
Pattern : déréférence d'un pointer null avec accès au champ à l'offset 0x70 (RAX=0x70, addr=0x70).
Repro minimal
# Dans une session ion fraîche, avec le compositor Wayland
# (https://gitlab.com/leyoda/redox-wayland-compositor) :
redox-wl-compositor & # backround job [0]
sleep 1
redox-wl-real-client-simple-window & # background job [1]
sleep 2
# Maintenant, tuer le compositor SANS quitter le client proprement.
# Le compositor ferme son socket, le client reçoit Broken pipe et exit
# avec status non-zéro. C'est en traitant cette terminaison que ion crashe.
pkill redox-wl-compositor
Reproductible aussi avec n'importe quelle paire client-serveur Unix :
- serveur en bg qui ferme son socket
- client en bg qui écrit dessus et reçoit EPIPE
Hypothèse de localisation (best-effort sans symboles)
Le crash semble survenir dans BackgroundEventCallback. La closure dans
src/main.rs:224-234 :
shell.set_background_event(Some(Arc::new(|njob, pid, kind| match kind {
BackgroundEvent::Added => eprintln!("ion: bg [{}] {}", njob, pid),
BackgroundEvent::Stopped => eprintln!("ion: ([{}] {}) Stopped", njob, pid),
BackgroundEvent::Resumed => eprintln!("ion: ([{}] {}) Running", njob, pid),
BackgroundEvent::Exited(status) => {
eprintln!("ion: ([{}] {}) exited with {}", njob, pid, status)
}
BackgroundEvent::Errored(error) => {
eprintln!("ion: ([{}] {}) errored: {}", njob, pid, error)
}
})));
Appelée depuis src/lib/shell/pipe_exec/job_control.rs:148-228 (watch_background), elle-même runs depuis un thread dédié au polling de waitpid.
Note : sur la sortie observée, le message "exited with" est imprimé AVANT le page fault :
[real-client] FAIL: Backend error: Io error: Broken pipe (os error 32)
root:~# [src/procmgr.rs:299 WARN] Cancellation for unknown id Id(26)
root:~#
ion: ([Page fault: 0000000000000070 ...
Donc le callback aurait fini son eprintln!, le crash arrive juste après — possiblement dans le code qui suit, peut-être le get_process!(|process| { process.forget(); ... }) ou dans le drop du job, ou dans le retour de thread vers le main thread.
Disassembly stripped autour de RIP=0x2335ae
2335a2: 48 8b 85 60 fe ff ff mov -0x1a0(%rbp), %rax
2335a9: 48 d1 e0 shl $1, %rax
2335ac: 48 85 c0 test %rax, %rax
2335af: 74 0d je 0x2335be
Pattern Vec/Box drop : "test capacity*2, jump-if-zero, else free pointer".
Le 0x2335ae tombe au milieu de l'instruction test — possible que
le strip + offset stable ne pointe pas exactement à la même instruction
sur l'image installée vs le rebuild local. RAX=0x70 au crash suggère un
load mov [rdi+0x70], rax (ou similaire) où rdi est null. Le champ à
l'offset 0x70 d'une struct Rust commune (BackgroundProcess ? File ?
Mutex<Vec<...>> ?) — à confirmer avec un build debug.
Side-bug observé en parallèle
Sur la même session, juste avant le crash :
[src/procmgr.rs:299 WARN] Cancellation for unknown id Id(26)
Ce warning vient de relibc (procmgr), pas d'ion. Peut être lié — une
cancellation de syscall qui laisse un state inconsistent, qu'ion
manipule ensuite. À investiguer côté relibc aussi.
Demande
- Identifier la fonction à
0x2335ae(rebuild non-stripped + addr2line). - Confirmer si c'est un null deref dans
process.forget(), drop deBackgroundProcess, ou la déstructure duVec<BackgroundProcess>. - Patch.
Workaround utilisateur en attendant
Toujours quitter les clients background avant le serveur :
# Bon ordre :
redox-wl-real-client-simple-window &
# (interagir)
fg %1 # ramener au foreground
# ESC ou autre pour quitter proprement
pkill redox-wl-compositor # seulement après que tous les clients sont sortis
Référence
Bug détecté pendant le port d'un compositor Wayland minimal sur Redox : https://gitlab.com/leyoda/redox-wayland-compositor (phase 13.1.b / 13.1.c).