fix(compositor): replace panic-prone unwraps with explicit error handling in winit and DRM backends

- winit backend: client insertion and dispatch_clients failures now log
  and continue instead of unwinding the event loop
- winit backend: bind/render/submit failures in the redraw handler skip
  the frame and log a warning; the compositor stays running
- DRM backend: same client insertion and dispatch_clients treatment
- DRM device_added: use .context()? instead of unwrap() when inserting
  the new device entry after the drm field is known to be initialised
- DRM render_output: use guard-return instead of unwrap() to access drm
  state that was already verified non-None lines above
- compositor state: duplicate layer surface mapping from a misbehaving
  client logs a warning and returns instead of panicking
This commit is contained in:
Marco Allegretti 2026-03-13 13:56:57 +01:00
parent 67f54c39be
commit b82345d24e
3 changed files with 49 additions and 24 deletions

View file

@ -137,10 +137,12 @@ pub fn run() -> anyhow::Result<()> {
loop_handle
.insert_source(listening_socket, |stream, _, state| {
state
if let Err(e) = state
.display_handle
.insert_client(stream, Arc::new(WeftClientState::default()))
.unwrap();
{
tracing::warn!(?e, "failed to insert Wayland client");
}
})
.map_err(|e| anyhow::anyhow!("socket source: {e}"))?;
@ -150,7 +152,9 @@ pub fn run() -> anyhow::Result<()> {
|_, display, state| {
// Safety: Display is owned by this Generic source and outlives the event loop.
unsafe {
display.get_mut().dispatch_clients(state).unwrap();
if let Err(e) = display.get_mut().dispatch_clients(state) {
tracing::warn!(?e, "Wayland dispatch error");
}
}
Ok(PostAction::Continue)
},
@ -375,16 +379,21 @@ fn device_added(state: &mut WeftCompositorState, node: DrmNode, path: &Path) ->
)
.map_err(|e| anyhow::anyhow!("DRM notifier: {e}"))?;
state.drm.as_mut().unwrap().devices.insert(
node,
WeftDrmDevice {
drm_output_manager,
drm_scanner: DrmScanner::new(),
surfaces: HashMap::new(),
render_node,
registration_token,
},
);
state
.drm
.as_mut()
.context("DRM data missing after initialization")?
.devices
.insert(
node,
WeftDrmDevice {
drm_output_manager,
drm_scanner: DrmScanner::new(),
surfaces: HashMap::new(),
render_node,
registration_token,
},
);
device_changed(state, node);
Ok(())
@ -604,7 +613,7 @@ fn render_output(state: &mut WeftCompositorState, node: DrmNode, crtc: crtc::Han
};
let render_node = {
let d = state.drm.as_ref().unwrap();
let Some(d) = state.drm.as_ref() else { return };
d.devices
.get(&node)
.and_then(|d| d.render_node)

View file

@ -63,10 +63,12 @@ pub fn run() -> anyhow::Result<()> {
loop_handle
.insert_source(listening_socket, |client_stream, _, state| {
state
if let Err(e) = state
.display_handle
.insert_client(client_stream, Arc::new(WeftClientState::default()))
.unwrap();
{
tracing::warn!(?e, "failed to insert Wayland client");
}
})
.map_err(|e| anyhow::anyhow!("socket source insertion failed: {e}"))?;
@ -78,7 +80,9 @@ pub fn run() -> anyhow::Result<()> {
// Safety: the display is owned by this Generic source and is never dropped
// while the event loop runs.
unsafe {
display.get_mut().dispatch_clients(state).unwrap();
if let Err(e) = display.get_mut().dispatch_clients(state) {
tracing::warn!(?e, "Wayland dispatch error");
}
}
Ok(PostAction::Continue)
},
@ -129,9 +133,8 @@ pub fn run() -> anyhow::Result<()> {
let size = backend.window_size();
let full_damage = Rectangle::from_size(size);
{
let (renderer, mut framebuffer) = backend.bind().unwrap();
smithay::desktop::space::render_output::<
let render_ok = match backend.bind() {
Ok((renderer, mut framebuffer)) => smithay::desktop::space::render_output::<
_,
WaylandSurfaceRenderElement<GlesRenderer>,
_,
@ -147,9 +150,18 @@ pub fn run() -> anyhow::Result<()> {
&mut damage_tracker,
[0.1_f32, 0.1, 0.1, 1.0],
)
.unwrap();
.map_err(|e| tracing::warn!(?e, "render_output failed"))
.is_ok(),
Err(e) => {
tracing::warn!(?e, "backend bind failed");
false
}
};
if render_ok {
if let Err(e) = backend.submit(Some(&[full_damage])) {
tracing::warn!(?e, "backend submit failed");
}
}
backend.submit(Some(&[full_damage])).unwrap();
state.space.elements().for_each(|window| {
window.send_frame(

View file

@ -294,9 +294,13 @@ impl WlrLayerShellHandler for WeftCompositorState {
) {
let desktop_surface = DesktopLayerSurface::new(surface, namespace);
if let Some(output) = self.space.outputs().next().cloned() {
layer_map_for_output(&output)
if layer_map_for_output(&output)
.map_layer(&desktop_surface)
.expect("layer surface must not already be mapped");
.is_err()
{
tracing::warn!("received duplicate layer surface mapping; ignoring");
return;
}
layer_map_for_output(&output).arrange();
}
}