News for hackers. Stuff that matters.
Re:C++ still isn't cutting it by agv720 on Sunday October 18, 2020 @07:46PM (#24822077)
>you aren't going to find anyone to argue that C is as safe as Rust.

That's good, I was starting to doubt humanity :)

>As for the TOCTTOU issue --- which is kind of silly, and had really nothing to do with Rust

agree. But well, was what it was claimed in the article.

>On a sane system...

I disagree with this one, although I know I am in the minority. A malloc failure is not a unrecoverable error, and the only reason to abort on memory error is because if you allow malloc errors, then virtually every line of code can fail, because it is either allocating memory or calling some other method that allocates memory. (I imagine you've already read http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p070... section 4.3 but I mention just in case someone hasn't heard of it)

Something similar happens with integer overflow, although we've collectively decided that we prefer to have 2,147,483,647 + 1 = -2,147,483,648. (in both C++ or rust in release mode). But if we assumed that i++ can cause an error, it would mean that every line of code could possible be an error.

But well, back to memory allocation: Just a month ago I had a situation where using a language (C#) which just throws an exception in memory overflow saved my day. I left running overnight a program that builds and creates setups for the programs I make. There are about 190 different setups (win32, 64, linux, and variations), all compressed using max settings in 7zip. Those builds run in parallel in a threadpool, and each 7zip compression takes a lot of memory. So much, that during the night one thread raised an out of memory error. When I woke up next day, I had 189 setups created correctly, and one that failed. I rerun that missing setup and was ready to publish them. Had I used a "sane" language, the full app would have aborted and I would have to run the 190 setups again.

But seriously, it can happen a lot, specially in embedded. You are processing images and one image is too big. Do you abort the app, or report the error and move to the next image?

>this code does essentially the same thing with errors that the Rust one does: it swallows them and continues

Thats was my point in the answer: Rust and C++ don't shallow the error. You have the line: reader.lines().filter_map(Result::ok)

And then: if let Err(e) = scanfiles() { println!("Error: Something unexpected happened: {:#?}", e);

So, if there is an error, it will report it to you, not shallow it. And that is to me the full point: The guy who coded the Rust version would have to go out of his way to shallow the error, while in C it is the default.

Re:C++ still isn't cutting it by tptacek on Sunday October 18, 2020 @07:54PM (#24822113)
The Rust program surfaces errors in globwalk, but swallows the fopen errors you were talking about (it filter_maps them away, which, to be fair, is what I'd do too).

None of the counters in that C program are going to wrap. If it makes you feel better, you can replace size_t with "unsigned long long", but that's already what it is on modern systems.

That Rust program will also abort on allocation failures, just like I'd expect my C program to, so recovering from memory exhaustion isn't really in the scope of the discussion here.

If you care about security, you abort a C program when allocation fails. If you ask programmers to check failures, you get malloc checking bugs. Especially in embedded systems, where offset-from-NULL pointers can get attackers something useful. There are exceptions to every rule (at least in C programming), but if the task is "count words in files", you're nuts if you do anything but blow up when malloc fails.

Re:C++ still isn't cutting it by agv720 on Sunday October 18, 2020 @08:27PM (#24822315)
> it filter_maps them away, which, to be fair, is what I'd do too

Ok, I don't know much rust and I imagined filter_maps reported to the main app. If it is shallowing them, then to me it is a big + for C++ in that area. It seems I will have to agree to disagree here, but shallowing the error is not what I would do at all. This program has the possibility to give you a completely wrong result, and you would never know. You could use that result in other thing, say publish a study where you claim there were only 100 words in the files you processed but there were 1000 because your program crashed and didn't warn you.

> If you care about security, you abort a C program when allocation fails.

Well, that's why I personally prefer C++ and exceptions. They abort by default, let you handle if you want/can.

But I think my original point was lost. My complain was that this code wasn't checking at all for failure. Shouldn't it be something like:

if(!w->next) w->next = calloc(1, sizeof(*w));

if (!w->next) abort();

    w = w->next; 
I mean, in this particular case it will indeed blow up because when it goes back to the while(w->word) w will be null and you will reference a null pointer. But that's mostly luck, and might be not be true anymore if you make changes to the code in the future. If you care about security, you should check all allocs, and abort if null. And that's my beef with C: It shallows and continues instead of crashing or reporting when there is an error.

> but if the task is "count words in files", you're nuts if you do anything but blow up when malloc fails.

I won't disagree here, if the task is count words in files. I was just trying to explain why imo, not all "sane" programs should abort in failed malloc.

Re:C++ still isn't cutting it by tptacek on Sunday October 18, 2020 @08:40PM (#24822382)
In serious C programs, you rig malloc to abort rather than return NULL. With jemalloc, for instance, you'd do it with opt.xmalloc.
Re:C++ still isn't cutting it by saagarjha on Monday October 19, 2020 @04:28AM (#24824300)
> A malloc failure is not a unrecoverable error

It's not, but it's also a fairly difficult error to recover from effectively. You really need to know what you're doing to get out of this–I think someone did a study for how many STL implementations handled std::bad_alloc correctly (i.e. unwound and didn't accidentally take down the program) and I think the number was zero.

> we've collectively decided that we prefer to have 2,147,483,647 + 1 = -2,147,483,648

Not always, overflowing is often exploitable since it lets you bypass less than checks.

Re:C++ still isn't cutting it by Ut_Pwnsim on Monday October 19, 2020 @01:05PM (#24828365)
>although we've collectively decided that we prefer to have 2,147,483,647 + 1 = -2,147,483,648. (in both C++ or rust in release mode)

Signed integer overflow is undefined behavior in C++. Only unsigned integers are defined to wrap like that.

https://stackoverflow.com/a/16188846