@@ -22,6 +22,48 @@ pub enum ProfileError {
2222 Other ( Cow < ' static , CStr > ) ,
2323}
2424
25+ impl ProfileError {
26+ /// Creates a ProfileError by formatting a Display-able error.
27+ pub fn from_display < E : fmt:: Display > ( err : E ) -> Self {
28+ use core:: fmt:: Write ;
29+
30+ let mut writer = FallibleStringWriter :: new ( ) ;
31+ if write ! ( writer, "{err}" ) . is_err ( ) {
32+ return ProfileError :: AllocError ;
33+ }
34+
35+ let mut string = String :: from ( writer) ;
36+
37+ // Check for interior null bytes using memchr
38+ let pos = unsafe { libc:: memchr ( string. as_ptr ( ) . cast ( ) , 0 , string. len ( ) ) } ;
39+ if !pos. is_null ( ) {
40+ return ProfileError :: from (
41+ c"encountered an interior null byte while formatting an error message" ,
42+ ) ;
43+ }
44+
45+ // Reserve memory for the null terminator. We have to shrink later in
46+ // order to turn it into a CString, so we don't want any excess capacity.
47+ if string. try_reserve_exact ( 1 ) . is_err ( ) {
48+ return ProfileError :: AllocError ;
49+ }
50+ string. push ( '\0' ) ;
51+
52+ // Shrink to avoid potential panic in CString::from_vec_unchecked
53+ if string_try_shrink_to_fit ( & mut string) . is_err ( ) {
54+ return ProfileError :: AllocError ;
55+ }
56+
57+ // Pop the null off because CString::from_vec_unchecked adds one.
58+ _ = string. pop ( ) ;
59+
60+ // SAFETY: We checked for interior null bytes with memchr above,
61+ // and the string is valid UTF-8 because it came from formatting.
62+ let cstring = unsafe { CString :: from_vec_unchecked ( string. into_bytes ( ) ) } ;
63+ ProfileError :: Other ( Cow :: Owned ( cstring) )
64+ }
65+ }
66+
2567/// Represents an error that means the handle is empty, meaning it doesn't
2668/// point to a resource.
2769#[ derive( Copy , Clone , PartialEq , Eq , Debug ) ]
@@ -132,26 +174,7 @@ impl From<std::io::Error> for ProfileError {
132174 match err. kind ( ) {
133175 ErrorKind :: StorageFull => ProfileError :: CapacityOverflow ,
134176 ErrorKind :: WriteZero | ErrorKind :: OutOfMemory => ProfileError :: AllocError ,
135- e => {
136- let mut writer = FallibleStringWriter :: new ( ) ;
137- use core:: fmt:: Write ;
138- // Add null terminator that from_vec_with_nul expects.
139- if write ! ( & mut writer, "{e}\0 " ) . is_err ( ) {
140- return ProfileError :: from (
141- c"memory allocation failed while trying to create an error message" ,
142- ) ;
143- }
144- let mut string = String :: from ( writer) ;
145- // We do this to avoid the potential panic case of failed
146- // allocation in CString::from_vec_with_nul.
147- if string_try_shrink_to_fit ( & mut string) . is_err ( ) {
148- return ProfileError :: from ( c"memory allocation failed while trying to shrink a vec to create an error message" ) ;
149- }
150- match CString :: from_vec_with_nul ( string. into_bytes ( ) ) {
151- Ok ( cstring) => ProfileError :: Other ( Cow :: Owned ( cstring) ) ,
152- Err ( _) => ProfileError :: from ( c"encountered an interior null byte while converting a std::io::Error into a ProfileError" )
153- }
154- }
177+ e => ProfileError :: from_display ( e) ,
155178 }
156179 }
157180}
0 commit comments