Hacker News new | ask | show | jobs
by lathiat 8 days ago
The problem with asserts is that they are pretty dramatic and you crash the entire program.

We generally did this in the avahi libraries, be fairly liberal with asserts that "shouldn't happen", it is a source of complaints though because basically you can be using a third party library that uses avahi and have your program crash due to a bug in that library, or in avahi. It's extra fun when using some historical libc systems such as "NSS" and you load a plugin to do hostname resolution, which nss-mdns does.. now you can have any program on the entire system crash if you are assert happy.

On the one hand I agree that if the result is going to be memory un-safety then perhaps you should assert, but more ideally you'd just fail gracefully and throw or return an error. That can sometimes be tricky though, if there is no good way to return an error or return a NULL value or similar. Depending on the API.

Of course, this is the entire reason behind the error return traditions of Golang and Rust, e.g: https://doc.rust-lang.org/book/ch09-00-error-handling.html

Which basically says what I said above :)

But in the case of curl_getenv, returning NULL seems a valid possibility (https://curl.se/libcurl/c/curl_getenv.html) as that is indicated to be done if you don't find the requested environment variable. Arguably the NULL environment variable is not found. so, this feels likely to be acceptable. Though I could see an argument for you now assuming the environment variable you were actually looking for not existing, but you didn't actually ask for one, and now your logic is broken and maybe you introduce a different class of security bug because you change your behaviour based on some environment variable not existing.

As always everything is a trade-off...

2 comments

Returning to the context of this post, this is one of the things I really like about rust. (And zig, haskell, typescript, swift and others). These languages make invalid states impossible to represent. If my function takes a value of type T (or &T), you can't accidentally receive NULL. So you just don't need to worry about this stuff any more. The compiler simply won't compile the program if type checking fails. At runtime, I only have to consider valid values.
Zig still doesn't have a way to represent that a pointer to a heap allocated region is no longer valid.
Crashing a program is always a much better alternative than behaviours that silently lead to memory corrupt, having much severe outcomes than a crash.

Ah but what high integrity computing, well there neither crashes nor memory corruption are welcomed, hence programming guidelines and certification workflows that would make most C devs cry with the language features they are allowed to use, and how each line of code gets analysed by tools and humans.