-
-
Notifications
You must be signed in to change notification settings - Fork 277
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add a feature to disable extra debug info (#595) #596
Conversation
This allows - More optimization (smallest final binary size) - No internal code structure leak (no enum name leak).
So if I do: fn main() {
let bytes = bincode::encode_to_vec(Foo::Bar, bincode::config::standard()).map_err(|_| ()).unwrap();
println!("{bytes:?}");
}
#[derive(bincode::Encode, bincode::Decode)]
enum Foo {
Bar
} And I run cargo build --release
strip target/release/test_proj
strings target/release/test_proj I cannot find any instance of If you get rid of all |
The code in question is in the fn main() {
let bytes = bincode::encode_to_vec(Foo::Bar, bincode::config::standard()).map_err(|_| ()).unwrap();
println!("{bytes:?}");
let (_, _): (Foo, _) = bincode::decode_from_slice(&bytes, bincode::config::standard()).unwrap();
}
#[derive(bincode::Encode, bincode::Decode)]
enum Foo {
Bar
} Which gives ( $ cargo build --release
$ strip errors-and-strings
$ strings errors-and-strings | grep "Foo"
Foolibrary/alloc/src/raw_vec.rscapacity overflowlibrary/alloc/src/ffi/c_str.rs You can also check that with the #![feature(prelude_import)]
#[prelude_import]
use std::prelude::rust_2021::*;
#[macro_use]
extern crate std;
fn main() {
let bytes = bincode::encode_to_vec(Foo::Bar, bincode::config::standard())
.map_err(|_| ())
.unwrap();
{
::std::io::_print(
::core::fmt::Arguments::new_v1(
&["", "\n"],
&[::core::fmt::ArgumentV1::new_debug(&bytes)],
),
);
};
let (_, _): (Foo, _) = bincode::decode_from_slice(
&bytes,
bincode::config::standard(),
)
.unwrap();
}
enum Foo {
Bar,
}
impl ::bincode::Encode for Foo {
fn encode<__E: ::bincode::enc::Encoder>(
&self,
encoder: &mut __E,
) -> core::result::Result<(), ::bincode::error::EncodeError> {
match self {
Self::Bar => {
<u32 as ::bincode::Encode>::encode(&(0u32), encoder)?;
Ok(())
}
}
}
}
impl ::bincode::Decode for Foo {
fn decode<__D: ::bincode::de::Decoder>(
decoder: &mut __D,
) -> core::result::Result<Self, ::bincode::error::DecodeError> {
let variant_index = <u32 as ::bincode::Decode>::decode(decoder)?;
match variant_index {
0u32 => Ok(Self::Bar {}),
variant => {
Err(::bincode::error::DecodeError::UnexpectedVariant {
found: variant,
type_name: "Foo",
allowed: &::bincode::error::AllowedEnumVariants::Range {
min: 0,
max: 0,
},
})
}
}
}
}
impl<'__de> ::bincode::BorrowDecode<'__de> for Foo {
fn borrow_decode<__D: ::bincode::de::BorrowDecoder<'__de>>(
decoder: &mut __D,
) -> core::result::Result<Self, ::bincode::error::DecodeError> {
let variant_index = <u32 as ::bincode::Decode>::decode(decoder)?;
match variant_index {
0u32 => Ok(Self::Bar {}),
variant => {
Err(::bincode::error::DecodeError::UnexpectedVariant {
found: variant,
type_name: "Foo",
allowed: &::bincode::error::AllowedEnumVariants::Range {
min: 0,
max: 0,
},
})
}
}
}
} In the same idea, your debug file in impl :: bincode :: Decode for Foo
{
fn decode < __D : :: bincode :: de :: Decoder > (decoder : & mut __D) ->
core :: result :: Result < Self, :: bincode :: error :: DecodeError >
{
let variant_index = < u32 as :: bincode :: Decode > :: decode(decoder)
? ; match variant_index
{
0u32 => Ok(Self :: Bar {}), variant =>
Err(:: bincode :: error :: DecodeError :: UnexpectedVariant
{
found : variant, type_name : "Foo", allowed : & :: bincode ::
error :: AllowedEnumVariants :: Range { min : 0, max : 0 }
})
}
}
} impl < '__de > :: bincode :: BorrowDecode < '__de > for Foo
{
fn borrow_decode < __D : :: bincode :: de :: BorrowDecoder < '__de > >
(decoder : & mut __D) -> core :: result :: Result < Self, :: bincode ::
error :: DecodeError >
{
let variant_index = < u32 as :: bincode :: Decode > :: decode(decoder)
? ; match variant_index
{
0u32 => Ok(Self :: Bar {}), variant =>
Err(:: bincode :: error :: DecodeError :: UnexpectedVariant
{
found : variant, type_name : "Foo", allowed : & :: bincode ::
error :: AllowedEnumVariants :: Range { min : 0, max : 0 }
})
}
}
} |
Can you try this? |
Thanks for the suggestion. I tried this but unfortunately the strings are still here, even if I get rid of the |
I think this is pretty common to deal with in your high-security domain? Surely enabling LTO is the very first thing you do in a new project. Can I recommend using cargo-vendor to get a local copy of all the dependencies you're using? I'd imagine you want to audit every single one of them and apply minor patches to make all your dependencies suitable for your usecase. For bincode you might even want to consider removing all error variants you do not care about. I'm going to close this and wait for the outcome of the discussion in #595 |
The issue is in bincode_derive crate, where we are adding extra debug info that are leaking enum names in the final binary (which imply less optimization with a bigger binary size, and internal structure leak). I think we should use a proper feature flag to disable this. This is linked to #595.
It seems there is only one leak in the code in this part of the code. I agree this debug line can be important, but should be optional for release build if required. A feature flag could be used to address that situation, and maybe it is useful for other cases like in #594.
This allows