Mercurial > crates > nonstick
comparison libpam-sys/libpam-sys-helpers/src/memory.rs @ 139:33b9622ed6d2
Remove redundant memory management in nonstick::libpam; fix UB.
- Uses the libpam-sys-helpers BinaryPayload / OwnedBinaryPayload structs
to handle memory management and parsing for Linux-PAM binary messages.
- Gets rid of the (technically) undefined behavior in PtrPtrVec
due to pointer provenance.
- Don't check for malloc failing. It won't, even if it does.
- Formatting/cleanups/etc.
author | Paul Fisher <paul@pfish.zone> |
---|---|
date | Thu, 03 Jul 2025 23:57:49 -0400 |
parents | efbc235f01d3 |
children | add7228adb2f |
comparison
equal
deleted
inserted
replaced
138:999bf07efbcb | 139:33b9622ed6d2 |
---|---|
1 //! Helpers to deal with annoying memory management in the PAM API. | 1 //! Helpers to deal with annoying memory management in the PAM API. |
2 //! | |
3 //! | |
4 | 2 |
5 use std::error::Error; | 3 use std::error::Error; |
6 use std::marker::{PhantomData, PhantomPinned}; | 4 use std::marker::{PhantomData, PhantomPinned}; |
7 use std::mem::ManuallyDrop; | 5 use std::mem::ManuallyDrop; |
8 use std::ptr::NonNull; | 6 use std::ptr::NonNull; |
9 use std::{any, fmt, mem, slice}; | 7 use std::{any, fmt, mem, ptr, slice}; |
10 | 8 |
11 /// A pointer-to-pointer-to-message container for PAM's conversation callback. | 9 /// A pointer-to-pointer-to-message container for PAM's conversation callback. |
12 /// | 10 /// |
13 /// The PAM conversation callback requires a pointer to a pointer of | 11 /// The PAM conversation callback requires a pointer to a pointer of |
14 /// `pam_message`s. Linux-PAM handles this differently than all other | 12 /// `pam_message`s. Linux-PAM handles this differently than all other |
71 unsafe impl<T> Sync for PtrPtrVec<T> where Vec<T>: Sync {} | 69 unsafe impl<T> Sync for PtrPtrVec<T> where Vec<T>: Sync {} |
72 | 70 |
73 impl<T> PtrPtrVec<T> { | 71 impl<T> PtrPtrVec<T> { |
74 /// Takes ownership of the given Vec and creates a vec of pointers to it. | 72 /// Takes ownership of the given Vec and creates a vec of pointers to it. |
75 pub fn new(data: Vec<T>) -> Self { | 73 pub fn new(data: Vec<T>) -> Self { |
76 let pointers: Vec<_> = data.iter().map(|r| r as *const T).collect(); | 74 let start = data.as_ptr(); |
75 // We do this slightly tricky little dance to satisfy Miri: | |
76 // | |
77 // A pointer extracted from a reference can only legally access | |
78 // that reference's memory. This means that if we say: | |
79 // pointers[0] = &data[0] as *const T; | |
80 // we can't traverse through pointers[0] to reach data[1], | |
81 // we can only use pointers[1]. | |
82 // | |
83 // However, if we use the start-of-vec pointer from the `data` vector, | |
84 // its "provenance"* is valid for the entire array (even if the address | |
85 // of the pointer is the same). This avoids some behavior which is | |
86 // technically undefined. While the CPU sees no difference between | |
87 // those two pointers, the compiler is allowed to make optimizations | |
88 // based on that provenance (even if, in this case, it isn't likely | |
89 // to do so). | |
90 // | |
91 // data.as_ptr() points here, and is valid for the whole Vec. | |
92 // ┃ | |
93 // ┠─────────────────╮ | |
94 // ┌─────┬─────┬─────┐ | |
95 // data │ [0] │ [1] │ [2] │ | |
96 // └─────┴─────┴─────┘ | |
97 // ┠─────╯ ┊ | |
98 // ┃ ┊ ┊ | |
99 // (&data[0] as *const T) points to the same place, but is valid | |
100 // only for that 0th element. | |
101 // ┊ ┊ | |
102 // ┠─────╯ | |
103 // ┃ | |
104 // (&data[1] as *const T) points here, and is only valid | |
105 // for that element. | |
106 // | |
107 // We only have to do this for pointers[0] because only that pointer | |
108 // is used for accessing elements other than data[0] (in XSSO). | |
109 // | |
110 // * "provenance" is kind of like if every pointer in your program | |
111 // remembered where it came from and, based on that, it had an implied | |
112 // memory range it was valid for, separate from its address. | |
113 // https://doc.rust-lang.org/std/ptr/#provenance | |
114 // (It took a long time for me to understand this.) | |
115 let mut pointers = Vec::with_capacity(data.len()); | |
116 // Ensure the 0th pointer has provenance from the entire vec | |
117 // (even though it's numerically identical to &data[0] as *const T). | |
118 pointers.push(start); | |
119 // The 1st and everything thereafter only need to have the provenance | |
120 // of their own memory. | |
121 pointers.extend(data[1..].iter().map(|r| r as *const T)); | |
77 Self { data, pointers } | 122 Self { data, pointers } |
78 } | 123 } |
79 | 124 |
80 /// Gives you back your Vec. | 125 /// Gives you back your Vec. |
81 pub fn into_inner(self) -> Vec<T> { | 126 pub fn into_inner(self) -> Vec<T> { |
192 /// This is intended to allow you to bring your own allocator for | 237 /// This is intended to allow you to bring your own allocator for |
193 /// [`OwnedBinaryPayload`]s. | 238 /// [`OwnedBinaryPayload`]s. |
194 /// | 239 /// |
195 /// For an implementation example, see the implementation of this trait | 240 /// For an implementation example, see the implementation of this trait |
196 /// for [`Vec`]. | 241 /// for [`Vec`]. |
197 pub trait Buffer<T: Default> { | 242 pub trait Buffer { |
198 /// Allocates a buffer of `len` elements, filled with the default. | 243 /// Allocates a buffer of `len` elements, filled with the default. |
199 fn allocate(len: usize) -> Self; | 244 fn allocate(len: usize) -> Self; |
200 | 245 |
201 fn as_ptr(&self) -> *const T; | 246 fn as_ptr(this: &Self) -> *const u8; |
202 | 247 |
203 /// Returns a slice view of `size` elements of the given memory. | 248 /// Returns a slice view of `size` elements of the given memory. |
204 /// | 249 /// |
205 /// # Safety | 250 /// # Safety |
206 /// | 251 /// |
207 /// The caller must not request more elements than are allocated. | 252 /// The caller must not request more elements than are allocated. |
208 unsafe fn as_mut_slice(&mut self, len: usize) -> &mut [T]; | 253 unsafe fn as_mut_slice(this: &mut Self, len: usize) -> &mut [u8]; |
209 | 254 |
210 /// Consumes this ownership and returns a pointer to the start of the arena. | 255 /// Consumes this ownership and returns a pointer to the start of the arena. |
211 fn into_ptr(self) -> NonNull<T>; | 256 fn into_ptr(this: Self) -> NonNull<u8>; |
212 | 257 |
213 /// "Adopts" the memory at the given pointer, taking it under management. | 258 /// "Adopts" the memory at the given pointer, taking it under management. |
214 /// | 259 /// |
215 /// Running the operation: | 260 /// Running the operation: |
216 /// | 261 /// |
217 /// ``` | 262 /// ``` |
218 /// # use libpam_sys_helpers::memory::Buffer; | 263 /// # use libpam_sys_helpers::memory::Buffer; |
219 /// # fn test<T: Default, OwnerType: Buffer<T>>(bytes: usize) { | 264 /// # fn test<T: Default, OwnerType: Buffer>(bytes: usize) { |
220 /// let owner = OwnerType::allocate(bytes); | 265 /// let owner = OwnerType::allocate(bytes); |
221 /// let ptr = owner.into_ptr(); | 266 /// let ptr = OwnerType::into_ptr(owner); |
222 /// let owner = unsafe { OwnerType::from_ptr(ptr, bytes) }; | 267 /// let owner = unsafe { OwnerType::from_ptr(ptr, bytes) }; |
223 /// # } | 268 /// # } |
224 /// ``` | 269 /// ``` |
225 /// | 270 /// |
226 /// must be a no-op. | 271 /// must be a no-op. |
227 /// | 272 /// |
228 /// # Safety | 273 /// # Safety |
229 /// | 274 /// |
230 /// The pointer must be valid, and the caller must provide the exact size | 275 /// The pointer must be valid, and the caller must provide the exact size |
231 /// of the given arena. | 276 /// of the given arena. |
232 unsafe fn from_ptr(ptr: NonNull<T>, bytes: usize) -> Self; | 277 unsafe fn from_ptr(ptr: NonNull<u8>, bytes: usize) -> Self; |
233 } | 278 } |
234 | 279 |
235 impl<T: Default> Buffer<T> for Vec<T> { | 280 impl Buffer for Vec<u8> { |
236 fn allocate(bytes: usize) -> Self { | 281 fn allocate(bytes: usize) -> Self { |
237 (0..bytes).map(|_| Default::default()).collect() | 282 vec![0; bytes] |
238 } | 283 } |
239 | 284 |
240 fn as_ptr(&self) -> *const T { | 285 fn as_ptr(this: &Self) -> *const u8 { |
241 Vec::as_ptr(self) | 286 Vec::as_ptr(this) |
242 } | 287 } |
243 | 288 |
244 unsafe fn as_mut_slice(&mut self, bytes: usize) -> &mut [T] { | 289 unsafe fn as_mut_slice(this: &mut Self, bytes: usize) -> &mut [u8] { |
245 debug_assert!(bytes <= self.len()); | 290 &mut this[..bytes] |
246 Vec::as_mut(self) | 291 } |
247 } | 292 |
248 | 293 fn into_ptr(this: Self) -> NonNull<u8> { |
249 fn into_ptr(self) -> NonNull<T> { | 294 let mut me = ManuallyDrop::new(this); |
250 let mut me = ManuallyDrop::new(self); | |
251 // SAFETY: a Vec is guaranteed to have a nonzero pointer. | 295 // SAFETY: a Vec is guaranteed to have a nonzero pointer. |
252 unsafe { NonNull::new_unchecked(me.as_mut_ptr()) } | 296 unsafe { NonNull::new_unchecked(me.as_mut_ptr()) } |
253 } | 297 } |
254 | 298 |
255 unsafe fn from_ptr(ptr: NonNull<T>, bytes: usize) -> Self { | 299 unsafe fn from_ptr(ptr: NonNull<u8>, bytes: usize) -> Self { |
256 Vec::from_raw_parts(ptr.as_ptr(), bytes, bytes) | 300 Vec::from_raw_parts(ptr.as_ptr(), bytes, bytes) |
257 } | 301 } |
258 } | 302 } |
259 | 303 |
260 /// The structure of the "binary message" payload for the `PAM_BINARY_PROMPT` | 304 /// The structure of the "binary message" payload for the `PAM_BINARY_PROMPT` |
279 /// Fills in the provided buffer with the given data. | 323 /// Fills in the provided buffer with the given data. |
280 /// | 324 /// |
281 /// This uses [`copy_from_slice`](slice::copy_from_slice) internally, | 325 /// This uses [`copy_from_slice`](slice::copy_from_slice) internally, |
282 /// so `buf` must be exactly 5 bytes longer than `data`, or this function | 326 /// so `buf` must be exactly 5 bytes longer than `data`, or this function |
283 /// will panic. | 327 /// will panic. |
284 pub fn fill(buf: &mut [u8], data_type: u8, data: &[u8]) { | 328 pub fn fill(buf: &mut [u8], data: &[u8], data_type: u8) { |
285 let ptr: *mut Self = buf.as_mut_ptr().cast(); | 329 let ptr: *mut Self = buf.as_mut_ptr().cast(); |
286 // SAFETY: We're given a slice, which always has a nonzero pointer. | 330 // SAFETY: We're given a slice, which always has a nonzero pointer. |
287 let me = unsafe { ptr.as_mut().unwrap_unchecked() }; | 331 let me = unsafe { ptr.as_mut().unwrap_unchecked() }; |
288 me.total_bytes_u32be = u32::to_be_bytes(buf.len() as u32); | 332 me.total_bytes_u32be = u32::to_be_bytes(buf.len() as u32); |
289 me.data_type = data_type; | 333 me.data_type = data_type; |
290 buf[5..].copy_from_slice(data) | 334 buf[5..].copy_from_slice(data) |
291 } | 335 } |
292 | 336 |
293 /// The total storage needed for the message, including header. | 337 /// The total storage needed for the message, including header. |
294 pub fn total_bytes(&self) -> usize { | 338 pub unsafe fn total_bytes(this: *const Self) -> usize { |
295 u32::from_be_bytes(self.total_bytes_u32be) as usize | 339 let header = this.as_ref().unwrap_unchecked(); |
340 u32::from_be_bytes(header.total_bytes_u32be) as usize | |
296 } | 341 } |
297 | 342 |
298 /// Gets the total byte buffer of the BinaryMessage stored at the pointer. | 343 /// Gets the total byte buffer of the BinaryMessage stored at the pointer. |
299 /// | 344 /// |
300 /// The returned data slice is borrowed from where the pointer points to. | 345 /// The returned data slice is borrowed from where the pointer points to. |
302 /// # Safety | 347 /// # Safety |
303 /// | 348 /// |
304 /// - The pointer must point to a valid `BinaryPayload`. | 349 /// - The pointer must point to a valid `BinaryPayload`. |
305 /// - The borrowed data must not outlive the pointer's validity. | 350 /// - The borrowed data must not outlive the pointer's validity. |
306 pub unsafe fn buffer_of<'a>(ptr: *const Self) -> &'a [u8] { | 351 pub unsafe fn buffer_of<'a>(ptr: *const Self) -> &'a [u8] { |
307 let header: &Self = ptr.as_ref().unwrap_unchecked(); | 352 slice::from_raw_parts(ptr.cast(), Self::total_bytes(ptr).max(5)) |
308 slice::from_raw_parts(ptr.cast(), header.total_bytes().max(5)) | |
309 } | 353 } |
310 | 354 |
311 /// Gets the contents of the BinaryMessage stored at the given pointer. | 355 /// Gets the contents of the BinaryMessage stored at the given pointer. |
312 /// | 356 /// |
313 /// The returned data slice is borrowed from where the pointer points to. | 357 /// The returned data slice is borrowed from where the pointer points to. |
320 /// | 364 /// |
321 /// # Safety | 365 /// # Safety |
322 /// | 366 /// |
323 /// - The pointer must point to a valid `BinaryPayload`. | 367 /// - The pointer must point to a valid `BinaryPayload`. |
324 /// - The borrowed data must not outlive the pointer's validity. | 368 /// - The borrowed data must not outlive the pointer's validity. |
325 pub unsafe fn contents<'a>(ptr: *const Self) -> (u8, &'a [u8]) { | 369 pub unsafe fn contents<'a>(ptr: *const Self) -> (&'a [u8], u8) { |
326 let header: &Self = ptr.as_ref().unwrap_unchecked(); | 370 let header: &Self = ptr.as_ref().unwrap_unchecked(); |
327 (header.data_type, &Self::buffer_of(ptr)[5..]) | 371 (&Self::buffer_of(ptr)[5..], header.data_type) |
372 } | |
373 | |
374 /// Zeroes out the data of this payload. | |
375 /// | |
376 /// # Safety | |
377 /// | |
378 /// - The pointer must point to a valid `BinaryPayload`. | |
379 /// - The binary payload must not be used in the future, | |
380 /// since its length metadata is gone and so its buffer is unknown. | |
381 pub unsafe fn zero(ptr: *mut Self) { | |
382 let size = Self::total_bytes(ptr); | |
383 let ptr: *mut u8 = ptr.cast(); | |
384 for x in 0..size { | |
385 ptr::write_volatile(ptr.byte_add(x), mem::zeroed()) | |
386 } | |
328 } | 387 } |
329 } | 388 } |
330 | 389 |
331 /// A binary message owned by some storage. | 390 /// A binary message owned by some storage. |
332 /// | 391 /// |
333 /// This is an owned, memory-managed version of [`BinaryPayload`]. | 392 /// This is an owned, memory-managed version of [`BinaryPayload`]. |
334 /// The `O` type manages the memory where the payload lives. | 393 /// The `O` type manages the memory where the payload lives. |
335 /// [`Vec<u8>`] is one such manager and can be used when ownership | 394 /// [`Vec<u8>`] is one such manager and can be used when ownership |
336 /// of the data does not need to transit through PAM. | 395 /// of the data does not need to transit through PAM. |
337 #[derive(Debug)] | 396 #[derive(Debug)] |
338 pub struct OwnedBinaryPayload<Owner: Buffer<u8>>(Owner); | 397 pub struct OwnedBinaryPayload<Owner: Buffer>(Owner); |
339 | 398 |
340 impl<O: Buffer<u8>> OwnedBinaryPayload<O> { | 399 impl<O: Buffer> OwnedBinaryPayload<O> { |
341 /// Allocates a new OwnedBinaryPayload. | 400 /// Allocates a new OwnedBinaryPayload. |
342 /// | 401 /// |
343 /// This will return a [`TooBigError`] if you try to allocate too much | 402 /// This will return a [`TooBigError`] if you try to allocate too much |
344 /// (more than [`BinaryPayload::MAX_SIZE`]). | 403 /// (more than [`BinaryPayload::MAX_SIZE`]). |
345 pub fn new(data_type: u8, data: &[u8]) -> Result<Self, TooBigError> { | 404 pub fn new(data: &[u8], type_: u8) -> Result<Self, TooBigError> { |
346 let total_len: u32 = (data.len() + 5).try_into().map_err(|_| TooBigError { | 405 let total_len: u32 = (data.len() + 5).try_into().map_err(|_| TooBigError { |
347 size: data.len(), | 406 size: data.len(), |
348 max: BinaryPayload::MAX_SIZE, | 407 max: BinaryPayload::MAX_SIZE, |
349 })?; | 408 })?; |
350 let total_len = total_len as usize; | 409 let total_len = total_len as usize; |
351 let mut buf = O::allocate(total_len); | 410 let mut buf = O::allocate(total_len); |
352 // SAFETY: We just allocated this exact size. | 411 // SAFETY: We just allocated this exact size. |
353 BinaryPayload::fill(unsafe { buf.as_mut_slice(total_len) }, data_type, data); | 412 BinaryPayload::fill( |
413 unsafe { Buffer::as_mut_slice(&mut buf, total_len) }, | |
414 data, | |
415 type_, | |
416 ); | |
354 Ok(Self(buf)) | 417 Ok(Self(buf)) |
355 } | 418 } |
356 | 419 |
357 /// The contents of the buffer. | 420 /// The contents of the buffer. |
358 pub fn contents(&self) -> (u8, &[u8]) { | 421 pub fn contents(&self) -> (&[u8], u8) { |
359 unsafe { BinaryPayload::contents(self.as_ptr()) } | 422 unsafe { BinaryPayload::contents(self.as_ptr()) } |
360 } | 423 } |
361 | 424 |
362 /// The total bytes needed to store this, including the header. | 425 /// The total bytes needed to store this, including the header. |
363 pub fn total_bytes(&self) -> usize { | 426 pub fn total_bytes(&self) -> usize { |
364 unsafe { BinaryPayload::buffer_of(self.0.as_ptr().cast()).len() } | 427 unsafe { BinaryPayload::buffer_of(Buffer::as_ptr(&self.0).cast()).len() } |
365 } | 428 } |
366 | 429 |
367 /// Unwraps this into the raw storage backing it. | 430 /// Unwraps this into the raw storage backing it. |
368 pub fn into_inner(self) -> O { | 431 pub fn into_inner(self) -> O { |
369 self.0 | 432 self.0 |
370 } | 433 } |
371 | 434 |
372 /// Gets a const pointer to the start of the message's buffer. | 435 /// Gets a const pointer to the start of the message's buffer. |
373 pub fn as_ptr(&self) -> *const BinaryPayload { | 436 pub fn as_ptr(&self) -> *const BinaryPayload { |
374 self.0.as_ptr().cast() | 437 Buffer::as_ptr(&self.0).cast() |
375 } | 438 } |
376 | 439 |
377 /// Consumes ownership of this message and converts it to a raw pointer | 440 /// Consumes ownership of this message and converts it to a raw pointer |
378 /// to the start of the message. | 441 /// to the start of the message. |
379 /// | 442 /// |
380 /// To clean this up, you should eventually pass it into [`Self::from_ptr`] | 443 /// To clean this up, you should eventually pass it into [`Self::from_ptr`] |
381 /// with the same `O` ownership type. | 444 /// with the same `O` ownership type. |
382 pub fn into_ptr(self) -> NonNull<BinaryPayload> { | 445 pub fn into_ptr(self) -> NonNull<BinaryPayload> { |
383 self.0.into_ptr().cast() | 446 Buffer::into_ptr(self.0).cast() |
384 } | 447 } |
385 | 448 |
386 /// Takes ownership of the given pointer. | 449 /// Takes ownership of the given pointer. |
387 /// | 450 /// |
388 /// # Safety | 451 /// # Safety |
389 /// | 452 /// |
390 /// You must provide a valid pointer, allocated by (or equivalent to one | 453 /// You must provide a valid pointer, allocated by (or equivalent to one |
391 /// allocated by) [`Self::new`]. For instance, passing a pointer allocated | 454 /// allocated by) [`Self::new`]. For instance, passing a pointer allocated |
392 /// by `malloc` to `OwnedBinaryPayload::<Vec<u8>>::from_ptr` is not allowed. | 455 /// by `malloc` to `OwnedBinaryPayload::<Vec<u8>>::from_ptr` is not allowed. |
393 pub unsafe fn from_ptr(ptr: NonNull<BinaryPayload>) -> Self { | 456 pub unsafe fn from_ptr(ptr: NonNull<BinaryPayload>) -> Self { |
394 Self(O::from_ptr(ptr.cast(), ptr.as_ref().total_bytes())) | 457 Self(O::from_ptr(ptr.cast(), BinaryPayload::total_bytes(ptr.as_ptr()))) |
395 } | 458 } |
396 } | 459 } |
397 | 460 |
398 #[cfg(test)] | 461 #[cfg(test)] |
399 mod tests { | 462 mod tests { |
405 #[test] | 468 #[test] |
406 fn test_binary_payload() { | 469 fn test_binary_payload() { |
407 let simple_message = &[0u8, 0, 0, 16, 0xff, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; | 470 let simple_message = &[0u8, 0, 0, 16, 0xff, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; |
408 let empty = &[0u8; 5]; | 471 let empty = &[0u8; 5]; |
409 | 472 |
410 assert_eq!((0xff, &[0u8, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10][..]), unsafe { | 473 assert_eq!((&[0u8, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10][..], 0xff), unsafe { |
411 BinaryPayload::contents(simple_message.as_ptr().cast()) | 474 BinaryPayload::contents(simple_message.as_ptr().cast()) |
412 }); | 475 }); |
413 assert_eq!((0x00, &[][..]), unsafe { | 476 assert_eq!((&[][..], 0x00), unsafe { |
414 BinaryPayload::contents(empty.as_ptr().cast()) | 477 BinaryPayload::contents(empty.as_ptr().cast()) |
415 }); | 478 }); |
416 } | 479 } |
417 | 480 |
418 #[test] | 481 #[test] |
419 fn test_owned_binary_payload() { | 482 fn test_owned_binary_payload() { |
420 let (typ, data) = ( | 483 let (data, typ) = ( |
484 &[0, 1, 1, 8, 9, 9, 9, 8, 8, 1, 9, 9, 9, 1, 1, 9, 7, 2, 5, 3][..], | |
421 112, | 485 112, |
422 &[0, 1, 1, 8, 9, 9, 9, 8, 8, 1, 9, 9, 9, 1, 1, 9, 7, 2, 5, 3][..], | |
423 ); | 486 ); |
424 let payload = VecPayload::new(typ, data).unwrap(); | 487 let payload = VecPayload::new(data, typ).unwrap(); |
425 assert_eq!((typ, data), payload.contents()); | 488 assert_eq!((data, typ), payload.contents()); |
426 let ptr = payload.into_ptr(); | 489 let ptr = payload.into_ptr(); |
427 let payload = unsafe { VecPayload::from_ptr(ptr) }; | 490 let payload = unsafe { VecPayload::from_ptr(ptr) }; |
428 assert_eq!((typ, data), payload.contents()); | 491 assert_eq!((data, typ), payload.contents()); |
429 } | 492 } |
430 | 493 |
431 #[test] | 494 #[test] |
432 #[ignore] | 495 #[ignore] |
433 fn test_owned_too_big() { | 496 fn test_owned_too_big() { |
435 assert_eq!( | 498 assert_eq!( |
436 TooBigError { | 499 TooBigError { |
437 max: 0xffff_fffa, | 500 max: 0xffff_fffa, |
438 size: 0x1_0000_0001 | 501 size: 0x1_0000_0001 |
439 }, | 502 }, |
440 VecPayload::new(5, &data).unwrap_err() | 503 VecPayload::new(&data, 5).unwrap_err() |
441 ) | 504 ) |
442 } | 505 } |
443 | 506 |
444 #[cfg(debug_assertions)] | 507 #[cfg(debug_assertions)] |
445 #[test] | 508 #[test] |