Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

If fresh code in Rust truly reduces the number or severity of CVE in a massively tested and fuzzed C library like this one it will be a major blow to the “carefully written and tested C/C++ is just as safe” perspective. Just need the resources and Rust performance to rewrite them all.


Despite mounting evidence this perspective remains shockingly common. There seems to be some effect where one might convince oneself that while others are constantly introducing high severity bugs related to memory un-safety, I always follow best practices and use good tooling so I don't have that issue. Of course evidence continues to build that no tooling or coding practice eliminates the risk here. I think what's going on is that as a programmer I can't truly be aware of how often I write bugs, because if I was I wouldn't write them in the first place.


I sort of have this perspective, slowly changing… I think it comes from a fallacy of take a small 20-line function in C, it can be made bug-free and fully tested, a program is made of small functions, why can’t the whole thing be bug free? But somehow it doesn’t work like that in the real world.


> why can’t the whole thing be bug free? But somehow it doesn’t work like that in the real world.

It can be, if the composition is itself sound. That's a key part of Rust's value proposition: individually safe abstractions in Rust also compose safely.

The problem in C isn't that you can't write safe C but that the composition of individually safe C components is much harder to make safe.


And the reason for that is that a C API cannot express lots of things that are needed to make composing code easy. Ownership is one of them, another “when I’m done with the thing you gave me, how do I dispose of it?”


There would be far fewer bugs if people actually stick to writing code like that.

I once had to reverse engineer (extract the spec from the code) a C++ function that was hundreds of lines long. I have had to fix a Python function over a thousand lines long.

I am sure the people who wrote that code will find ways to make life difficult with Rust too, but I cannot regret having one less sharp knife in their hands.


On the other hand, parceling a large function into smaller functions can create indirection that is even harder to follow and harder to verify as bug-free.


Maybe, but it usually has the opposite effect. If you have well-designed and named functions the indirection is a feature since it reduces the amount of context you need to remember and gives you a visible contract instead of having to reason about a large block of code.


This works if you know what each callee performs, which you frequently don't when you're visiting a new codebase (it may have an unknown function you have to read to know, functionality not relevant to your problem, or you may have to analyze two or more functions in the context of each other to understand a bug).


Also, the act of breaking it into smaller functions itself may introduce more bugs.


Yes, rewrites are risky, but I really meant not writing such large functions in the first place.


> I think it comes from a fallacy of take a small 20-line function in C, it can be made bug-free and fully tested

It can't. You can make yourself 99.9...% confident that it's correct. Then you compose it with some other functions that you're 99.9...% about, and you now have a new function that you are slightly less confident in. And you compose that function with other functions to get a function that you're slightly less confident in. And you compose them all together to get a complete program that you wouldn't trust to take a dollar to the store to buy gum.


There's also a sort of dead sea effect at work. People who worry about introducing safety bugs use safe languages to protect themselves from that. Which means that the only people using C are people who don't worry about introducing safety bugs.


> Of course evidence continues to build that no tooling or coding practice eliminates the risk here

Concidering Rust is just tooling and coding practice in front of LLVM IR does this statement not also include Rust? There are in fact formally verified C and C++ programs, does that formal verification also count as tooling and coding practice and therefore not apply?

If either of the above is true why does it matter at all?

I am specifically calling out your blanket statement and want to open uo discussion about it because at present your implied point was it is impossible to write safe code in C/C++ and it is only possible in Rust, however the very point you made would also apply to Rust.

There are also non-safety issues that may affect the integrity of a program. I recently again looked into Rust, haven't given up just yet but to just instantiate a WGPU project the amount of incidental complexity is mind boggling. I haven't explored OpenGL but concidering that the unofficial webgpu guide for rust [1] recommends using an older version of winit because the current version would require significant rewrites due to API changes is not encouraging. Never mind the massive incidental complexity of needing an async runtime for webgpu itself, is this a pattern I am going to see in different parts of Rust. Rust already has enough complexity without injecting coroutines in places where blocking functions are reasonable.

1. https://sotrh.github.io/learn-wgpu/#what-is-wgpu


