52 comments

[ 1.6 ms ] story [ 139 ms ] thread
I will probably get downvoted for this, but I feel writing any new libraries in C/C++ is a bit of a waste when Rust is now available. Especially for file format parsing which is prone to overflows and the like. Yes there are safe coding practices but why not just choose a better tool for the job.
> is a bit of a waste when Rust is now available.

I will probably get upwoted for Libmobi and other C/C++, because Rust is a bit of a waste of time.

Rust is a language created by idiots who couldn't learn how to program C. I agree completely. Nobody uses Rust except for NFT and crypto shills, and that's because Rust is a rhetorical language created by a company that should be making free web browsers, not wasting time..m
Judging by the number of vulnerabilities that continue to be found every freaking year due to easily preventable problems, it seems nobody has learned how to program in C to this day. Yourself included.

Having said that, Rust is a C++ replacement not a C replacement. The biggest selling point of C is being the thing every other language talks and running everywhere including embedded devices with crappy custom compilers.

With both Rust and C++ you still need to write extern "C" wrappers which are suboptimal, even when partially automated, and neither runs everywhere.

I'd say zig is more of the "safe" c replacement. Rust is more of a competitor to c++. I'm happy to switch to rust and be able to focus on making sure my logic is secure while letting rust take care of catching memory safety bugs for me.
Some of us have no desire to learn Rust… well I did, but found the syntax to be awful. If you already know C, C++ or something else, you really need a good reason to learn a new language, especially one with a syntax as messy as the of Rust.

That being said, you do have a valid point that file format parsing really could benefit from a language with the safety features of Rust.

I'd say making buffer overflow and UAF CVEs Just Go Away -- forever -- is a DAMN good reason to switch to Rust.

I've found that prior exposure to C is somewhat negatively correlated with willingness to grok Rust. Something in their mind rebels against it, which is why I say that if you're an "old hand" C programmer who feels that the syntax of Rust is too hard, or the borrow checker is obscure, maybe you shouldn't worry about learining Rust because Rust isn't for you -- it's for your replacement. You're John Henry, the borrow checker is the mechanical spike driver, and no matter how hard you work at it all your programming discipline is just no match.

> I'd say making buffer overflow and UAF CVEs Just Go Away -- forever -- is a DAMN good reason to switch to Rust.

rocket Crate up to 0.4.6 on Rust uri::Formatter use after free

https://vuldb.com/?id.172079

If only people stopped with the cargo cult nonsense that leads to this absurd belief that adopting a tool is a silver bullet to fix their sloppy practices.

You know, seeing one of the few existing Rust CVEs, which is a freak case, hard to exploit - makes me directly want to go back to the language family with the majority of the CVEs assigned. The existence of CVE itself arguably is a result of unsafe C/C++.
> You know, seeing one of the few existing Rust CVEs (...)

It is a real world CVE of use-after-free on real world Rust code in production.

This demonstrates that, unlike claims from fanboys, mindlessly migrating to Rust does not magically make your code safe and immune to vulnerabilities such as use-after-free, and just like with any other language you still need to know what you are doing.

I think you are exactly right and it's sad that you are getting downvoted for this. The "bright" side for coders unwilling to learn new things is that there is lots of legacy C code to maintain to last a lifetime. It's still a bit sad since Rust is just lots of fun to work with.
C and C++ are completely different languages. The arbitrary parsing of data into structs in C is what makes it incredibly suitable for file parsing. Among other things.
C is a subset of C++. The key point is that both languages suffer from the same problems, e.g. memory safety issues, undefined behavior, data races.

The software industry has been dealing with the fallout of these issues for the past three decades. It's about time we moved the bar higher.

By the way, the main data structure of my first large Rust program was simply a vector of a custom struct, optimized for memory footprint. Just like in C, with the same low overhead serialization.

With C, you always have to be careful to not overrun a buffer. The recent NSS vulnerability is a great example of this:

https://googleprojectzero.blogspot.com/2021/12/this-shouldnt...

Even though this code was heavily fuzzed and tested, the problem slipped through. Not possible in Rust. Also, with Rust you can throw away all your sanitizer infrastructure and save all the associated costs.

> C is a subset of C++

It is not, they diverged since decades now.

