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] |