Google's overall approach to Rust right now is based on a philosophy that sees two categories of bugs:

1. bugs in new code

2. bugs in old code that have survived years of scrutiny

Their conclusion from this is that they're generally greenlighting Rust for new projects but not requiring a rewrite for old projects because they believe rewrites are likely to introduce new category-1 bugs (regardless of the target language). But new code always has category-1 bugs, so if they write it in Rust they cut down on the number of possible category-2 bugs thanks to the static constraints imposed by the type system.

I'm assuming the font module got rewritten into Rust because they planned to rewrite it period (i.e. their analysis suggests the current status quo of how it's built and maintained is generating too many bugs, and Google tends to be very NIH about third-party dependencies so their knee-jerk response would be "solve that by writing our own").


Was going to jump in to say this. We interviewed Jeff Vander Stoep about this a couple months ago; it was pretty interesting: https://securitycryptographywhatever.com/2024/10/15/a-little...

It's always better to get new memory-safe code in to replace old memory-unsafe code, when you can, but the prioritization here is a little more complex.


FreeType was written when fonts were local, trusted, resources, and it was written in low-level C to be fast. The TrueType/OpenType format is also made for fast access, e.g. with internal pointers, making validation a pain.

So though FreeType is carefully written w.r.t. correctness, it was not meant to deal with malicious input and that robustness is hard to put in afterwards.


TrueType also just has way too much complexity accumulated into it. The character to glyph mapping table alone has nine different encoding formats. I was only writing a TTF file instead of reading it and the complexity was still impressive.


If you think FreeType is bad, wait until you find out win32k.sys used to parse TrueType fonts directly in the kernel. https://msrc.microsoft.com/blog/2009/11/font-directory-entry... (that’s just one of a million vulnerabilities thanks to kernel mode font parsing.)


That perspective is blown to those that see beyond themselves.

Or can admit themselves as fallible.

Or realize that even if they are near-infallible, that unless they've studied the C _and_ C++ standards to the finest detail they will probably unintentionally produce code at some point that the modern C++ compilers will manage to make vulnerable in the name of undefined behaviors optimizations (see the recent HN article about how modern C/C++ compilers has a tendency to turn fixed-time multiplications into variable time and vulnerable to timing attacks).

But of course, there is always tons of people that believe that they are better than the "average schmuck" and never produce vulnerable code.


Is the FreeType2 test suite public? It looks like the project's tests/ directory only contains a script for downloading a single font [1]. They have a fuzz test repo with what appears to be a corpus of only a few hundred tests [2]. For critical infrastructure, like FreeType, I'd expect hundreds of thousands if not millions of tests, just like SQLite [3].

[1] https://gitlab.freedesktop.org/freetype/freetype/

[2] https://github.com/freetype/freetype2-testing/

[3] https://www.sqlite.org/testing.html


I don’t know if this applies to freetype’s testing, but when I worked on software that operated on fonts in the past I quickly concluded that piracy was the only practical way to test it. You need a very large corpus of real fonts, which would be both very expensive and not redistributable. This meant that I did not open source my tests.


Better comparison would be fresh code in Rust vs fresh code in C. Re-writing in both languages following best practices testing and fuzzing. A big difference vs comparing to legacy C code that is trying to be maintained by throwing 0.25 google engineers at it to fix an ongoing stream of fuzzing issues.


There are no major blows required. The idea that carefully written C/C++ code is just as safe was never tenable in the first place, and obviously so.


And yet there are still many people, some who comment here, who think that they can and do write C/C++ carefully enough to avoid memory safety bugs. The hubris and arrogance is mind-boggling.


I generally agree, but their manual memory management CVEs were dated 2014 and 2020. That doesn't really feel like a strong substantiation of their case here.


The real issue is the effort required to rewrite everything without introducing new bugs resulting from a misunderstanding of the original code


New (likely aesthetic only) bugs in font rendering are probably considered preferable to existing security vulnerabilities, I would hope.


if you have too many aesthetic bugs, nobody will use it. it then becomes the most secure code because it doesn't run anywhere so can't be exploited.


