@@ -170,11 +170,19 @@ impl Buffer {
170170 /// Example
171171 /// ```rust,ignore
172172 /// let transforms: Vec<InstanceTransform> = compute_transforms();
173- /// instance_buffer.write_slice(render_context.gpu(), 0, &transforms);
173+ /// instance_buffer
174+ /// .write_slice(render_context.gpu(), 0, &transforms)
175+ /// .unwrap();
174176 /// ```
175- pub fn write_slice < T : Copy > ( & self , gpu : & Gpu , offset : u64 , data : & [ T ] ) {
176- let bytes = slice_as_bytes ( data) ;
177+ pub fn write_slice < T : Copy > (
178+ & self ,
179+ gpu : & Gpu ,
180+ offset : u64 ,
181+ data : & [ T ] ,
182+ ) -> Result < ( ) , & ' static str > {
183+ let bytes = slice_as_bytes ( data) ?;
177184 self . write_bytes ( gpu, offset, bytes) ;
185+ return Ok ( ( ) ) ;
178186 }
179187}
180188
@@ -188,21 +196,23 @@ fn value_as_bytes<T: Copy>(data: &T) -> &[u8] {
188196 return bytes;
189197}
190198
191- fn slice_as_bytes < T : Copy > ( data : & [ T ] ) -> & [ u8 ] {
192- let element_size = std:: mem:: size_of :: < T > ( ) ;
193- let Some ( byte_len) = element_size. checked_mul ( data. len ( ) ) else {
194- debug_assert ! (
195- false ,
196- "Buffer::write_slice byte length overflow: element_size={}, len={}" ,
197- element_size,
198- data. len( )
199- ) ;
200- return & [ ] ;
199+ fn checked_byte_len (
200+ element_size : usize ,
201+ element_count : usize ,
202+ ) -> Result < usize , & ' static str > {
203+ let Some ( byte_len) = element_size. checked_mul ( element_count) else {
204+ return Err ( "Buffer byte length overflow." ) ;
201205 } ;
206+ return Ok ( byte_len) ;
207+ }
208+
209+ fn slice_as_bytes < T : Copy > ( data : & [ T ] ) -> Result < & [ u8 ] , & ' static str > {
210+ let element_size = std:: mem:: size_of :: < T > ( ) ;
211+ let byte_len = checked_byte_len ( element_size, data. len ( ) ) ?;
202212
203213 let bytes =
204214 unsafe { std:: slice:: from_raw_parts ( data. as_ptr ( ) as * const u8 , byte_len) } ;
205- return bytes;
215+ return Ok ( bytes) ;
206216}
207217
208218/// Strongly‑typed uniform buffer wrapper for ergonomics and safety.
@@ -398,7 +408,7 @@ impl BufferBuilder {
398408 data_len : usize ,
399409 ) -> Result < usize , & ' static str > {
400410 let buffer_length = if self . buffer_length == 0 {
401- element_size * data_len
411+ checked_byte_len ( element_size, data_len) ?
402412 } else {
403413 self . buffer_length
404414 } ;
@@ -428,6 +438,13 @@ mod tests {
428438 assert_eq ! ( builder. label. as_deref( ) , Some ( "buffer-test" ) ) ;
429439 }
430440
441+ #[ test]
442+ fn resolve_length_rejects_overflow ( ) {
443+ let builder = BufferBuilder :: new ( ) ;
444+ let result = builder. resolve_length ( usize:: MAX , 2 ) ;
445+ assert ! ( result. is_err( ) ) ;
446+ }
447+
431448 #[ test]
432449 fn value_as_bytes_matches_native_bytes ( ) {
433450 let value: u32 = 0x1122_3344 ;
@@ -442,12 +459,18 @@ mod tests {
442459 for value in values {
443460 expected. extend_from_slice ( & value. to_ne_bytes ( ) ) ;
444461 }
445- assert_eq ! ( slice_as_bytes( & values) , expected. as_slice( ) ) ;
462+ assert_eq ! ( slice_as_bytes( & values) . unwrap ( ) , expected. as_slice( ) ) ;
446463 }
447464
448465 #[ test]
449466 fn slice_as_bytes_empty_is_empty ( ) {
450467 let values: [ u32 ; 0 ] = [ ] ;
451- assert_eq ! ( slice_as_bytes( & values) , & [ ] ) ;
468+ assert_eq ! ( slice_as_bytes( & values) . unwrap( ) , & [ ] ) ;
469+ }
470+
471+ #[ test]
472+ fn checked_byte_len_rejects_overflow ( ) {
473+ let result = checked_byte_len ( usize:: MAX , 2 ) ;
474+ assert ! ( result. is_err( ) ) ;
452475 }
453476}
0 commit comments