Phase 13.1.c — rapport upstream bug B.2 ion + warn image étroite (B.4)
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
This commit is contained in:
parent
58ef6a85c2
commit
095d7e5550
2 changed files with 185 additions and 0 deletions
167
docs/phase13-1-c-ion-bug-b2-upstream.md
Normal file
167
docs/phase13-1-c-ion-bug-b2-upstream.md
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
# Bug B.2 — Rapport pour upstream Redox ion
|
||||
|
||||
> Document produit le 2026-05-16 dans le cadre de
|
||||
> [`phase13-1-c-cursor.md`](phase13-1-c-cursor.md). À copier-coller (en
|
||||
> traduisant en anglais) dans une issue sur
|
||||
> `gitlab.redox-os.org/redox-os/ion/-/issues` quand 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-src` la veille)
|
||||
- **ion** : version embarquée dans cette image (binaire stripped, source upstream synced via cookbook recipe `core/ion`)
|
||||
- **QEMU** : `qemu-system-x86_64` avec `-enable-kvm -cpu host -k fr` sur 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
|
||||
|
||||
```sh
|
||||
# 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` :
|
||||
|
||||
```rust
|
||||
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
|
||||
|
||||
1. Identifier la fonction à `0x2335ae` (rebuild non-stripped + addr2line).
|
||||
2. Confirmer si c'est un null deref dans `process.forget()`, drop de
|
||||
`BackgroundProcess`, ou la déstructure du `Vec<BackgroundProcess>`.
|
||||
3. Patch.
|
||||
|
||||
## Workaround utilisateur en attendant
|
||||
|
||||
Toujours quitter les clients background **avant** le serveur :
|
||||
|
||||
```sh
|
||||
# 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).
|
||||
18
run-qemu.sh
18
run-qemu.sh
|
|
@ -84,6 +84,24 @@ if [[ ! -e /dev/fuse ]]; then
|
|||
exit 3
|
||||
fi
|
||||
|
||||
# Phase 13.1.c B.4 : warn si l'image est trop petite. L'image desktop par
|
||||
# défaut fait ~680 Mo et sature dès qu'on tente `pkg update` (cf. session
|
||||
# de la phase 13.1.b). Pour confort, recommandation : 4 Go minimum, idéal
|
||||
# 10 Go. La grossir avec :
|
||||
# qemu-img resize -f raw <image> 10G
|
||||
# <redox-src>/build/fstools/bin/redoxfs-resize <image>
|
||||
IMAGE_SIZE_BYTES=$(stat -c %s "$IMAGE" 2>/dev/null || echo 0)
|
||||
MIN_IMAGE_SIZE=$((4 * 1024 * 1024 * 1024)) # 4 GiB
|
||||
if [[ "$IMAGE_SIZE_BYTES" -gt 0 && "$IMAGE_SIZE_BYTES" -lt "$MIN_IMAGE_SIZE" ]]; then
|
||||
image_size_human=$(numfmt --to=iec --suffix=B "$IMAGE_SIZE_BYTES" 2>/dev/null || echo "${IMAGE_SIZE_BYTES} octets")
|
||||
echo "WARN : image $IMAGE de taille ${image_size_human} (< 4 GiB recommandés)" >&2
|
||||
echo " Tu risques 'No space left on device' au moindre pkg update." >&2
|
||||
echo " Pour la grossir :" >&2
|
||||
echo " qemu-img resize -f raw $IMAGE 10G" >&2
|
||||
echo " $REDOX_SRC/build/fstools/bin/redoxfs-resize $IMAGE" >&2
|
||||
echo " (warning seulement, on continue)" >&2
|
||||
fi
|
||||
|
||||
# --- 2. Mount ---
|
||||
mkdir -p "$MOUNT"
|
||||
echo "==> monter $IMAGE -> $MOUNT"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue