diff --git a/CHANGELOG.md b/CHANGELOG.md index 97c3b102e5..af9d771b2b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -48,6 +48,7 @@ Bottom level categories: - Allow multi-sampled textures that are supported by the device but not WebGPU if `TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES` is enabled by @cwfitzgerald in [#2856](https://github.com/gfx-rs/wgpu/pull/2856) - `get_texture_format_features` only lists the COPY_* usages if the adapter actually supports that usage by @cwfitzgerald in [#2856](https://github.com/gfx-rs/wgpu/pull/2856) - Fix bind group / pipeline deduplication not taking into account RenderBundle execution resetting these values by @shoebe [#2867](https://github.com/gfx-rs/wgpu/pull/2867) +- Fix panics that occur when using `as_hal` functions when the hal generic type does not match the hub being looked up in by @i509VCB [#2871](https://github.com/gfx-rs/wgpu/pull/2871) #### DX12 - `DownlevelCapabilities::default()` now returns the `ANISOTROPIC_FILTERING` flag set to true so DX12 lists `ANISOTROPIC_FILTERING` as true again by @cwfitzgerald in [#2851](https://github.com/gfx-rs/wgpu/pull/2851) diff --git a/wgpu-core/src/hub.rs b/wgpu-core/src/hub.rs index 8c7e617e38..091e785665 100644 --- a/wgpu-core/src/hub.rs +++ b/wgpu-core/src/hub.rs @@ -158,6 +158,28 @@ impl Storage { } } + /// Attempts to get a reference to an item behind a potentially invalid ID. + /// + /// Returns [`None`] if there is an epoch mismatch, or the entry is empty. + /// + /// This function is primarily intended for the `as_hal` family of functions where you may need to + /// fallibly get a object backed by an id that could be in a different hub. + pub(crate) fn try_get(&self, id: I) -> Result, InvalidId> { + let (index, epoch, _) = id.unzip(); + let (result, storage_epoch) = match self.map.get(index as usize) { + Some(&Element::Occupied(ref v, epoch)) => (Ok(Some(v)), epoch), + Some(&Element::Vacant) => return Ok(None), + Some(&Element::Error(epoch, ..)) => (Err(InvalidId), epoch), + None => return Err(InvalidId), + }; + assert_eq!( + epoch, storage_epoch, + "{}[{}] is no longer alive", + self.kind, index + ); + result + } + /// Get a reference to an item behind a potentially invalid ID. /// Panics if there is an epoch mismatch, or the entry is empty. pub(crate) fn get(&self, id: I) -> Result<&T, InvalidId> { diff --git a/wgpu-core/src/resource.rs b/wgpu-core/src/resource.rs index 4c123587ac..53c05b82fd 100644 --- a/wgpu-core/src/resource.rs +++ b/wgpu-core/src/resource.rs @@ -293,7 +293,7 @@ impl Global { let hub = A::hub(self); let mut token = Token::root(); let (guard, _) = hub.textures.read(&mut token); - let texture = guard.get(id).ok(); + let texture = guard.try_get(id).ok().flatten(); let hal_texture = texture.map(|tex| tex.inner.as_raw().unwrap()); hal_texture_callback(hal_texture); @@ -313,7 +313,7 @@ impl Global { let mut token = Token::root(); let (guard, _) = hub.adapters.read(&mut token); - let adapter = guard.get(id).ok(); + let adapter = guard.try_get(id).ok().flatten(); let hal_adapter = adapter.map(|adapter| &adapter.raw.adapter); hal_adapter_callback(hal_adapter) @@ -332,7 +332,7 @@ impl Global { let hub = A::hub(self); let mut token = Token::root(); let (guard, _) = hub.devices.read(&mut token); - let device = guard.get(id).ok(); + let device = guard.try_get(id).ok().flatten(); let hal_device = device.map(|device| &device.raw); hal_device_callback(hal_device)