How would I override the default Debug implementation?

Hello,

How would you go about disabling or overriding the default #[derive(Debug)] implementation in release builds for a crate, as well as all its dependencies (including libstd and crates.io crates)?

I haven't tried it, but perhaps something like:

#[cfg_attr(not(feature = "release"), derive(Debug))]
struct MySpecialType { /* ... */ }

#[cfg(feature = "release")]
impl fmt::Debug for MySpecialType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Nothing to see here...")
    }
}

I don't know any way to do this at such a deep level, sorry. Generally speaking, Rust has strong coherence opinions about the One True Owner of a given trait/type/etc., so replacing Debug or its derivation would be out of line. Besides, even if you did hack out derive(Debug), wouldn't you also care about others' manual impl Debug?

I'm curious where do you expect the Debug impls to be visible to your end users? I can think of only one place (maybe I've forgotten something?) – I guess they could show up on some unwraps, but you can catch panics and choose to not print the unwrap messages. The Debug impls will still be somewhere in the binary though. But are the layouts of std structs really secret (assuming you hide the Debug of your custom structs)?

@krdln he's more worried about them being in the binary; he doesn't want cheat programs to be able to reliably where certain data structures are what there structure is. As-is, a cheat program could search the compiled game for known strings from Debug implementations, search for pointers to them, and use that to find where various data structures are in memory (and their layout).

Personally, I'd patch rustc itself to create a special "release" compiler. Unless I'm mistaken, you'll already need to do this to properly randomize the struct layout.

1 Like

I'd have to investigate further but compiling a binary on release with or without LTO doesn't seem to include the debug fmt function impl for a couple of data structures with debug derive, when they aren't used to debug print (which is sort of expected).

Iirc we pass --gc-sections to the linker which usually removes unused functions.

So this might be something you just dont need to worry about as long as you don't debug print.

Why is it a problem though if they can reverse engineer std debug structures or external crate? Not sure what that buys them exactly.

1 Like