rust-lang / backtrace-rs

Backtraces in Rust
https://docs.rs/backtrace
Other
530 stars 245 forks source link

When will it crash(segfault)? We cannot afford Rust algorithms crashing on our Android/iOS app #441

Closed fzyzcjy closed 2 years ago

fzyzcjy commented 2 years ago

Hi thanks for the lib and the language! As doc says,

Unwind information may be inaccurate or corrupt. In the worst case inaccurate unwind information can lead this library to segfault. In the best case inaccurate information will result in a truncated stack trace.

Therefore, I wonder when will such case happen? Especially, when will such information be inaccurate or corrupt? When will it segfault? Can we avoid such cases?

We run Rust on Android/iOS apps, so you know, we cannot afford Rust algorithms crashing on our app. Otherwise, it will be a very, very bad user experience - imagining your daily used app just crashs once in a while!

bjorn3 commented 2 years ago

backtrace-rs is normally only used when your program has a bug that would cause your app to crash anywau. In this case backtrace-rs is used to show a nicer error message. This error message will be printed to the terminal (or in case of a mobile app likely a log file), so inaccurate or corrupt will only be an issue when you are actually debugging the app yourself, or if your app is security sensitive. The unwind info already needs to be accurate and not be corrupt for code written in C++ (like part of the OS libraries) to handle exceptions, so backtrace-rs is unlikely to be an extra risk.

fzyzcjy commented 2 years ago

backtrace-rs is normally only used when your program has a bug that would cause your app to crash anywau. ... so inaccurate or corrupt will only be an issue when you are actually debugging the app yourself

Oops, I want to use backtrace-rs when using anyhow's Result. In other words, whenever I return an Error (recoverable, of course), I want to know the stack trace of that error. I want this feature in production environments as well, since when using other languages such as Java or Dart(Flutter) we do have this. Indeed, anyhow has a cargo feature that enables this backtrace capturing.

Therefore, in such cases, inaccurate can be problems - when the app is running in production in users' mobile phones and have errors, I do want to know what happens. Let alone crashes like segfaults mentioned in readme.

The unwind info already needs to be accurate and not be corrupt for code written in C++ (like part of the OS libraries) to handle exceptions, so backtrace-rs is unlikely to be an extra risk.

Sorry I do not quite understand. What is the relationship between unwind info for C++ and backtrace-rs? Does backtrace-rs uses C++? I have seen that Rust says its format is incompatible with other languages, so I guess a C++ unwinder should fail.

Thanks!

bjorn3 commented 2 years ago

Oops, I want to use backtrace-rs when using anyhow's Result.

I see.

Therefore, in such cases, inaccurate can be problems - when the app is running in production in users' mobile phones and have errors, I do want to know what happens. Let alone crashes like segfaults mentioned in readme.

I don't think you will have to worry about that. If the unwind info is corrupted, this either happened during compilation, in which case your compiler is broken (unlikely to be the case for rustc) or it happened at the user's device, in which case the actual code is probably also corrupt.

I think the reason the readme mentions it at all is because backtrace-rs used to use the C(++?) library libbacktrace for symbolication, which badly handled corrupt debuginfo, which is possible for an external process to cause as the debuginfo is read only once it is actually needed and may be stored in an external file. The unwind info however is stored inside the executable itself and loaded immediately when running the program, so if an attacker is able to corrupt the unwindinfo, they could also corrupt the code itself. Backtrace-rs has now replaced libbacktrace with the rust dependencies gimli/addr2line, which won't segfault with corrupt debuginfo. At most they will panic, which you can catch using std::panic::catch_unwind.

Sorry I do not quite understand. What is the relationship between unwind info for C++ and backtrace-rs? Does backtrace-rs uses C++? I have seen that Rust says its format is incompatible with other languages, so I guess a C++ unwinder should fail.

The same unwinding information is used by C++ to handle exceptions, by Rust to handle panics and by backtrace-rs to unwind the stack. In fact they all use the same stack unwinding library underneath.

fzyzcjy commented 2 years ago

I think the reason the readme mentions it at all is because backtrace-rs used to use the C(++?) library libbacktrace for symbolication, which badly handled corrupt debuginfo, which is possible for an external process to cause as the debuginfo is read only once it is actually needed and may be stored in an external file. The unwind info however is stored inside the executable itself and loaded immediately when running the program, so if an attacker is able to corrupt the unwindinfo, they could also corrupt the code itself. Backtrace-rs has now replaced libbacktrace with the rust dependencies gimli/addr2line, which won't segfault with corrupt debuginfo. At most they will panic, which you can catch using std::panic::catch_unwind.

Wow, so you mean it now uses gimli/addr2line instead of libbacktrace, so that sentence is outdated and not true anymore?

The same unwinding information is used by C++ to handle exceptions, by Rust to handle panics and by backtrace-rs to unwind the stack. In fact they all use the same stack unwinding library underneath.

Interesting! Originally when I say in the nomicon: Rust's unwinding strategy is not specified to be fundamentally compatible with any other language's unwinding. As such, unwinding into Rust from another language, or unwinding into another language from Rust is Undefined Behavior. (https://doc.rust-lang.org/nomicon/unwinding.html) I thought that, Rust used a pretty different way of stacks. However, now I guess you mean that, they use the same unwinding information, but just different strategy to use that same information.

philipc commented 2 years ago

Wow, so you mean it now uses gimli/addr2line instead of libbacktrace, so that sentence is outdated and not true anymore?

It is still true. The sentence is referring to unwinding using the unwind info, which still uses non-rust code (and even if it were rust, it would still potentially segfault because unwinding is inherently unsafe). The likelihood of segfaults when unwinding rust applications is the same as for code written in other languages like C/C++ (so not something you should be worrying about).

gimli/addr2line is used for symbolization, which uses debug info. The sentence in the doc below the one you quoted applies to it: "Backtraces may not report filenames/line numbers correctly due to missing or corrupt debug information. This won’t lead to segfaults unlike corrupt unwinding information, but missing or malformed debug information will mean that filenames and line numbers will not be available. This may be because debug information wasn’t generated by the compiler, or it’s just missing on the filesystem."

fzyzcjy commented 2 years ago

The likelihood of segfaults when unwinding rust applications is the same as for code written in other languages like C/C++ (so not something you should be worrying about).

That sounds great!

gimli/addr2line is used for symbolization, which uses debug info

Now I am clear about the difference between unwinding and symbolization. Thanks!

alexcrichton commented 2 years ago

The general answer to the title of this issue is "no", under normal and expected operation this crate won't segfault. If you are a compiler engineer and/or writing a linker, then a mistake in your code could cause this library to segfault. If you're not one of those and the platform you're working for has a high-quality compiler and linker then you're unlikely to crash. Basically if you trust the platform then this library won't segfault, so it's no more or less trustworthy than functions in libc itself.

Corrupt, missing, or incorrect unwinding information is pretty rare. It's not impossible and does happen (e.g. if you hand-write assembly and mix up directives), and this crate's safe API for getting a backtrace does not reflect some of the inherent unsafety of unwinding. In general, though, if you're developing an application on a major platform then it should be expected that this library won't segfault or crash.

fzyzcjy commented 2 years ago

Thank you very much!