it's hard to argue that "occasional accent rendering issue" is better than "occasional zero-click issue", but rewriting code of any actual complexity is hard in practice... and we are talking about only one library here, with thousands libraries and utils to go


“Aesthetic only” bugs for a project entirely for aesthetics can easily kill the usage of it.

Nobody cares about a CVE-free rendering library if it can’t render things correctly.


that really depends. There are thousands of languages in the world in dozens of alphabets and I currently only have a hope of reading text in a latin alphabet. As such, even a rendering library that misrendered 99% of unicode but was CVE free would be a major win for me (and hundreds of millions of people)


freetype code looks chaotic, though, it was written for local trusted fonts first. It was a typical google move "let's expose this random thing to internet, we can add security in 2025".


C and modern C++ are so different that lumping them together in a blanket assertion doesn't really carry much meaning.


It is true that they are different, but also, given the significant overlap between the two, people will reasonably talk about them together.


From a safety perspective they aren't very close, there is a reason that all these CVE bugs are C code.


I haven't seen conclusive evidence that this is the case, do you happen to have an analysis of this somewhere?

Of course, C++ offers you tools that C doesn't, but some of those tools have their own sharp edges as well. Plus, many C++ codebases are "C with classes" style or similar hybrids, those are still ultimately C++ programs, not C ones.


Counterexamples would be s2n, grpc, putty, postfix, that are either C with classes or non-PDP C. I suppose in postfix security design was an afterthought and added gradually, but at least it was thought.


I think this means you're making the opposite argument that most C++ folks do, which is that C with classes is bad, and more prone to security issues than "modern C++" is.


My argument is that C with classes is bad when it uses bad security practice, not because it must be bad.


If the code compiles with a C++ compiler, for better or worse it is C++ as well, might be C style C++ code, which is nonetheless part of the grammar, semantics and libraries defined by ISO C++ standard.

And that is the deal, lack of security culture.


If only didn't exist so many folks that insist in using C types, and C headers, in modern C++ code.


Indeed.


i think part of it is that if you have one in your project, it's nearly frictionless to have both. the toolchain is the same, and especially if you're using C++, you can and often do have C dependencies


That perspective was never correct to begin with. Along with laughable comments I have seen like "memory safety is easy. Memory related bugs are created by bad programmers".

See comments under this video: https://youtu.be/gG4BJ23BFBE

We are all humans, and humans make mistakes. The obvious way to avoid mistakes is to formalize "correct code" and get code chekced by machines, and in this context, let the compiler guarantee the correctness. Anything else will never be as effective.


Only "obvious" if the things you are doing match simple ownership patterns for example. If you want to do performance-oriented things: for example compressing the size of certain data structures, shaving off a few pointers/integers of or even compress them in some way. Or applying various concurrency patterns, or otherwise speed up the code...

... then it's not all obvious anymore. In these situations you'd rather drop down to assembly than go up to sth like Rust.

I'm currently doing my 2nd take on a userspace allocator (fixed-size pages but of different sizes, running 32-bit too) as well probably my 8th take or so on a GUI toolkit. I've experimented with lots of approaches, but it always seems to come back to removing abstractions, because those seem to kill my work output. A big reason is they blow up code size and make code (by and large) less understandable, as well as harder to change because of the sheer size.

Not necessarily saying that approach doesn't lead to more potential security issues. I mostly just turn up warnings, not doing fuzzing etc. But it seems to be a more pragmatic way for me to achieve functioning (and robust-in-practice) software at all.


I think the center of the conversation is "general purpose safety" (a term I just made up), i.e. if you just want to get things done, how to write thr code in a safe way. If your other needs like performance are critical, things need to be looked at differently.

Which is why the video I linked is not so relevant to HFT guys, for example. (Context: some people try to use HFT as "counter example" to that video.) Let's be realistic -- nobody cares about whether your code running trading algorithms inside your company is memory safe.


As C++ is a completely separate language from C, this has no relevance to C++.


Not disagreeing but its not absolutely fresh - the library used was released more than an year ago, and its built on a low level library released three years ago.

Obviously a lot younger than Freetype.

It would also be a lot less important if we did not do silly things like loading fonts from random websites.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: