Skip to content

Commit

Permalink
rslice: add Debug impl for rustls_str (rustls#240)
Browse files Browse the repository at this point in the history
This makes it easier to troubleshoot the contents of one of these
strings.

Fixes rustls#239.
  • Loading branch information
kevinburke authored Nov 18, 2021
1 parent 7bb5c5d commit d7a8692
Showing 1 changed file with 47 additions and 0 deletions.
47 changes: 47 additions & 0 deletions src/rslice.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
use libc::{c_char, size_t};
use std::fmt;
use std::marker::PhantomData;
use std::slice;
use std::str;
use std::{
convert::{TryFrom, TryInto},
ptr::null,
Expand Down Expand Up @@ -163,6 +166,10 @@ impl<'a> TryFrom<&'a str> for rustls_str<'a> {
}
}

/// rustls_str represents a string that can be passed to C code. The string
/// should not have any internal null bytes and is not null terminated. C code
/// should not create rustls_str objects, they should only be created in Rust
/// code.
impl<'a> rustls_str<'a> {
pub fn from_str_unchecked(s: &'static str) -> rustls_str<'static> {
rustls_str {
Expand All @@ -173,6 +180,30 @@ impl<'a> rustls_str<'a> {
}
}

// If the assertion about Rust code being the only creator of rustls_str objects
// changes, you must change this Debug impl, since the assertion in it no longer
// holds.
impl<'a> fmt::Debug for rustls_str<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let raw = unsafe {
// Despite the use of "unsafe", we know that this is safe because:
// - self.data is a u8, and single bytes are aligned
// - the entire memory range is a single allocated object, because
// we always build rustls_str objects from a slice (though this may
// change if we accept rustls_str objects from C code)
// - all values are properly initialized because we only init
// rustls_str objects inside of Rust code
// - not larger than isize::MAX because, again, it's coming from Rust
slice::from_raw_parts(self.data as *const u8, self.len as usize)
};
let s = str::from_utf8(raw).unwrap_or("%!(ERROR)");
f.debug_struct("rustls_str")
.field("data", &s)
.field("len", &self.len)
.finish()
}
}

#[test]
fn test_rustls_str() {
let s = "abcd";
Expand All @@ -184,6 +215,22 @@ fn test_rustls_str() {
}
}

#[cfg(test)]
mod tests {
use crate::rslice::*;
use std::convert::TryInto;

#[test]
fn test_rustls_str_debug() {
let s = "abcd";
let rs: rustls_str = s.try_into().unwrap();
assert_eq!(
format!("{:?}", rs),
r#"rustls_str { data: "abcd", len: 4 }"#
);
}
}

#[test]
fn test_rustls_str_rejects_nul() {
assert!(matches!(rustls_str::try_from("\0"), Err(NulByte {})));
Expand Down

0 comments on commit d7a8692

Please sign in to comment.