Still, even if this was the case, the programming styles are so different that there’s nothing to gain considering them as any more similar as any two other languages.

> It is not, they diverged since decades now.

AFAIK you always had to cast `void *` in C++ (like the return value of `malloc`).

Why on Earth would one use malloc in C++? Instead of using ’new’ if explicit allocation is desired.
We are talking about the question if C is a subset of C++. `new` certainly isn't a part of C, so also not an element of the intersection of C and C++.

Idiomatic C code doesn't explicitly cast the return value of malloc

    foo *bar = malloc(sizeof *bar);
C++ did AFAIK never (certainly not with C++98, the question is if it had been allowed sometime before the standardization, but I think it never did) allow this, so you always had to do

    foo *bar = (foo *)malloc(sizeof *bar);
Therefore, C is not a subset of C++. But a (non-empty ;) intersection of C and C++ exists.
If you need to change the buffer size afterwards.

My understanding is that most implementations of new call malloc under the hood (this may or may not be outdated at this point, I haven't kept up with C++ implementation) and both of these systems introduce a layer of record keeping, so if you're in an extremely memory constrained environment, you may want to use malloc directly.

If you want your code to be noexcept, you need to call malloc and handle the case where it returns null as new can throw (this is UB in theory, but in practice I'm pretty sure everything just aborts) to strip out all the stack-unwinding code.

If you want to avoid the constructor call (for whatever reason).

> Why on Earth would one use malloc in C++? Instead of using ’new’ if explicit allocation is desired.

That was the point of my original comment that C++ and C are not the same language :)

Yeah. Someone gave me a file and told me to parse it. I used structs and fread. It was easy-peasy! I do not know of any other languages where what I wanted to do would have been just as easy as it was in C.
It is almost as if it was written with people doing a lot of IO and internet :D
Sockets are a later addition, but definitely wrt IO.
This sentiment is getting so fucking tiresome. Just don't use it if you don't like it.
Because the reason C/C++ codebases are getting hacked is not primarily because they're written in C/C++, its because they were written a LONG time ago when security didn't matter so much, the entire industry was much less mature and it was probably way harder to code, and management at companies would probably never allocate any time to a non-issue like that.

Its just so completely uninformed and noob-ish to equate _tools_ to what people build with them. The language is not nearly as important as the programmer and the context in which the code was written. Its a very typical new-programmer thing to think language is all that matters, but most programmers with a few years experience understand how little it matters compared to everything else. You guys are basically like those old Christian missionaries who show up somewhere in Africa knowing nothing and insist the locals convert. Totally clueless..

If we are starting to get snarky: There are two kinds of people who choose Rust over C++. Beginners who think C++ is too hard, and seasoned developers with years of experience working in large teams who _know_ C++ is too hard to get right.
ive been learning Rust and it doesn’t seem like the clear win fans say it is. i recently ran into a variant of this problem:

https://doc.rust-lang.org/nomicon/lifetime-mismatch.html

i know the lifetimes are fine, but Rust doesn’t. in a memory unsafe language i would have to model the mutability in my head to ensure the code is fine. i now need to model the lifetime checker and its limitations/false positives _in addition to_ the underlying mutability to understand whether a compiler error is actually a bug in my code or not. and this is in an extremely short & simple program.

a compiler that can truly enforce safety without too many false positives is definitely a win. but for now it seems like a leaky abstraction so it adds complexity instead of reducing it.

* Libmobi: C library for handling one specific vendor's eBook formats

If this let you at least ingest basically any eBook format, I'd be super interested. Unfortunately, it does not.

For example, literally the only (OSS) tool I've found that can parse .lrf files is calibre. There are zero other library tools that can let me extract the text content from them. MS's .lit files have similar issues, but at least there's no python libraries for it.

Outside of epub, there's a similar story for most other file formats too.

> If this let you at least ingest basically any eBook format, I'd be super interested.

Ever tried Calibre?

You could have at least read the rest of the comment first.

>For example, literally the only (OSS) tool I've found that can parse .lrf files is calibre

It seems like it can save Mobi/Kindle files as ePub, but it’s not clear if I can do the reverse, which would be rather neat.
I see some rust, c, c++ arguments in these comments.

It’s getting tired. This is the second time this morning that I’ve stumbled across that particular flame war.

I understand that security and memory safety are important and necessary arguments to have. Unfortunately, it’s a larger problem than which language you use. And, even if it were, it’s not like most (or any?) of the comments in this thread are even remotely correct.

On behalf of (hopefully) plenty of programmers, Let’s take a step back. Stop bugging me.

The log4j fiasco showed that just because you're memory safe doesn't mean you're out of the woods, security-wise. But... memory safety is still a necessary condition for a good security posture if you're building something that runs executable code. And while memory safety is theoretically possible in C, in practice it is an utterly intractable problem for human programmers to solve.

The abandonment of C as a viable language, and the replacement of C code, is a critical project for the software development community. It's not the only thing that needs to be done, but it's a great and necessary first step, just like abandoning internal combustion engines is for the climate, If you are writing new, production code in C, you are a fool. If you do not have a long-term plan in place to replace the C code you have that it isn't on some God-forsaken unreflashable ROM, you are irresponsible.

I agree with everything you raise here. C is a dinosaur that should be left to museums.

But I’m really, really tired of people comparing c interchangeably with c++ — and, more than anything else, if you have a good idea please just make a pull request on someone’s git repo.

And just in case anyone is unclear about this, if you ship code with unbounded memory leaks you’re going to hell

More than anything C should have had "slices" (aka fat pointers) added to the language. They wouldn't solve issues like use after free but they would enable sane ways of working with strings and buffers like every other language in existence.

Instead we got VLAs (now deprecated) and _Generic. Neat but who cares? The C standards committee doesn't really know what to do with the language it seems.

The purpose of C was to be an optimizable low-level language. If programmers wanted those things, the sense was always one of “ok, do it yourself and use it as a library.”

There are definite pros and cons to that particular standards methodology. It is, without any question, the most distributable language. The ABI is and will likely always be intact.

Nobody has ever argued that C is anything other than that. It’s about as dead simple as it can be.

There are other languages for other purposes. Rust and C++ are, in all cases I’m aware of, equivalent in performance to their “ideal” C program alternatives.

Nobody has ever argued until just recently that C is or ever has been anything other than what it is or that there is some kind of battle going on between Rust and “c/c++.” Nothing could be more untrue. C and C++ are different things. Though, with a clear lack of understanding you can write a “c” program in c++. The same is true with rust — everything can still be mutable and you can still have undefined behavior very easily (perhaps most easily with IO).

Plenty of other languages exist, too, with other ways of solving these problems. Haskell is a wonderful language which I hope someday to develop with if there was only some way of making it easier to work with file systems without a PHD.

This particular flame war between rust, c, and c++ is so contrived and tired and misleading.

Eh that's rather revisionist, C was a high-level language for the 70s. It isn't nowadays because there are languages that are so much higher level that it is low level in comparison. It's not much different from Fortran in that regard.

Rather than the purpose of C being an optimizable low-level language, it's more accurate to say that is the niche it carved out for itself.

There's plenty of crap in C that doesn't help with either optimization or a good ABI.

> Eh that's rather revisionist, C was a high-level language for the 70s.

No, not really. C was always, right from the start, a kin to portable assembly. You'd be hard pressed to come up with a language from the 70s which was at the same level or lower than C. Neigher Fortran nor COBOL nor ALGOL nor Lisp nor BASIC were lower level than C. Precisely which language, other than assembly, leads you to believe that C ever was considered a high-level language?

I don't understand what leads anyone to argue otherwise.

All languages back then, all of them, were "high-level" languages, including C. Look at the history of BCPL, B and C and how the goal was to write Unix in a "high-level" language. You can go hear Brian Kernighan himself tell you all about it.

C as a low-level language is revisionist history. Rust is a high-level language and yet it is a "lower level" language than Java. Same as C vs Pascal. You could write very low level code in Turbo Pascal back in the 80s, the demoscene used it a lot alongside assembly, it had inline assembly even.

EDIT: and to answer your question on what else was "low-level", Forth.

> All languages back then, all of them, were "high-level" languages, including C.

The only interpretation where this assertion rings remotely true is if you follow a definition of "high level language" which boils down to "it's not assembly", which has not been the case for around half a century.

It makes absolutely no sense to claim that languages such as COBOl and C are even close at the same level of abstraction, just because C is compiled, has loops, and has a standard library.

> The only interpretation where this assertion rings remotely true is if you follow a definition of "high level language" which boils down to "it's not assembly", which has not been the case for around half a century.

It was the interpretation back then which is what we're discussing :)

> The C standards committee doesn't really know what to do with the language it seems.

Honest question: why should C change? I mean, if all we want is access to higher-level core language features not provided by C, isn't it better to just pick up a higher-level language that already offers it? After all, if you add higher level features like smart pointers, is it really worth it to keep other features like the extensive reliance on the C preprocessor, dangerous string handling, and a spartan and in some cases outright unsafe standard library? Or would it be better to cut our losses and just adopt languages that already fixed those issues?

Honest answer: of course it is, and no serious developer is arguing otherwise.

I just finished shipping an industrial lighting unit for “smart farms.” I worked extensively on embedded hardware. The most advanced processor I used was armv6, with the majority of hardware being IC or FPGA.

I used C for one thing only: reading the bitstream from microcontrollers into memory. After which point, I used c++ (17) with exclusively standard libraries (one exception: boost’s ASIO for http) to implement any and all other features.

I would have happily used c++ to read those bitstreams, but the code was so unsafe that it refused to compile. Turns out that reading raw bytes from an irregular file descriptor is so arcane and bizarre that no sane modern compiler felt good enough about itself to allow me to compile it.

All that said, I would only ever allow myself to write in C in that isolated case and for that isolated purpose. Every other nanosecond of my codebase runs on modern c++.

Honest answer, there is no legitimate reason to use C. If in some edge case you must, there is no legitimate reason to use it for anything other than that.

But is is changing, the standards committee keeps adding things. Some of those are reasonable (stdbool.h, atomics), others are head scratchers (VLAs, now deprecated). It might have been better for C to have stayed frozen in time.

But look how many libraries are written in C, such that they can be made available everywhere. Look at how many are written in C++/Rust but with C wrappers with plenty of pointers and bad error handling.

Any improvements to the C standard would have meant a safer surface area for those languages to use to talk to other languages, since C is the english of programming.

There's no reason why C couldn't have namespacing, out-of-band errors, fat pointers, minimal reflection (typeof), standardized attributes, etc. ages ago. None of that would have screwed with the ABI or with optimization, but would have made language interoperability a lot easier.

> But is is changing

No, not really. At least in practical terms.

C11 saw some changes, and arguably only minor ones.

C17 is a bugfix update to C11.

And C20 is still in the works, and none of the proposed changes are relevant.

Consequently, C as been dormant since the release of C99, which already was criticized for not bringing anything new to the table other than C++98 tuneups, and support for inline comments (?!)

C11 had some very good updates for multithreading, unicode support and alignment specifications. All of those things made the language better. Yes compared to the crazy changes going on in C++ land all of these are minor, but they are good maintenance improvements.

C11 also had _Generic as a "major" addition (and a crappy one IMO). I agree that if C is not going to evolve in any meaningful way, they should probably just stop adding stuff to it entirely. Either go for a "C++11" or let it be frozen in place.

> comparing c interchangeably with c++

For the sake of the arguments made with regards to using Rust instead, they are exactly the same and comparable - both do not have memory safety, suffer from races and lots of undefined behavior. That was the whole argument. Sure, you can use only parts of C++ and use RAII to make much of that go away. But then again you can do the same in C. And nobody can enforce that everyone adheres to it.

This might be a good thread to raise this: a related EPUB library (libepub/ebook-tools[0]) is written in C and hasn't seen a release in 9 years. I tried to fuzz it once and reported dozens of crashes upstream[1], but it's unmaintained - no response.

Packages like okular, baloo, basket use it so it's semi-popular. Anyone has suggestions on what to do next?

[0]: https://sourceforge.net/projects/ebook-tools/

[1]: https://sourceforge.net/p/ebook-tools/bugs/10/

Hi, thanks for looking into this. I'm a kde developer and at least in name maintain basket. I think it would make sense to either replace the usage of this library in the above mentioned apps or fork the library and move it inside KDE. Could you contact me per email (see bio)?