Remove project info from panic messages - rust

How can I hide project info (like source code paths) from panic messages occurred while running a release build?
Assume following code as a Minima Reproducible Example
fn main() {
println!("Hello!");
let v = vec![0];
println!("{:?}", v[1]); // panic - index out of bounds
}
> cargo build --release
> target/release/hello-rust
Getting:
Hello!
thread 'main' panicked at 'index out of bounds: the len is 1 but the index is 1', src/main.rs:5:22
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Revealing "src/main.rs:5:22" is very unwanted. I would prefer not to reveal even that the executable build with Rust.
I would like just to exit the process with "1" error code on every panic situation, like index out of bounds or .unwrap() on error.
Tried:
[profile.release]
panic = "abort"
Didn't help.
Tried to look in Profile Settings, didn't find something useful.

Related

dead_code warning in Rust when Debug printing a struct

I am very new to Rust and I am wondering about the warning produced by the following code before it runs. I am running version: rustc 1.67.0 (fc594f156 2023-01-24) from the stable channel.
1 #[derive(Debug)]
2 //#[allow(dead_code)]
3 struct Account {
4 balance: f32,
5 }
6
7 fn main() {
8 let account = Account { balance: 10.0 };
9 println!("{:?}", account);
10 }
$ cargo run
Compiling bank v0.1.0 (/Users/rlfeider/projects/rust/bank)
warning: field `balance` is never read
--> src/main.rs:4:5
|
3 | struct Account {
| ------- field in this struct
4 | balance: f32,
| ^^^^^^^
|
= note: `Account` has a derived impl for the trait `Debug`, but this is intentionally ignored during dead code analysis
= note: `#[warn(dead_code)]` on by default
warning: `bank` (bin "bank") generated 1 warning
Finished dev [unoptimized + debuginfo] target(s) in 0.09s
Running `/Users/rlfeider/projects/rust/bank/target/debug/bank`
Account { balance: 10.0 }
$
Why is a warning printed before the code runs?
I would think that the Debug print of the account struct in line 9 would read the balance field.
Does it have something to do with at what point in the compilation of the code that the println! macro is expanded vs when the lint check for dead code occurs?
All things I tried that gets rid of the warning:
Allowing dead_code by uncommenting line 2 removed the warning.
explicitly printing account.balance in the println! also gets rid of the warning.
Making the account variable mutable and setting account.balance to another value before println! also gets rid of the warning.
The error appears before your program is run because it's a compile time warning.
Derived Debug instances are a special case for the dead_code warning, if your code only uses a field in the Debug implementation then it will still consider it unused, i.e. the field isn't used in non debugging code.

How to properly fix clippy::unused_io_amount for std::net::TcpStream::read()?

In the Rust's book final project the code compile and run as expected with cargo run.
However, clippy highlights these commented lines with clippy::unused_io_amount
let mut buffer = [0; 1024];
stream.read(&mut buffer).unwrap(); // clippy: read amount is not handled
// --snip--
stream.write(response.as_bytes()).unwrap(); // clippy: written amount is not handled
stream.flush().unwrap();
The suggest fix is to change read to read_exact and write to write_all. However, when running with this changes I get the following error:
thread '<unnamed>' panicked at 'called `Result::unwrap()` on an `Err` value: Error { kind: UnexpectedEof, message: "failed to fill whole buffer" }', src/main.rs:24:36
How to fix the clippy:: unused_io_amount warning to be able to properly run the rust final project code without any warnings and have it to work as expected?
P.s. in the final project listing write_all is included but the warning for read continues on.
The stream.write(...).unwrap() will return the number of bytes that have been written into the stream. Your warning says that this number is not handled. It means that you should write let bytes_amount = stream.write(...).unwrap(); and then compare bytes_amount with buffer.len().
Why? Because in real life can be a situation when not all data from the buffer were written into the stream. You should handle such situations
The same with the read function.
Why read_exact fails. The read_exact function tries to read bytes to fill a WHOLE buffer but can be a situation the stream ends before the buffer gets filled.

why does max_by_key with i32.log10() causing "attempt to add with overflow"

I'm trying to get the max number of digits in an i32 array. I'm using log10(n) + 1 as my formula to calculate how many digits an i32 has and I thought I would just be able to use that within a max_by_key, but I am getting
thread 'main' panicked at 'attempt to add with overflow', /mnt/f/Personal-Docs/Repos/radix_sort_rs/src/lib/lib.rs:9:60
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Here's my code:
fn get_max_digits<const N: usize>(arr: [i32; N]) -> i32 {
return *arr.iter().max_by_key(|a| a.log10() + 1).unwrap();
}
I'm still new to rust so sorry if this is a simple question.
Figured out the answer to my question not too long after posting. I was trying to do a logarithm of 0 causing undefined. I believe the attempt to add with overflow is the current interaction with 0i32.log10() as it is a nightly only feature.

Why does the Rust compiler not reuse the memory on the stack after an object is moved?

I thought that once an object is moved, the memory occupied by it on the stack can be reused for other purpose. However, the minimal example below shows the opposite.
#[inline(never)]
fn consume_string(s: String) {
drop(s);
}
fn main() {
println!(
"String occupies {} bytes on the stack.",
std::mem::size_of::<String>()
);
let s = String::from("hello");
println!("s at {:p}", &s);
consume_string(s);
let r = String::from("world");
println!("r at {:p}", &r);
consume_string(r);
}
After compiling the code with --release flag, it gives the following output on my computer.
String occupies 24 bytes on the stack.
s at 0x7ffee3b011b0
r at 0x7ffee3b011c8
It is pretty clear that even if s is moved, r does not reuse the 24-byte chunk on the stack that originally belonged to s. I suppose that reusing the stack memory of a moved object is safe, but why does the Rust compiler not do it? Am I missing any corner case?
Update:
If I enclose s by curly brackets, r can reuse the 24-byte chunk on the stack.
#[inline(never)]
fn consume_string(s: String) {
drop(s);
}
fn main() {
println!(
"String occupies {} bytes on the stack.",
std::mem::size_of::<String>()
);
{
let s = String::from("hello");
println!("s at {:p}", &s);
consume_string(s);
}
let r = String::from("world");
println!("r at {:p}", &r);
consume_string(r);
}
The code above gives the output below.
String occupies 24 bytes on the stack.
s at 0x7ffee2ca31f8
r at 0x7ffee2ca31f8
I thought that the curly brackets should not make any difference, because the lifetime of s ends after calling comsume_string(s) and its drop handler is called within comsume_string(). Why does adding the curly brackets enable the optimization?
The version of the Rust compiler I am using is given below.
rustc 1.54.0-nightly (5c0292654 2021-05-11)
binary: rustc
commit-hash: 5c029265465301fe9cb3960ce2a5da6c99b8dcf2
commit-date: 2021-05-11
host: x86_64-apple-darwin
release: 1.54.0-nightly
LLVM version: 12.0.1
Update 2:
I would like to clarify my focus of this question. I want to know the proposed "stack reuse optimization" lies in which category.
This is an invalid optimization. Under certain cases the compiled code may fail if we perform the "optimization".
This is a valid optimization, but the compiler (including both rustc frontend and llvm) is not capable of performing it.
This is a valid optimization, but is temporarily turned off, like this.
This is a valid optimization, but is missed. It will be added in the future.
My TLDR conclusion: A missed optimization opportunity.
So the first thing I did was look into whether your consume_string function actually makes a difference. To do this I created the following (a bit more) minimal example:
struct Obj([u8; 8]);
fn main()
{
println!(
"Obj occupies {} bytes on the stack.",
std::mem::size_of::<Obj>()
);
let s = Obj([1,2,3,4,5,6,7,8]);
println!("{:p}", &s);
std::mem::drop(s);
let r = Obj([11,12,13,14,15,16,17,18]);
println!("{:p}", &r);
std::mem::drop(r);
}
Instead of consume_string I use std::mem::drop which is dedicated to simply consuming an object. This code behaves just like yours:
Obj occupies 8 bytes on the stack.
0x7ffe81a43fa0
0x7ffe81a43fa8
Removing the drop doesn't affect the result.
So the question is then why rustc doesn't notice that s is dead before r goes live. As your second example shows, enclosing s in a scope will allow the optimization.
Why does this work? Because the Rust semantics dictate that an object is dropped at the end of its scope. Since s is in an inner scope, it is dropped before the scope exits. Without the scope, s is alive until the main function exits.
Why doesn't it work when moving s into a function, where it should be dropped on exit?
Probably because rust doesn't correctly flag the memory location used by s as free after the function call. As has been mentioned in the comments, it is LLVM that actually handles this optimization (called 'Stack Coloring' as far as I can tell), which means rustc must correctly tell it when the memory is no longer in use. Clearly, from your last example, rustc does it on scope exit, but apparently not when an object is moved.
i think the fn drop do not free the memory of S, just call the fn drop.
in first case the s still use the stack memory, rust can not be reused.
in second case, because the {} scope, the memory is free. so the stack memory reused

Cargo build --release option ignored when testing overflow

I've been stepping through the Programming Rust book and wanted to observe the two's complement wrapping, so simple code of:
fn main() {
let mut x: u8 = 255;
println!("the value of x is {}", x) ;
x = 255 + 1 ;
println!("The value of x now is {}",x) ;
}
when I try and compile this with Cargo as per the guide, I run
cargo build --release
which in the book says will let it compile without overflow protection, but it won't compile. I get the protection error
|
6 | x = 255 + 1 ;
| ^^^^^^^^^^^ attempt to compute u8::MAX + 1_u8, which would overflow
Can you explain what I'm doing wrong please ?
I believe the value is not checked dynamically during run-time (it wont panic and would overflow) but still statically checked for (if possible) during compile time.
In this case the compiler is able to determine at compile time what you're trying to do and prevents you from doing it.
That being said if you look at the compiler output you can see the following message:
note: #[deny(arithmetic_overflow)] on by default
You'll see this message regardless of the optimization level.
If you'd like to observe the overflow put the following inner attribute at the top of your source file.
#![allow(arithmetic_overflow)]
Or, if you're compiling with rustc directly you can pass the following flags:
-O -A arithmetic_overflow
The rustc docs show that the following lints are on by default (regardless of optimization level)
ambiguous_associated_items
arithmetic_overflow
conflicting_repr_hints
const_err
ill_formed_attribute_input
incomplete_include
invalid_type_param_default
macro_expanded_macro_exports_accessed_by_absolute_paths
missing_fragment_specifier
mutable_transmutes
no_mangle_const_items
order_dependent_trait_objects
overflowing_literals
patterns_in_fns_without_body
pub_use_of_private_extern_crate
soft_unstable
unconditional_panic
unknown_crate_types
useless_deprecated
When you write a literal 255+1 in your code, the compiler evaluates the expression at compile-time and sees the overflow immediately, whether in debug or release mode. When the book says that --release disables overflow protection, it's talking about runtime checks. You can see the difference with this code:
fn increment (x: u8) -> u8 { x + 1 }
fn main() {
let x = 255;
println!("x: {}, x+1: {}", x, increment (x));
}
Playground
If you run this code in debug mode, you get:
thread 'main' panicked at 'attempt to add with overflow', src/main.rs:1:30
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
But if you run it in release mode, you get:
x: 255, x+1: 0

Resources