Avoid overflow in check texture copy bounds. (#2963)

This commit is contained in:
Jim Blandy 2022-08-28 17:07:04 -07:00 committed by GitHub
parent a0dfb28b8d
commit 7d138e2e76
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 107 additions and 36 deletions

View File

@ -225,6 +225,8 @@ jobs:
for backend in ${{ matrix.backends }}; do for backend in ${{ matrix.backends }}; do
echo "======= NATIVE TESTS $backend ======"; echo "======= NATIVE TESTS $backend ======";
WGPU_BACKEND=$backend cargo nextest run -p wgpu --no-fail-fast WGPU_BACKEND=$backend cargo nextest run -p wgpu --no-fail-fast
# Test that we catch overflows in `--release` builds too.
WGPU_BACKEND=$backend cargo nextest run --release -p wgpu --no-fail-fast
done done
fmt: fmt:

View File

@ -64,6 +64,7 @@ the same every time it is rendered, we now warn if it is missing.
#### General #### General
- Free `StagingBuffers` even when an error occurs in the operation that consumes them. By @jimblandy in [#2961](https://github.com/gfx-rs/wgpu/pull/2961) - Free `StagingBuffers` even when an error occurs in the operation that consumes them. By @jimblandy in [#2961](https://github.com/gfx-rs/wgpu/pull/2961)
- Avoid overflow when checking that texture copies fall within bounds. By @jimblandy in [#2963](https://github.com/gfx-rs/wgpu/pull/2963)
- Improve the validation and error reporting of buffer mappings by @nical in [#2848](https://github.com/gfx-rs/wgpu/pull/2848) - Improve the validation and error reporting of buffer mappings by @nical in [#2848](https://github.com/gfx-rs/wgpu/pull/2848)
- Fix compilation errors when using wgpu-core in isolation while targetting `wasm32-unknown-unknown` by @Seamooo in [#2922](https://github.com/gfx-rs/wgpu/pull/2922) - Fix compilation errors when using wgpu-core in isolation while targetting `wasm32-unknown-unknown` by @Seamooo in [#2922](https://github.com/gfx-rs/wgpu/pull/2922)
- Fixed opening of RenderDoc library by @abuffseagull in [#2930](https://github.com/gfx-rs/wgpu/pull/2930) - Fixed opening of RenderDoc library by @abuffseagull in [#2930](https://github.com/gfx-rs/wgpu/pull/2930)

View File

@ -25,7 +25,7 @@ use std::iter;
pub type ImageCopyBuffer = wgt::ImageCopyBuffer<BufferId>; pub type ImageCopyBuffer = wgt::ImageCopyBuffer<BufferId>;
pub type ImageCopyTexture = wgt::ImageCopyTexture<TextureId>; pub type ImageCopyTexture = wgt::ImageCopyTexture<TextureId>;
#[derive(Clone, Debug)] #[derive(Clone, Copy, Debug)]
pub enum CopySide { pub enum CopySide {
Source, Source,
Destination, Destination,
@ -326,37 +326,52 @@ pub(crate) fn validate_texture_copy_range(
_ => {} _ => {}
} }
let x_copy_max = texture_copy_view.origin.x + copy_size.width; /// Return `Ok` if a run `size` texels long starting at `start_offset` falls
if x_copy_max > extent.width { /// entirely within `texture_size`. Otherwise, return an appropriate a`Err`.
return Err(TransferError::TextureOverrun { fn check_dimension(
start_offset: texture_copy_view.origin.x, dimension: TextureErrorDimension,
end_offset: x_copy_max, side: CopySide,
texture_size: extent.width, start_offset: u32,
dimension: TextureErrorDimension::X, size: u32,
side: texture_side, texture_size: u32,
}); ) -> Result<(), TransferError> {
} // Avoid underflow in the subtraction by checking start_offset against
let y_copy_max = texture_copy_view.origin.y + copy_size.height; // texture_size first.
if y_copy_max > extent.height { if start_offset <= texture_size && size <= texture_size - start_offset {
return Err(TransferError::TextureOverrun { Ok(())
start_offset: texture_copy_view.origin.y, } else {
end_offset: y_copy_max, Err(TransferError::TextureOverrun {
texture_size: extent.height, start_offset,
dimension: TextureErrorDimension::Y, end_offset: start_offset.wrapping_add(size),
side: texture_side, texture_size,
}); dimension,
} side,
let z_copy_max = texture_copy_view.origin.z + copy_size.depth_or_array_layers; })
if z_copy_max > extent.depth_or_array_layers { }
return Err(TransferError::TextureOverrun {
start_offset: texture_copy_view.origin.z,
end_offset: z_copy_max,
texture_size: extent.depth_or_array_layers,
dimension: TextureErrorDimension::Z,
side: texture_side,
});
} }
check_dimension(
TextureErrorDimension::X,
texture_side,
texture_copy_view.origin.x,
copy_size.width,
extent.width,
)?;
check_dimension(
TextureErrorDimension::Y,
texture_side,
texture_copy_view.origin.y,
copy_size.height,
extent.height,
)?;
check_dimension(
TextureErrorDimension::Z,
texture_side,
texture_copy_view.origin.z,
copy_size.depth_or_array_layers,
extent.depth_or_array_layers,
)?;
if texture_copy_view.origin.x % block_width != 0 { if texture_copy_view.origin.x % block_width != 0 {
return Err(TransferError::UnalignedCopyOriginX); return Err(TransferError::UnalignedCopyOriginX);
} }

View File

@ -5,7 +5,7 @@ use std::num::NonZeroU32;
#[test] #[test]
fn bad_copy_origin() { fn bad_copy_origin() {
fn try_origin(origin: wgpu::Origin3d, should_panic: bool) { fn try_origin(origin: wgpu::Origin3d, size: wgpu::Extent3d, should_panic: bool) {
let mut parameters = TestParameters::default(); let mut parameters = TestParameters::default();
if should_panic { if should_panic {
parameters = parameters.failure(); parameters = parameters.failure();
@ -23,15 +23,68 @@ fn bad_copy_origin() {
}, },
&data, &data,
BUFFER_COPY_LAYOUT, BUFFER_COPY_LAYOUT,
TEXTURE_SIZE, size,
); );
}); });
} }
try_origin(wgpu::Origin3d { x: 0, y: 0, z: 0 }, false); try_origin(wgpu::Origin3d { x: 0, y: 0, z: 0 }, TEXTURE_SIZE, false);
try_origin(wgpu::Origin3d { x: 1, y: 0, z: 0 }, true); try_origin(wgpu::Origin3d { x: 1, y: 0, z: 0 }, TEXTURE_SIZE, true);
try_origin(wgpu::Origin3d { x: 0, y: 1, z: 0 }, true); try_origin(wgpu::Origin3d { x: 0, y: 1, z: 0 }, TEXTURE_SIZE, true);
try_origin(wgpu::Origin3d { x: 0, y: 0, z: 1 }, true); try_origin(wgpu::Origin3d { x: 0, y: 0, z: 1 }, TEXTURE_SIZE, true);
try_origin(
wgpu::Origin3d {
x: TEXTURE_SIZE.width - 1,
y: TEXTURE_SIZE.height - 1,
z: TEXTURE_SIZE.depth_or_array_layers - 1,
},
wgpu::Extent3d {
width: 1,
height: 1,
depth_or_array_layers: 1,
},
false,
);
try_origin(
wgpu::Origin3d {
x: u32::MAX,
y: 0,
z: 0,
},
wgpu::Extent3d {
width: 1,
height: 1,
depth_or_array_layers: 1,
},
true,
);
try_origin(
wgpu::Origin3d {
x: u32::MAX,
y: 0,
z: 0,
},
wgpu::Extent3d {
width: 1,
height: 1,
depth_or_array_layers: 1,
},
true,
);
try_origin(
wgpu::Origin3d {
x: u32::MAX,
y: 0,
z: 0,
},
wgpu::Extent3d {
width: 1,
height: 1,
depth_or_array_layers: 1,
},
true,
);
} }
const TEXTURE_SIZE: wgpu::Extent3d = wgpu::Extent3d { const TEXTURE_SIZE: wgpu::Extent3d = wgpu::Extent3d {