1#[cfg(not(feature = "use_os"))]
5use alloc::alloc::Layout;
6
7#[cfg(feature = "use_os")]
8use std::vec::Vec;
9
10#[cfg(all(feature = "serde", not(feature = "use_os")))]
12use alloc::vec::Vec;
13
14use super::{Error, SecureArray, alloc};
15use core::{
16 marker::PhantomData,
17 mem,
18 ops::{Bound, RangeBounds},
19 ptr::{self, NonNull},
20};
21use zeroize::{DefaultIsZeroes, Zeroize};
22
23#[cfg(feature = "use_os")]
24use super::free;
25#[cfg(feature = "use_os")]
26use memsec::Prot;
27
28pub type SecureBytes = SecureVec<u8>;
29
30pub(crate) struct UnlockGuard<'a, T: Zeroize> {
33 vec: &'a SecureVec<T>,
34}
35
36impl<'a, T: Zeroize> UnlockGuard<'a, T> {
37 pub(crate) fn new(vec: &'a SecureVec<T>) -> Self {
38 let ok = vec.unlock_memory();
39 debug_assert!(ok, "UnlockGuard::new: unlock_memory failed");
40
41 UnlockGuard { vec }
42 }
43}
44
45impl<'a, T: Zeroize> Drop for UnlockGuard<'a, T> {
46 fn drop(&mut self) {
47 let ok = self.vec.lock_memory();
48 assert!(ok, "UnlockGuard::drop: lock_memory failed");
51 }
52}
53
54pub struct SecureVec<T>
121where
122 T: Zeroize,
123{
124 ptr: NonNull<T>,
125 pub(crate) len: usize,
126 pub(crate) capacity: usize,
127 _marker: PhantomData<T>,
128}
129
130unsafe impl<T: Zeroize + Send> Send for SecureVec<T> {}
131
132impl<T: Zeroize> SecureVec<T> {
133 pub fn new() -> Result<Self, Error> {
135 let capacity = 1;
136 let size = capacity * mem::size_of::<T>();
137 let ptr = unsafe { alloc::<T>(size)? };
141
142 let secure = SecureVec {
143 ptr,
144 len: 0,
145 capacity,
146 _marker: PhantomData,
147 };
148
149 let _locked = secure.lock_memory();
150
151 #[cfg(feature = "use_os")]
152 if !_locked {
153 return Err(Error::LockFailed);
154 }
155
156 Ok(secure)
157 }
158
159 pub fn new_with_capacity(mut capacity: usize) -> Result<Self, Error> {
161 if capacity == 0 {
162 capacity = 1;
163 }
164
165 let size = capacity
166 .checked_mul(size_of::<T>())
167 .ok_or(Error::AllocationFailed)?;
168
169 let ptr = unsafe { alloc::<T>(size)? };
172
173 let secure = SecureVec {
174 ptr,
175 len: 0,
176 capacity,
177 _marker: PhantomData,
178 };
179
180 let _locked = secure.lock_memory();
181
182 #[cfg(feature = "use_os")]
183 if !_locked {
184 return Err(Error::LockFailed);
185 }
186
187 Ok(secure)
188 }
189
190 #[cfg(feature = "use_os")]
191 pub fn from_vec(mut vec: Vec<T>) -> Result<Self, Error> {
195 if vec.capacity() == 0 {
196 vec.reserve(1);
197 }
198
199 let capacity = vec.capacity();
200 let len = vec.len();
201
202 let size = match capacity.checked_mul(size_of::<T>()) {
203 Some(s) => s,
204 None => {
205 vec.zeroize();
206 return Err(Error::AllocationFailed);
207 }
208 };
209
210 let ptr = match unsafe { alloc::<T>(size) } {
214 Ok(ptr) => ptr,
215 Err(_) => {
216 vec.zeroize();
217 return Err(Error::AllocationFailed);
218 }
219 };
220
221 unsafe {
231 let src = vec.as_ptr();
232 let dst = ptr.as_ptr();
233 for i in 0..len {
234 let value = core::ptr::read(src.add(i));
235 core::ptr::write(dst.add(i), value);
236 }
237 }
238
239 let old_byte_size = capacity * mem::size_of::<T>();
247 unsafe {
250 vec.set_len(0);
251 }
252 if old_byte_size > 0 {
253 let bytes =
256 unsafe { core::slice::from_raw_parts_mut(vec.as_mut_ptr() as *mut u8, old_byte_size) };
257 bytes.zeroize();
258 }
259
260 let secure = SecureVec {
261 ptr,
262 len,
263 capacity,
264 _marker: PhantomData,
265 };
266
267 let locked = secure.lock_memory();
268
269 if !locked {
270 return Err(Error::LockFailed);
271 }
272
273 Ok(secure)
274 }
275
276 pub fn from_slice_mut(slice: &mut [T]) -> Result<Self, Error>
280 where
281 T: Clone + DefaultIsZeroes,
282 {
283 let mut secure_vec = match SecureVec::new_with_capacity(slice.len()) {
284 Ok(secure_vec) => secure_vec,
285 Err(e) => {
286 slice.zeroize();
287 return Err(e);
288 }
289 };
290
291 secure_vec.init_from_clone(slice);
292 slice.zeroize();
293
294 Ok(secure_vec)
295 }
296
297 pub fn from_slice(slice: &[T]) -> Result<Self, Error>
301 where
302 T: Clone,
303 {
304 let mut secure_vec = SecureVec::new_with_capacity(slice.len())?;
305 secure_vec.init_from_clone(slice);
306 Ok(secure_vec)
307 }
308
309 pub fn len(&self) -> usize {
310 self.len
311 }
312
313 pub fn capacity(&self) -> usize {
318 self.capacity
319 }
320
321 pub fn is_empty(&self) -> bool {
322 self.len() == 0
323 }
324
325 #[cfg(feature = "expose-ptr")]
333 #[deprecated(
334 since = "0.3.0",
335 note = "This method is intended only for testing/crash reproduction. Use one of the unlock methods instead."
336 )]
337 pub fn ptr(&self) -> NonNull<T> {
338 self.ptr
339 }
340
341 #[cfg(not(feature = "use_os"))]
343 pub(crate) fn allocated_byte_size(&self) -> usize {
344 self.capacity * mem::size_of::<T>()
345 }
346
347 pub(crate) fn as_mut_ptr(&mut self) -> *mut u8 {
348 self.ptr.as_ptr() as *mut u8
349 }
350
351 pub(crate) fn lock_memory(&self) -> bool {
352 #[cfg(feature = "use_os")]
353 {
354 #[cfg(windows)]
355 {
356 super::mprotect(self.ptr, Prot::NoAccess)
357 }
358 #[cfg(unix)]
359 {
360 super::mprotect(self.ptr, Prot::NoAccess)
361 }
362 }
363 #[cfg(not(feature = "use_os"))]
364 {
365 true }
367 }
368
369 pub(crate) fn unlock_memory(&self) -> bool {
370 #[cfg(feature = "use_os")]
371 {
372 #[cfg(windows)]
373 {
374 super::mprotect(self.ptr, Prot::ReadWrite)
375 }
376 #[cfg(unix)]
377 {
378 super::mprotect(self.ptr, Prot::ReadWrite)
379 }
380 }
381
382 #[cfg(not(feature = "use_os"))]
383 {
384 true }
386 }
387
388 pub fn unlock<F, R>(&self, f: F) -> R
397 where
398 F: FnOnce(&SecureVec<T>) -> R,
399 {
400 let _guard = UnlockGuard::new(self);
401 f(self)
402 }
403
404 pub fn unlock_slice<F, R>(&self, f: F) -> R
406 where
407 F: FnOnce(&[T]) -> R,
408 {
409 let _guard = UnlockGuard::new(self);
410 let slice = unsafe { core::slice::from_raw_parts(self.ptr.as_ptr(), self.len) };
414 f(slice)
415 }
416
417 pub fn unlock_slice_mut<F, R>(&mut self, f: F) -> R
419 where
420 F: FnOnce(&mut [T]) -> R,
421 {
422 unsafe {
425 let _guard = UnlockGuard::new(self);
426 let slice = core::slice::from_raw_parts_mut(self.ptr.as_ptr(), self.len);
427 f(slice)
428 }
429 }
430
431 pub fn unlock_iter<F, R>(&self, f: F) -> R
433 where
434 F: FnOnce(core::slice::Iter<T>) -> R,
435 {
436 unsafe {
439 let _guard = UnlockGuard::new(self);
440 let slice = core::slice::from_raw_parts(self.ptr.as_ptr(), self.len);
441 let iter = slice.iter();
442 f(iter)
443 }
444 }
445
446 pub fn unlock_iter_mut<F, R>(&mut self, f: F) -> R
448 where
449 F: FnOnce(core::slice::IterMut<T>) -> R,
450 {
451 unsafe {
454 let _guard = UnlockGuard::new(self);
455 let slice = core::slice::from_raw_parts_mut(self.ptr.as_ptr(), self.len);
456 let iter = slice.iter_mut();
457 f(iter)
458 }
459 }
460
461 pub fn erase(&mut self) {
465 {
466 let _guard = UnlockGuard::new(self);
467
468 unsafe {
472 let slice = core::slice::from_raw_parts_mut(self.ptr.as_ptr(), self.len);
473 for elem in slice.iter_mut() {
474 elem.zeroize();
475 }
476 }
477 }
478
479 self.clear();
480 }
481
482 pub fn clear(&mut self) {
486 self.len = 0;
487 }
488
489 pub fn push(&mut self, value: T) {
490 self.reserve(1);
491
492 let dst = self.ptr.as_ptr();
493 let write_at = self.len;
494
495 {
496 let _guard = UnlockGuard::new(self);
497
498 unsafe {
502 core::ptr::write(dst.add(write_at), value);
503 }
504 }
505
506 self.len = write_at + 1;
507 }
508
509 #[cfg(any(feature = "use_os", feature = "codec"))]
519 pub(crate) fn extend_from_slice(&mut self, src: &[T]) -> Result<(), Error>
520 where
521 T: Clone,
522 {
523 if src.is_empty() {
524 return Ok(());
525 }
526
527 self.try_reserve(src.len())?;
528
529 let write_at = self.len;
530 let dst = self.ptr.as_ptr();
531
532 {
533 let _guard = UnlockGuard::new(self);
534
535 unsafe {
539 for (i, item) in src.iter().enumerate() {
540 core::ptr::write(dst.add(write_at + i), item.clone());
541 }
542 }
543 }
544
545 self.len = write_at + src.len();
546 Ok(())
547 }
548
549 pub fn reserve(&mut self, additional: usize) {
557 self.try_reserve(additional).unwrap_or_else(|error| {
558 panic!(
559 "secure-types: SecureVec::reserve overflow or allocation failed ({error}); SecureVec left unchanged"
560 )
561 });
562 }
563
564 pub(crate) fn try_reserve(&mut self, additional: usize) -> Result<(), Error> {
567 let required_capacity = self
568 .len
569 .checked_add(additional)
570 .ok_or(Error::AllocationFailed)?;
571
572 if required_capacity <= self.capacity {
573 return Ok(());
574 }
575
576 let new_capacity = self
580 .capacity
581 .max(1)
582 .checked_mul(2)
583 .unwrap_or(required_capacity)
584 .max(required_capacity);
585
586 let new_size = new_capacity
587 .checked_mul(mem::size_of::<T>())
588 .ok_or(Error::AllocationFailed)?;
589
590 let new_ptr = unsafe { alloc::<T>(new_size)? };
593
594 unsafe {
601 let ok = self.unlock_memory();
602 debug_assert!(ok, "SecureVec::try_reserve: unlock_memory failed");
603
604 let len = self.len();
607 for i in 0..len {
608 let val = core::ptr::read(self.ptr.as_ptr().add(i));
609 core::ptr::write(new_ptr.as_ptr().add(i), val);
610 }
611
612 if self.capacity > 0 {
614 let old_bytes = self.capacity * mem::size_of::<T>();
615 let bytes = core::slice::from_raw_parts_mut(self.ptr.as_ptr() as *mut u8, old_bytes);
616 bytes.zeroize();
617 }
618
619 #[cfg(feature = "use_os")]
620 free(self.ptr);
621
622 #[cfg(not(feature = "use_os"))]
623 {
624 let old_size = self.capacity * mem::size_of::<T>();
625 let old_layout = Layout::from_size_align_unchecked(old_size, mem::align_of::<T>());
626 alloc::alloc::dealloc(self.ptr.as_ptr() as *mut u8, old_layout);
627 }
628 }
629
630 self.ptr = new_ptr;
632 self.capacity = new_capacity;
633 let ok = self.lock_memory();
634 assert!(ok, "SecureVec::try_reserve: lock_memory failed");
635 Ok(())
636 }
637
638 pub fn drain<R>(&mut self, range: R) -> Drain<'_, T>
649 where
650 R: RangeBounds<usize>,
651 {
652 let original_len = self.len;
653
654 let (drain_start_idx, drain_end_idx) = resolve_range_indices(range, original_len);
655
656 let tail_len = original_len - drain_end_idx;
657
658 self.len = drain_start_idx;
659
660 Drain {
661 vec_ref: self,
662 drain_start_index: drain_start_idx,
663 current_drain_iter_index: drain_start_idx,
664 drain_end_index: drain_end_idx,
665 original_vec_len: original_len,
666 tail_len,
667 _marker: PhantomData,
668 }
669 }
670
671 pub(crate) fn init_from_clone(&mut self, src: &[T])
678 where
679 T: Clone,
680 {
681 debug_assert!(src.len() <= self.capacity);
682
683 {
684 let _guard = UnlockGuard::new(self);
685
686 unsafe {
691 let dst = self.ptr.as_ptr();
692 for (i, item) in src.iter().enumerate() {
693 core::ptr::write(dst.add(i), item.clone());
694 }
695 }
696 }
697
698 self.len = src.len();
699 }
700}
701
702impl SecureVec<u8> {
703 #[cfg(feature = "codec")]
719 pub(crate) fn patch_at(&mut self, offset: usize, src: &[u8]) {
720 let end = offset
721 .checked_add(src.len())
722 .expect("SecureVec::patch_at: offset overflow");
723 assert!(
724 end <= self.len,
725 "SecureVec::patch_at: range {offset}..{end} exceeds length {}",
726 self.len
727 );
728
729 {
734 let _guard = UnlockGuard::new(self);
735
736 unsafe {
737 core::ptr::copy_nonoverlapping(
738 src.as_ptr(),
739 self.ptr.as_ptr().add(offset),
740 src.len(),
741 );
742 }
743 }
744 }
745}
746
747impl<T: Clone + Zeroize> Clone for SecureVec<T> {
748 fn clone(&self) -> Self {
752 let mut new_vec = SecureVec::new_with_capacity(self.capacity).unwrap();
753 self.unlock_slice(|src_slice| {
754 new_vec.init_from_clone(src_slice);
755 });
756 new_vec
757 }
758}
759
760impl<T: Clone + Zeroize, const LENGTH: usize> From<SecureArray<T, LENGTH>> for SecureVec<T> {
761 fn from(array: SecureArray<T, LENGTH>) -> Self {
765 let mut new_vec = SecureVec::new_with_capacity(LENGTH)
766 .expect("Failed to allocate SecureVec during conversion");
767 array.unlock(|array_slice| {
768 new_vec.init_from_clone(array_slice);
769 });
770 new_vec
771 }
772}
773
774impl<T: Zeroize> Drop for SecureVec<T> {
775 fn drop(&mut self) {
776 unsafe {
780 let ok = self.unlock_memory();
781 debug_assert!(ok, "SecureVec::drop: unlock_memory failed");
782
783 let slice = core::slice::from_raw_parts_mut(self.ptr.as_ptr(), self.len);
784 for elem in slice.iter_mut() {
785 elem.zeroize();
786 }
787 }
788
789 #[cfg(feature = "use_os")]
790 free(self.ptr);
791
792 #[cfg(not(feature = "use_os"))]
793 unsafe {
798 let byte_size = self.allocated_byte_size();
799 let bytes = core::slice::from_raw_parts_mut(self.ptr.as_ptr() as *mut u8, byte_size);
800 bytes.zeroize();
801
802 let layout = Layout::from_size_align_unchecked(byte_size, mem::align_of::<T>());
803 alloc::alloc::dealloc(self.ptr.as_ptr() as *mut u8, layout);
804 }
805 }
806}
807
808#[cfg(feature = "serde")]
821const MAX_PREALLOCATION_FROM_SIZE_HINT: usize = 4096;
822
823#[cfg(feature = "serde")]
828impl serde::Serialize for SecureVec<u8> {
829 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
830 where
831 S: serde::Serializer,
832 {
833 self.unlock_slice(|slice| serializer.serialize_bytes(slice))
834 }
835}
836
837#[cfg(feature = "serde")]
838impl<'de> serde::Deserialize<'de> for SecureVec<u8> {
839 fn deserialize<D>(deserializer: D) -> Result<SecureVec<u8>, D::Error>
840 where
841 D: serde::Deserializer<'de>,
842 {
843 struct SecureVecVisitor;
844 impl<'de> serde::de::Visitor<'de> for SecureVecVisitor {
845 type Value = SecureVec<u8>;
846
847 fn expecting(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
848 write!(formatter, "a sequence or a byte buffer")
849 }
850
851 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
852 where
853 A: serde::de::SeqAccess<'de>,
854 {
855 let capacity = seq
860 .size_hint()
861 .unwrap_or(0)
862 .min(MAX_PREALLOCATION_FROM_SIZE_HINT);
863 let mut vec =
864 SecureVec::new_with_capacity(capacity).map_err(serde::de::Error::custom)?;
865
866 while let Some(byte) = seq.next_element::<u8>()? {
867 vec.push(byte);
868 }
869
870 Ok(vec)
871 }
872
873 fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
876 where
877 E: serde::de::Error,
878 {
879 SecureVec::from_slice(v).map_err(serde::de::Error::custom)
880 }
881
882 fn visit_byte_buf<E>(self, mut v: Vec<u8>) -> Result<Self::Value, E>
885 where
886 E: serde::de::Error,
887 {
888 let vec = self.visit_bytes(&v);
889 v.zeroize();
890 vec
891 }
892 }
893
894 deserializer.deserialize_bytes(SecureVecVisitor)
895 }
896}
897
898#[cfg(feature = "serde")]
910pub trait SeqElement: Zeroize {}
911
912#[cfg(feature = "serde")]
913impl SeqElement for bool {}
914
915#[cfg(feature = "serde")]
916impl SeqElement for char {}
917
918#[cfg(feature = "serde")]
919impl SeqElement for f32 {}
920
921#[cfg(feature = "serde")]
922impl SeqElement for f64 {}
923
924#[cfg(feature = "serde")]
925impl SeqElement for i8 {}
926
927#[cfg(feature = "serde")]
928impl SeqElement for i16 {}
929
930#[cfg(feature = "serde")]
931impl SeqElement for i32 {}
932
933#[cfg(feature = "serde")]
934impl SeqElement for i64 {}
935
936#[cfg(feature = "serde")]
937impl SeqElement for i128 {}
938
939#[cfg(feature = "serde")]
940impl SeqElement for u16 {}
941
942#[cfg(feature = "serde")]
943impl SeqElement for u32 {}
944
945#[cfg(feature = "serde")]
946impl SeqElement for u64 {}
947
948#[cfg(feature = "serde")]
949impl SeqElement for u128 {}
950
951#[cfg(feature = "serde")]
956impl<T> serde::Serialize for SecureVec<T>
957where
958 T: SeqElement + serde::Serialize,
959{
960 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
961 where
962 S: serde::Serializer,
963 {
964 use serde::ser::SerializeSeq;
965
966 let mut seq = serializer.serialize_seq(Some(self.len()))?;
967
968 let elements: Result<(), S::Error> = self.unlock_slice(|slice| {
972 for item in slice {
973 seq.serialize_element(item)?;
974 }
975
976 Ok(())
977 });
978 elements?;
979
980 seq.end()
981 }
982}
983
984#[cfg(feature = "serde")]
986impl<'de, T> serde::Deserialize<'de> for SecureVec<T>
987where
988 T: SeqElement + serde::Deserialize<'de>,
989{
990 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
991 where
992 D: serde::Deserializer<'de>,
993 {
994 struct SecureSeqVisitor<T>(PhantomData<T>);
995
996 impl<'de, T> serde::de::Visitor<'de> for SecureSeqVisitor<T>
997 where
998 T: SeqElement + serde::Deserialize<'de>,
999 {
1000 type Value = SecureVec<T>;
1001
1002 fn expecting(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
1003 write!(formatter, "a sequence of secure elements")
1004 }
1005
1006 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
1007 where
1008 A: serde::de::SeqAccess<'de>,
1009 {
1010 let capacity = seq
1013 .size_hint()
1014 .unwrap_or(0)
1015 .min(MAX_PREALLOCATION_FROM_SIZE_HINT);
1016 let mut vec =
1017 SecureVec::new_with_capacity(capacity).map_err(serde::de::Error::custom)?;
1018
1019 while let Some(item) = seq.next_element::<T>()? {
1020 vec.push(item);
1021 }
1022
1023 Ok(vec)
1024 }
1025 }
1026
1027 deserializer.deserialize_seq(SecureSeqVisitor::<T>(PhantomData))
1028 }
1029}
1030
1031pub struct Drain<'a, T: Zeroize + 'a> {
1042 vec_ref: &'a mut SecureVec<T>,
1043 drain_start_index: usize,
1044 current_drain_iter_index: usize,
1045 drain_end_index: usize,
1046
1047 original_vec_len: usize, tail_len: usize, _marker: PhantomData<&'a T>,
1051}
1052
1053impl<'a, T: Zeroize> Iterator for Drain<'a, T> {
1054 type Item = T;
1055
1056 fn next(&mut self) -> Option<T> {
1057 if self.current_drain_iter_index >= self.drain_end_index {
1058 return None;
1059 }
1060
1061 let base = self.vec_ref.ptr.as_ptr();
1064
1065 let _guard = UnlockGuard::new(&*self.vec_ref);
1068
1069 let item = unsafe { ptr::read(base.add(self.current_drain_iter_index)) };
1074 self.current_drain_iter_index += 1;
1075
1076 Some(item)
1077 }
1078
1079 fn size_hint(&self) -> (usize, Option<usize>) {
1080 let remaining = self.drain_end_index - self.current_drain_iter_index;
1081 (remaining, Some(remaining))
1082 }
1083}
1084
1085impl<'a, T: Zeroize> ExactSizeIterator for Drain<'a, T> {}
1086
1087impl<'a, T: Zeroize> Drain<'a, T> {
1088 fn compact(&self) -> usize {
1094 let base = self.vec_ref.ptr.as_ptr();
1097
1098 let _guard = UnlockGuard::new(&*self.vec_ref);
1099
1100 unsafe {
1106 if mem::needs_drop::<T>() {
1110 let mut current_ptr = base.add(self.current_drain_iter_index);
1111 let end_ptr = base.add(self.drain_end_index);
1112 while current_ptr < end_ptr {
1113 ptr::drop_in_place(current_ptr);
1114 current_ptr = current_ptr.add(1);
1115 }
1116 }
1117
1118 let hole_dst_ptr = base.add(self.drain_start_index);
1119 let tail_src_ptr = base.add(self.drain_end_index);
1120
1121 if self.tail_len > 0 {
1122 ptr::copy(tail_src_ptr, hole_dst_ptr, self.tail_len);
1123 }
1124
1125 let new_len = self.drain_start_index + self.tail_len;
1126
1127 let leftover_elems = self.original_vec_len.saturating_sub(new_len);
1132 let leftover_bytes = leftover_elems.saturating_mul(mem::size_of::<T>());
1133 if leftover_bytes > 0 {
1134 let bytes =
1135 core::slice::from_raw_parts_mut(base.add(new_len) as *mut u8, leftover_bytes);
1136 bytes.zeroize();
1137 }
1138
1139 new_len
1140 }
1141 }
1142}
1143
1144impl<'a, T: Zeroize> Drop for Drain<'a, T> {
1145 fn drop(&mut self) {
1146 let new_len = self.compact();
1147
1148 self.vec_ref.len = new_len;
1150 }
1151}
1152
1153fn resolve_range_indices<R: RangeBounds<usize>>(range: R, len: usize) -> (usize, usize) {
1155 let start_bound = range.start_bound();
1156 let end_bound = range.end_bound();
1157
1158 let start = match start_bound {
1159 Bound::Included(&s) => s,
1160 Bound::Excluded(&s) => s
1161 .checked_add(1)
1162 .unwrap_or_else(|| panic!("attempted to start drain at Excluded(usize::MAX)")),
1163 Bound::Unbounded => 0,
1164 };
1165
1166 let end = match end_bound {
1167 Bound::Included(&e) => e
1168 .checked_add(1)
1169 .unwrap_or_else(|| panic!("attempted to end drain at Included(usize::MAX)")),
1170 Bound::Excluded(&e) => e,
1171 Bound::Unbounded => len,
1172 };
1173
1174 if start > end {
1175 panic!(
1176 "drain range start ({}) must be less than or equal to end ({})",
1177 start, end
1178 );
1179 }
1180 if end > len {
1181 panic!(
1182 "drain range end ({}) out of bounds for slice of length {}",
1183 end, len
1184 );
1185 }
1186
1187 (start, end)
1188}
1189
1190#[cfg(test)]
1191mod tests {
1192 #[cfg(any(feature = "use_os", feature = "codec"))]
1196 use super::*;
1197
1198 #[cfg(feature = "use_os")]
1199 use std::process::{Command, Stdio};
1200
1201 #[cfg(feature = "use_os")]
1202 #[test]
1203 fn lock_unlock_works() {
1204 let secure: SecureVec<u8> = SecureVec::new().unwrap();
1205
1206 let unlocked = secure.unlock_memory();
1207 assert!(unlocked);
1208
1209 let locked = secure.lock_memory();
1210 assert!(locked);
1211 }
1212
1213 #[cfg(feature = "codec")]
1214 #[test]
1215 fn test_patch_at_overwrites_in_place() {
1216 let mut secure = SecureBytes::from_slice(b"abcdefgh").unwrap();
1217
1218 secure.patch_at(2, b"XY");
1219
1220 secure.unlock_slice(|bytes| {
1221 assert_eq!(bytes, b"abXYefgh");
1222 assert_eq!(bytes.len(), 8);
1223 });
1224 }
1225
1226 #[cfg(feature = "codec")]
1227 #[test]
1228 fn test_patch_at_last_bytes_and_whole_buffer() {
1229 let mut secure = SecureBytes::from_slice(b"abcdefgh").unwrap();
1230
1231 secure.patch_at(6, b"XY");
1232 secure.unlock_slice(|bytes| assert_eq!(bytes, b"abcdefXY"));
1233
1234 secure.patch_at(0, b"12345678");
1235 secure.unlock_slice(|bytes| assert_eq!(bytes, b"12345678"));
1236 }
1237
1238 #[cfg(feature = "codec")]
1239 #[test]
1240 fn test_patch_at_empty_source_is_a_noop() {
1241 let mut secure = SecureBytes::from_slice(b"abc").unwrap();
1242
1243 secure.patch_at(0, b"");
1245 secure.patch_at(3, b"");
1246
1247 secure.unlock_slice(|bytes| assert_eq!(bytes, b"abc"));
1248 }
1249
1250 #[cfg(feature = "use_os")]
1251 #[test]
1252 fn test_erase_zeroizes_initialized_slots() {
1253 let mut secure = SecureVec::from_slice(&[1u8, 2, 3]).unwrap();
1254 let capacity = secure.capacity;
1255 secure.erase();
1256 assert_eq!(secure.len, 0);
1257 assert_eq!(secure.capacity, capacity);
1258
1259 let ok = secure.unlock_memory();
1260 assert!(ok);
1261 unsafe {
1264 let slice = core::slice::from_raw_parts(secure.ptr.as_ptr(), 3);
1265 assert_eq!(slice, &[0, 0, 0]);
1266 }
1267 let ok = secure.lock_memory();
1268 assert!(ok);
1269 }
1270
1271 #[cfg(feature = "codec")]
1272 #[test]
1273 fn test_patch_at_leaves_length_and_capacity_alone() {
1274 let mut secure = SecureBytes::new_with_capacity(16).unwrap();
1275 secure.extend_from_slice(b"abc").unwrap();
1276 let capacity_before = secure.unlock(|vec| vec.capacity);
1277
1278 secure.patch_at(0, b"ZY");
1279
1280 secure.unlock(|vec| {
1281 assert_eq!(vec.len, 3);
1282 assert_eq!(vec.capacity, capacity_before);
1283 });
1284 secure.unlock_slice(|bytes| assert_eq!(bytes, b"ZYc"));
1285 }
1286
1287 #[cfg(feature = "codec")]
1288 #[test]
1289 fn test_patch_at_survives_reallocation() {
1290 let mut secure = SecureBytes::new().unwrap();
1293 secure.extend_from_slice(b"first").unwrap();
1294 secure.reserve(4096);
1295 secure.extend_from_slice(b"second").unwrap();
1296
1297 secure.patch_at(0, b"FIRST");
1298
1299 secure.unlock_slice(|bytes| assert_eq!(bytes, b"FIRSTsecond"));
1300 }
1301
1302 #[cfg(feature = "codec")]
1303 #[test]
1304 #[should_panic(expected = "exceeds length")]
1305 fn test_patch_at_straddling_the_end_panics() {
1306 let mut secure = SecureBytes::from_slice(b"abc").unwrap();
1307
1308 secure.patch_at(2, b"XY");
1309 }
1310
1311 #[cfg(feature = "codec")]
1312 #[test]
1313 #[should_panic(expected = "exceeds length")]
1314 fn test_patch_at_past_the_end_panics() {
1315 let mut secure = SecureBytes::from_slice(b"abc").unwrap();
1316
1317 secure.patch_at(4, b"");
1318 }
1319
1320 #[cfg(feature = "use_os")]
1321 #[test]
1322 fn test_forgotten_drain_keeps_memory_locked() {
1323 let arg = "CRASH_TEST_DRAIN_FORGET_LOCKED";
1324
1325 if std::env::args().any(|a| a == arg) {
1326 let vec: Vec<u8> = vec![1, 2, 3, 4, 5];
1327 let mut secure = SecureVec::from_vec(vec).unwrap();
1328 let drain = secure.drain(..3);
1329 core::mem::forget(drain);
1330
1331 let _value = unsafe { core::hint::black_box(*secure.ptr.as_ptr()) };
1335
1336 std::process::exit(1);
1337 }
1338
1339 let child = Command::new(std::env::current_exe().unwrap())
1340 .arg("vec::tests::test_forgotten_drain_keeps_memory_locked")
1341 .arg(arg)
1342 .arg("--nocapture")
1343 .stdout(Stdio::piped())
1344 .stderr(Stdio::piped())
1345 .spawn()
1346 .expect("Failed to spawn child process");
1347
1348 let output = child.wait_with_output().expect("Failed to wait on child");
1349 let status = output.status;
1350
1351 assert!(
1352 !status.success(),
1353 "Process exited successfully with code {:?}, but it should have crashed.",
1354 status.code()
1355 );
1356
1357 #[cfg(unix)]
1358 {
1359 use std::os::unix::process::ExitStatusExt;
1360 let signal = status
1361 .signal()
1362 .expect("Process was not terminated by a signal on Unix.");
1363 assert!(
1364 signal == libc::SIGSEGV || signal == libc::SIGBUS,
1365 "Process terminated with unexpected signal: {}",
1366 signal
1367 );
1368 println!(
1369 "Test passed: Process correctly terminated with signal {}.",
1370 signal
1371 );
1372 }
1373
1374 #[cfg(windows)]
1375 {
1376 const STATUS_ACCESS_VIOLATION: i32 = 0xC0000005_u32 as i32;
1377 assert_eq!(
1378 status.code(),
1379 Some(STATUS_ACCESS_VIOLATION),
1380 "Process exited with unexpected code: {:x?}.",
1381 status.code()
1382 );
1383 }
1384 }
1385
1386 #[cfg(feature = "use_os")]
1387 #[test]
1388 fn test_index_should_fail_when_locked() {
1389 let arg = "CRASH_TEST_SECUREVEC_LOCKED";
1390
1391 if std::env::args().any(|a| a == arg) {
1392 let vec: Vec<u8> = vec![1, 2, 3];
1393 let secure = SecureVec::from_vec(vec).unwrap();
1394 let _value = unsafe { core::hint::black_box(*secure.ptr.as_ptr()) };
1398
1399 std::process::exit(1);
1400 }
1401
1402 let child = Command::new(std::env::current_exe().unwrap())
1403 .arg("vec::tests::test_index_should_fail_when_locked")
1404 .arg(arg)
1405 .arg("--nocapture")
1406 .stdout(Stdio::piped())
1407 .stderr(Stdio::piped())
1408 .spawn()
1409 .expect("Failed to spawn child process");
1410
1411 let output = child.wait_with_output().expect("Failed to wait on child");
1412 let status = output.status;
1413
1414 assert!(
1415 !status.success(),
1416 "Process exited successfully with code {:?}, but it should have crashed.",
1417 status.code()
1418 );
1419
1420 #[cfg(unix)]
1421 {
1422 use std::os::unix::process::ExitStatusExt;
1423 let signal = status
1424 .signal()
1425 .expect("Process was not terminated by a signal on Unix.");
1426 assert!(
1427 signal == libc::SIGSEGV || signal == libc::SIGBUS,
1428 "Process terminated with unexpected signal: {}",
1429 signal
1430 );
1431 println!(
1432 "Test passed: Process correctly terminated with signal {}.",
1433 signal
1434 );
1435 }
1436
1437 #[cfg(windows)]
1438 {
1439 const STATUS_ACCESS_VIOLATION: i32 = 0xC0000005_u32 as i32;
1440 assert_eq!(
1441 status.code(),
1442 Some(STATUS_ACCESS_VIOLATION),
1443 "Process exited with unexpected code: {:x?}. Expected STATUS_ACCESS_VIOLATION.",
1444 status.code()
1445 );
1446 eprintln!("Test passed: Process correctly terminated with STATUS_ACCESS_VIOLATION.");
1447 }
1448 }
1449}