@@ -10,6 +10,7 @@ use wgt::{
1010
1111use crate :: {
1212 api_log,
13+ buffer_region_overrun:: BufferRegionOverrunError ,
1314 command:: {
1415 clear_texture, encoder:: EncodingState , ArcCommand , CommandEncoderError , EncoderStateError ,
1516 } ,
@@ -47,24 +48,8 @@ pub enum TransferError {
4748 MissingBufferUsage ( #[ from] MissingBufferUsageError ) ,
4849 #[ error( transparent) ]
4950 MissingTextureUsage ( #[ from] MissingTextureUsageError ) ,
50- #[ error( "Start offset ({offset}) is out-of-bounds for buffer of size {buffer_size}" ) ]
51- BufferStartOffsetOverrun {
52- offset : BufferAddress ,
53- buffer_size : BufferAddress ,
54- side : CopySide ,
55- } ,
56- #[ error(
57- "End offset (start at {} + size of {}) is out-of-bounds for buffer of size {}" ,
58- offset,
59- size,
60- buffer_size
61- ) ]
62- BufferEndOffsetOverrun {
63- offset : BufferAddress ,
64- size : BufferAddress ,
65- buffer_size : BufferAddress ,
66- side : CopySide ,
67- } ,
51+ #[ error( "Transfer {_0}" ) ]
52+ BufferOverrun ( BufferRegionOverrunError ) ,
6853 #[ error( "Copy of {dimension:?} {start_offset}..{end_offset} would end up overrunning the bounds of the {side:?} texture of {dimension:?} size {texture_size}" ) ]
6954 TextureOverrun {
7055 start_offset : u32 ,
@@ -192,9 +177,8 @@ impl WebGpuError for TransferError {
192177 Self :: MissingTextureUsage ( e) => e,
193178 Self :: MemoryInitFailure ( e) => e,
194179
195- Self :: BufferEndOffsetOverrun { .. }
180+ Self :: BufferOverrun { .. }
196181 | Self :: TextureOverrun { .. }
197- | Self :: BufferStartOffsetOverrun { .. }
198182 | Self :: UnsupportedPartialTransfer { .. }
199183 | Self :: InvalidCopyWithinSameTexture { .. }
200184 | Self :: InvalidTextureAspect { .. }
@@ -352,22 +336,9 @@ pub(crate) fn validate_linear_texture_data(
352336 return Err ( TransferError :: UnspecifiedRowsPerImage ) ;
353337 } ;
354338
355- if offset > buffer_size {
356- return Err ( TransferError :: BufferStartOffsetOverrun {
357- start_offset : offset,
358- buffer_size,
359- side : buffer_side,
360- } ) ;
361- }
362- // NOTE: Should never underflow because of our earlier check.
363- if bytes_in_copy > buffer_size - offset {
364- return Err ( TransferError :: BufferEndOffsetOverrun {
365- offset,
366- size : bytes_in_copy,
367- buffer_size,
368- side : buffer_side,
369- } ) ;
370- }
339+ // Avoid underflow in the subtraction by checking bytes_in_copy against buffer_size first.
340+ let _ = BufferRegionOverrunError :: check ( offset, bytes_in_copy, buffer_size)
341+ . map_err ( |e| e. to_transfer_error ( buffer_side) ) ?;
371342
372343 let is_contiguous = ( row_stride_bytes == row_bytes_dense || !requires_multiple_rows)
373344 && ( image_stride_bytes == image_bytes_dense || !requires_multiple_images) ;
@@ -1000,14 +971,10 @@ pub(super) fn copy_buffer_to_buffer(
1000971 . map_err ( TransferError :: MissingBufferUsage ) ?;
1001972 let dst_barrier = dst_pending. map ( |pending| pending. into_hal ( dst_buffer, state. snatch_guard ) ) ;
1002973
1003- if source_offset > src_buffer. size {
1004- return Err ( TransferError :: BufferStartOffsetOverrun {
1005- offset : source_offset,
1006- buffer_size : src_buffer. size ,
1007- side : CopySide :: Source ,
1008- }
1009- . into ( ) ) ;
1010- }
974+ let src_end_offset_checker =
975+ BufferRegionOverrunError :: check_start ( source_offset, src_buffer. size )
976+ . map_err ( |e| e. to_transfer_error ( CopySide :: Source ) ) ?;
977+
1011978 let size = size. unwrap_or_else ( || {
1012979 // NOTE: Should never underflow because of our earlier check.
1013980 src_buffer. size - source_offset
@@ -1044,38 +1011,13 @@ pub(super) fn copy_buffer_to_buffer(
10441011 }
10451012 }
10461013
1047- if size > src_buffer. size - source_offset {
1048- return Err ( TransferError :: BufferEndOffsetOverrun {
1049- offset : source_offset,
1050- size,
1051- buffer_size : src_buffer. size ,
1052- side : CopySide :: Source ,
1053- }
1054- . into ( ) ) ;
1055- }
1056- // NOTE: Should never overflow because of our earlier check.
1057- let source_end_offset = source_offset + size;
1058-
1059- if destination_offset > dst_buffer. size {
1060- return Err ( TransferError :: BufferStartOffsetOverrun {
1061- offset : destination_offset,
1062- buffer_size : dst_buffer. size ,
1063- side : CopySide :: Destination ,
1064- }
1065- . into ( ) ) ;
1066- }
1067- // NOTE: Should never underflow because of our earlier check.
1068- if size > dst_buffer. size - destination_offset {
1069- return Err ( TransferError :: BufferEndOffsetOverrun {
1070- offset : destination_offset,
1071- size,
1072- buffer_size : dst_buffer. size ,
1073- side : CopySide :: Destination ,
1074- }
1075- . into ( ) ) ;
1076- }
1077- // NOTE: Should never overflow because of our earlier check.
1078- let destination_end_offset = destination_offset + size;
1014+ let source_end_offset = src_end_offset_checker
1015+ . check_end ( size)
1016+ . map_err ( |e| e. to_transfer_error ( CopySide :: Source ) ) ?;
1017+
1018+ let destination_end_offset =
1019+ BufferRegionOverrunError :: check ( destination_offset, size, dst_buffer. size )
1020+ . map_err ( |e| e. to_transfer_error ( CopySide :: Destination ) ) ?;
10791021
10801022 // This must happen after parameter validation (so that errors are reported
10811023 // as required by the spec), but before any side effects.
0 commit comments