Skip to content

Commit db30e39

Browse files
authored
Avoid integer overflow on multiplication in write_texture. (#3146)
1 parent 2245227 commit db30e39

File tree

6 files changed

+115
-26
lines changed

6 files changed

+115
-26
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ Bottom level categories:
7676
- Fixed the mipmap example by adding the missing WRITE_TIMESTAMP_INSIDE_PASSES feature. By @Olaroll in [#3081](https://github.com/gfx-rs/wgpu/pull/3081).
7777
- Avoid panicking in some interactions with invalid resources by @nical in (#3094)[https://github.com/gfx-rs/wgpu/pull/3094]
7878
- Remove `wgpu_types::Features::DEPTH24PLUS_STENCIL8`, making `wgpu::TextureFormat::Depth24PlusStencil8` available on all backends. By @Healthire in (#3151)[https://github.com/gfx-rs/wgpu/pull/3151]
79+
- Fix an integer overflow in `queue_write_texture` by @nical in (#3146)[https://github.com/gfx-rs/wgpu/pull/3146]
7980

8081
#### WebGPU
8182
- Use `log` instead of `println` in hello example by @JolifantoBambla in [#2858](https://github.com/gfx-rs/wgpu/pull/2858)

wgpu-core/src/command/transfer.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,10 @@ pub(crate) fn validate_linear_texture_data(
219219
copy_size: &Extent3d,
220220
need_copy_aligned_rows: bool,
221221
) -> Result<(BufferAddress, BufferAddress), TransferError> {
222-
// Convert all inputs to BufferAddress (u64) to prevent overflow issues
222+
// Convert all inputs to BufferAddress (u64) to avoid some of the overflow issues
223+
// Note: u64 is not always enough to prevent overflow, especially when multiplying
224+
// something with a potentially large depth value, so it is preferrable to validate
225+
// the copy size before calling this function (for example via `validate_texture_copy_range`).
223226
let copy_width = copy_size.width as BufferAddress;
224227
let copy_height = copy_size.height as BufferAddress;
225228
let copy_depth = copy_size.depth_or_array_layers as BufferAddress;

wgpu-core/src/device/queue.rs

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -600,6 +600,19 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
600600
let (selector, dst_base, texture_format) =
601601
extract_texture_selector(destination, size, &*texture_guard)?;
602602
let format_desc = texture_format.describe();
603+
604+
let dst = texture_guard.get_mut(destination.texture).unwrap();
605+
if !dst.desc.usage.contains(wgt::TextureUsages::COPY_DST) {
606+
return Err(
607+
TransferError::MissingCopyDstUsageFlag(None, Some(destination.texture)).into(),
608+
);
609+
}
610+
611+
// Note: Doing the copy range validation early is important because ensures that the
612+
// dimensions are not going to cause overflow in other parts of the validation.
613+
let (hal_copy_size, array_layer_count) =
614+
validate_texture_copy_range(destination, &dst.desc, CopySide::Destination, size)?;
615+
603616
// Note: `_source_bytes_per_array_layer` is ignored since we
604617
// have a staging copy, and it can have a different value.
605618
let (_, _source_bytes_per_array_layer) = validate_linear_texture_data(
@@ -642,13 +655,6 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
642655
(size.depth_or_array_layers - 1) * block_rows_per_image + height_blocks;
643656
let stage_size = stage_bytes_per_row as u64 * block_rows_in_copy as u64;
644657

645-
let dst = texture_guard.get_mut(destination.texture).unwrap();
646-
if !dst.desc.usage.contains(wgt::TextureUsages::COPY_DST) {
647-
return Err(
648-
TransferError::MissingCopyDstUsageFlag(None, Some(destination.texture)).into(),
649-
);
650-
}
651-
652658
let mut trackers = device.trackers.lock();
653659
let encoder = device.pending_writes.activate();
654660

@@ -702,8 +708,6 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
702708
)
703709
.ok_or(TransferError::InvalidTexture(destination.texture))?;
704710

705-
let (hal_copy_size, array_layer_count) =
706-
validate_texture_copy_range(destination, &dst.desc, CopySide::Destination, size)?;
707711
dst.life_guard.use_at(device.active_submission_index + 1);
708712

709713
let dst_raw = dst

wgpu/src/backend/direct.rs

Lines changed: 47 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ impl Context {
9595
hal_device: hal::OpenDevice<A>,
9696
desc: &crate::DeviceDescriptor,
9797
trace_dir: Option<&std::path::Path>,
98-
) -> Result<(Device, wgc::id::QueueId), crate::RequestDeviceError> {
98+
) -> Result<(Device, Queue), crate::RequestDeviceError> {
9999
let global = &self.0;
100100
let (device_id, error) = global.create_device_from_hal(
101101
*adapter,
@@ -107,12 +107,17 @@ impl Context {
107107
if let Some(err) = error {
108108
self.handle_error_fatal(err, "Adapter::create_device_from_hal");
109109
}
110+
let error_sink = Arc::new(Mutex::new(ErrorSinkRaw::new()));
110111
let device = Device {
111112
id: device_id,
112-
error_sink: Arc::new(Mutex::new(ErrorSinkRaw::new())),
113+
error_sink: error_sink.clone(),
113114
features: desc.features,
114115
};
115-
Ok((device, device_id))
116+
let queue = Queue {
117+
id: device_id,
118+
error_sink,
119+
};
120+
Ok((device, queue))
116121
}
117122

118123
#[cfg(any(not(target_arch = "wasm32"), feature = "emscripten"))]
@@ -808,6 +813,18 @@ pub struct Texture {
808813
error_sink: ErrorSink,
809814
}
810815

816+
#[derive(Debug)]
817+
pub struct Queue {
818+
id: wgc::id::QueueId,
819+
error_sink: ErrorSink,
820+
}
821+
822+
impl Queue {
823+
pub(crate) fn backend(&self) -> wgt::Backend {
824+
self.id.backend()
825+
}
826+
}
827+
811828
#[derive(Debug)]
812829
pub(crate) struct CommandEncoder {
813830
id: wgc::id::CommandEncoderId,
@@ -858,10 +875,17 @@ impl crate::GlobalId for CommandEncoder {
858875
}
859876
}
860877

878+
impl crate::GlobalId for Queue {
879+
fn global_id(&self) -> Id {
880+
use wgc::id::TypedId;
881+
self.id.unzip()
882+
}
883+
}
884+
861885
impl crate::Context for Context {
862886
type AdapterId = wgc::id::AdapterId;
863887
type DeviceId = Device;
864-
type QueueId = wgc::id::QueueId;
888+
type QueueId = Queue;
865889
type ShaderModuleId = wgc::id::ShaderModuleId;
866890
type BindGroupLayoutId = wgc::id::BindGroupLayoutId;
867891
type BindGroupId = wgc::id::BindGroupId;
@@ -951,12 +975,17 @@ impl crate::Context for Context {
951975
log::error!("Error in Adapter::request_device: {}", err);
952976
return ready(Err(crate::RequestDeviceError));
953977
}
978+
let error_sink = Arc::new(Mutex::new(ErrorSinkRaw::new()));
954979
let device = Device {
955980
id: device_id,
956-
error_sink: Arc::new(Mutex::new(ErrorSinkRaw::new())),
981+
error_sink: error_sink.clone(),
957982
features: desc.features,
958983
};
959-
ready(Ok((device, device_id)))
984+
let queue = Queue {
985+
id: device_id,
986+
error_sink,
987+
};
988+
ready(Ok((device, queue)))
960989
}
961990

962991
fn adapter_is_surface_supported(
@@ -2270,7 +2299,7 @@ impl crate::Context for Context {
22702299
) {
22712300
let global = &self.0;
22722301
match wgc::gfx_select!(
2273-
*queue => global.queue_write_buffer(*queue, buffer.id, offset, data)
2302+
*queue => global.queue_write_buffer(queue.id, buffer.id, offset, data)
22742303
) {
22752304
Ok(()) => (),
22762305
Err(err) => self.handle_error_fatal(err, "Queue::write_buffer"),
@@ -2286,7 +2315,7 @@ impl crate::Context for Context {
22862315
) {
22872316
let global = &self.0;
22882317
match wgc::gfx_select!(
2289-
*queue => global.queue_validate_write_buffer(*queue, buffer.id, offset, size.get())
2318+
*queue => global.queue_validate_write_buffer(queue.id, buffer.id, offset, size.get())
22902319
) {
22912320
Ok(()) => (),
22922321
Err(err) => self.handle_error_fatal(err, "Queue::write_buffer_with"),
@@ -2300,7 +2329,7 @@ impl crate::Context for Context {
23002329
) -> QueueWriteBuffer {
23012330
let global = &self.0;
23022331
match wgc::gfx_select!(
2303-
*queue => global.queue_create_staging_buffer(*queue, size, ())
2332+
*queue => global.queue_create_staging_buffer(queue.id, size, ())
23042333
) {
23052334
Ok((buffer_id, ptr)) => QueueWriteBuffer {
23062335
buffer_id,
@@ -2322,10 +2351,12 @@ impl crate::Context for Context {
23222351
) {
23232352
let global = &self.0;
23242353
match wgc::gfx_select!(
2325-
*queue => global.queue_write_staging_buffer(*queue, buffer.id, offset, staging_buffer.buffer_id)
2354+
*queue => global.queue_write_staging_buffer(queue.id, buffer.id, offset, staging_buffer.buffer_id)
23262355
) {
23272356
Ok(()) => (),
2328-
Err(err) => self.handle_error_fatal(err, "Queue::write_buffer_with"),
2357+
Err(err) => {
2358+
self.handle_error_nolabel(&queue.error_sink, err, "Queue::write_buffer_with");
2359+
}
23292360
}
23302361
}
23312362

@@ -2339,14 +2370,14 @@ impl crate::Context for Context {
23392370
) {
23402371
let global = &self.0;
23412372
match wgc::gfx_select!(*queue => global.queue_write_texture(
2342-
*queue,
2373+
queue.id,
23432374
&map_texture_copy_view(texture),
23442375
data,
23452376
&data_layout,
23462377
&size
23472378
)) {
23482379
Ok(()) => (),
2349-
Err(err) => self.handle_error_fatal(err, "Queue::write_texture"),
2380+
Err(err) => self.handle_error_nolabel(&queue.error_sink, err, "Queue::write_texture"),
23502381
}
23512382
}
23522383

@@ -2358,7 +2389,7 @@ impl crate::Context for Context {
23582389
let temp_command_buffers = command_buffers.collect::<SmallVec<[_; 4]>>();
23592390

23602391
let global = &self.0;
2361-
match wgc::gfx_select!(*queue => global.queue_submit(*queue, &temp_command_buffers)) {
2392+
match wgc::gfx_select!(*queue => global.queue_submit(queue.id, &temp_command_buffers)) {
23622393
Ok(index) => index,
23632394
Err(err) => self.handle_error_fatal(err, "Queue::submit"),
23642395
}
@@ -2367,7 +2398,7 @@ impl crate::Context for Context {
23672398
fn queue_get_timestamp_period(&self, queue: &Self::QueueId) -> f32 {
23682399
let global = &self.0;
23692400
let res = wgc::gfx_select!(queue => global.queue_get_timestamp_period(
2370-
*queue
2401+
queue.id
23712402
));
23722403
match res {
23732404
Ok(v) => v,
@@ -2385,7 +2416,7 @@ impl crate::Context for Context {
23852416
let closure = wgc::device::queue::SubmittedWorkDoneClosure::from_rust(callback);
23862417

23872418
let global = &self.0;
2388-
let res = wgc::gfx_select!(queue => global.queue_on_submitted_work_done(*queue, closure));
2419+
let res = wgc::gfx_select!(queue => global.queue_on_submitted_work_done(queue.id, closure));
23892420
if let Err(cause) = res {
23902421
self.handle_error_fatal(cause, "Queue::on_submitted_work_done");
23912422
}

wgpu/tests/queue_transfer.rs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
//! Tests for buffer copy validation.
2+
3+
use std::num::NonZeroU32;
4+
5+
use crate::common::{fail, initialize_test, TestParameters};
6+
7+
#[test]
8+
fn queue_write_texture_overflow() {
9+
initialize_test(TestParameters::default(), |ctx| {
10+
let texture = ctx.device.create_texture(&wgpu::TextureDescriptor {
11+
label: None,
12+
size: wgpu::Extent3d {
13+
width: 146,
14+
height: 25,
15+
depth_or_array_layers: 192,
16+
},
17+
mip_level_count: 1,
18+
sample_count: 1,
19+
dimension: wgpu::TextureDimension::D2,
20+
format: wgpu::TextureFormat::Rgba32Float,
21+
usage: wgpu::TextureUsages::COPY_DST,
22+
});
23+
24+
let data = vec![255; 128];
25+
26+
fail(&ctx.device, || {
27+
ctx.queue.write_texture(
28+
wgpu::ImageCopyTexture {
29+
texture: &texture,
30+
mip_level: 0,
31+
origin: wgpu::Origin3d::ZERO,
32+
aspect: wgpu::TextureAspect::All,
33+
},
34+
&data,
35+
wgpu::ImageDataLayout {
36+
offset: 0,
37+
bytes_per_row: NonZeroU32::new(879161360),
38+
//bytes_per_image: 4294967295,
39+
rows_per_image: NonZeroU32::new(4294967295 / 879161360),
40+
},
41+
wgpu::Extent3d {
42+
width: 3056263286,
43+
height: 64,
44+
depth_or_array_layers: 1144576469,
45+
},
46+
);
47+
});
48+
});
49+
}

wgpu/tests/root.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ mod encoder;
99
mod example_wgsl;
1010
mod instance;
1111
mod poll;
12+
mod queue_transfer;
1213
mod resource_descriptor_accessor;
1314
mod resource_error;
1415
mod shader;

0 commit comments

Comments
 (0)