I hope that if we switch away from FreeType, we'll still have a way to use TTF hinting instructions fully.
Windows/macOS don't seem to have a way to enable proper hinting anymore [0], and even FreeType (since 2.7 [1]) defaults to improper hinting (they call it "subpixel hinting", which doesn't make sense to me in theory, and practically still seems blurry, as if it's unhinted).
In case anyone's wondering what properly hinted text looks like, here's a screenshot [2]. This currently relies on setting the environment variable `FREETYPE_PROPERTIES=truetype:interpreter-version=35`, possibly some other configuration through fontconfig, and using a font with good hinting instructions (eg, DejaVu Sans and DejaVu Sans Mono in the screenshot).
My suspicion is that Windows moved away from font hinting after XP because it's very hard to create fonts with good sets of hinting instructions (aiui, OTF effectively only allows something like "autohinting"), so in the modern world of designer fonts it's easier to just have everyone look at blurry text. Some other minor reasons would be that UI scaling in Windows sometimes (or always?) introduces blurring anyway, and viewing raster images on screens of varying resolutions also introduces scaling blur.
[0] Windows still has a way to enable it, but it disables antialiasing at the same time. This is using an option called "Smooth edges of screen fonts" in "Performance Options"). This basically makes it look like XP, which imo is an improvement, but not as good as FreeType which can do hinting and antialiasing at the same time.
> In addition, before the integration into Chromium, we ran a wide set of pixel comparisons in Skia, comparing FreeType rendering to Skrifa and Skia rendering to ensure the pixel differences are absolutely minimal, in all required rendering modes (across different antialiasing and hinting modes).
I'm hoping (but not sure) Skrifa will support hinting (though I'm not sure how it interacts with fontconfig). I noticed your screenshot uses full hinting (a subjective choice I currently don't use on my machines), presumably with integer glyph positioning/advance which isn't scale-independent (neither is Windows GDI), though this is quite a nonstandard configuration IMO.
I really want hinting, subpixel and anti-aliasing available on all systems, and i want to pick the appropriate set of techniques based on the dpi and font size to minimize error, fuzzy excesses, and balance computation cost. Obviously we still don't all have high DPI all the time and likely won't for a long while. Apple dropping support was a disaster, and I currently run Apple devices plugged into to regular DPI screens with a slightly downsized resolution to trick it into rendering in a sane way, but it's a bonkers process that's also expensive and unnecessary for non-font paint work.
That said, one of the horrors of using the old font stacks, and in many ways the very thing that drove me away from fighting Linux desktop configurations for now about 10y of freedom from pain, was dealing with other related disasters. First it's a fight to even get to things being consistent, and as seen in your screenshot there's inconsistency between the content renders, the title, and the address bar. Worse though the kerning in `Yes` in your screenshot is just too bad for constant use for me.
I hope as we usher in a new generation of font tech, that we can finally reach consistency. I really want to see these engines used on Windows and macOS as well, where they're currently only used as fall-back, because I want them to present extremely high quality results on all platforms, and then I can use them in desktop app work and stop having constant fights with these subsystems. I'm fed up with it after many decades, I just want to be able to recommend a solution that works and have those slowly become the consistently correct output for everyone everywhere.
And there are internal calculators that tell you how much CPU, memory, network etc a SWE-year gets you. Same for other internal units, like the cost of a particular DB.
This allows you to make time/resource tradeoffs. Spending half an engineer’s year to save 0.5 SWE-y of CPU is not a great ROI. But if you get 10 SWE out of it, it’s probably a great idea.
I personally have used it to argue that we shouldn’t spend 2 weeks of engineering time to save a TB of DB disk space. The cost of the disk comes to less than a SWE-hour per year!
Note that this can lead to horrid economics for the user.
An example being Google unilaterally flipping on VP8/VP9 decode, which at that time purely decoded on the CPU or experimentally on the GPU.
It saved Google a few CPU cycles and some bandwidth but it nuked every user's CPU and battery. And the amount of energy YouTube consumed wholesale (so servers + clients) skyrocketed. Tragedy of the Commons.
There's definitely some nuance around how many resources to consume at the client vs the server. Video decoding and ML inference are probably at the extreme end of what you can make a client do.
On the whole, since clients are so constrained, it usually pays to be efficient there - make websites load quickly to increase revenue, require only weak hardware to get more game/app sales, etc. Clients are also untrusted, so there's so many things you can only do on the backend.
I think what they're suggesting is that yes, Google spent some SWE hours to implement it, but they have (or will, over time) saved more than that in equivalent compute (by pushing it onto users). So, from Google's point of view, they saved SWE hours on the company balance sheet, so it's a win.
But from the larger point of view of "everyone," this actually made the total cost worse. The cost/benefit analysis from Google's point-of-view was worth it, even though it made things overall worse in the larger perspective. Hence "tragedy of the commons," where the short-sighted behavior of some actors makes things worse overall.
I'm don't think that metric applies here - "SWE years" is when you want for determine whether investing in certain optimisation is worth doing.
In case of VP9, there was no such tradeoff - it used more storage, more CPU time and age SWE hours. What it saved was a very clearly quantifiable financial cost of bandwidth and SWE hour tradeoff didn't have much to do with it.
It would be applicable if the debate would be investing engineering time to speed up VP9 encoder for example.
They did this during the period where Chrome was eating into Firefox usage, after telling Mozilla that they would drop H.264 in favor of open codecs but never keeping that promise. Here’s some period discussion:
What this meant in practice was that Firefox would play YouTube videos at close to 100% CPU and Chrome would use H.264 and play at like 5% CPU, and since it was VP8 the quality was noticeably worse than H.264 as well. Regular people talked about that a lot, and it helped establish Chrome’s reputation for being faster.
This is also extremely extremely common in engineering services contracts, both for government and private sector contracting. RFPs (or their equivalent) will specifically lay out what level of effort is expected and will often denote effort in terms of FTE
Yeap, kinds of. It's preferred because whenever you propose/evaluate some changes, you can have a rough idea whether it was worth the time. Like you worked on some significant optimization then measure it and justify like the saving was 10 SWE-years where you just put 1 SWE-quarter.
Yes, all those well paid C-level managers cannot handle multiple units so they require everyone to use one “easy to understand unit so that everything is easy to compare and micromanage”
Yep, often things are measured in FTE or FTE-equivalent units. It’s not precise of course but is a reasonable shorthand for the amount of work required.
It means it costs them three months per year per employee. So, 'n' employees, n/4 years of man-power is spent fixing issues found by fuzzing. As others have said, FTE (full-time equivalent) is the more common name.
> Fonts are passed through the OpenType Sanitizer prior to processing.
Are font formats so bad that the files need to be sanitized?
Also, note that the identified integer overflows as one of causes of vulnerabilities. It is sad that today many languages do not detect overflows, and even modern architectures like RISC-V do not include overflow traps although detecting an overflow doesn't require many logic gates. C is old, ok, but why new languages like Rust do not have overflow traps, I cannot understand. Don't Rust developers know about this thing?
Rust traps on overflow in debug mode, and does two’s compliment overflow in release mode. You can turn the traps on in release if you wish, but the cost is deemed too expensive to do so by default, especially when bounds are always checked, so it isn’t as severe of an issue in Rust.
This is the true power of Rust that many are missing (like Microsoft with its TypeScript rewrite in Go): a gradual migration towards safety and the capability of being embedded in existing project.
You don't have to do the Big Rewrite™, you can simply migrate components one by one instead.
> like Microsoft with its TypeScript rewrite in Go
My understanding is that Microsoft chose Go precisely to avoid having to do a full rewrite. Of all the “modern” native/AoT compiled languages (Rust, Swift, Go, Zig) Go has the most straightforward 1:1 mapping in semantics with the original TypeScript/JavaScript, so that a tool-assisted translation of the whole codebase is feasible with bug-for-bug compatibility, and minimal support/utility code.
It would be of course _possible_ to port/translate it to any language (Including Rust) but you would essentially end up implementing a small JavaScript runtime and GC, with none or very little of the safety guarantees provided by Rust. (Rust's ownership model generally favors drastically different architectures.)
No, it was absolutely about the effort needed to rewrite the project. They couldn't afford a rewrite, only a port. They're not going to keep maintaining the Typescript version once they have transitioned to the Go version.
In a similar way Rust can be very useful for the hot path in programs written in Python, Ruby, etc. You don't have to throw out and rewrite everything, but because Rust can look like C you can use it easily anywhere C FFI is supported.
IIUC word tearing in Java cannot cause arbitrary memory corruption. Any read is guaranteed to see either the old value, or the new value, or half of each. Since these are just numbers we're talking about, not pointers, and the language doesn't otherwise allow memory-unsafe things like pointer arithmetic, a data race resulting in word tearing in Java can at worst result in a runtime crash or a logic bug, not arbitrary memory corruption.
By contrast, in Go, all it takes to cause full-blown undefined behavior, in the same sense as C or C++ or Rust, is accessing an interface/map/slice value in a racy way, not having the race detector on, and being sufficiently unlucky.
I agree that in practice this doesn't stop people from calling Go a memory-safe language. I think it's reasonable to argue that this statement is just wrong. That said, I think the Carbon people once said something along the lines of, in their experience, it's rare in practice for memory corruption bugs in C++ to be caused solely by data races. So a language that's memory-safe in single-threaded contexts, but where concurrency is not memory-safe, is "good enough". Maybe it's the same in Go.
I am still suspicious of this, though. Maybe it's just that concurrent operations are rarer in general because they're so famously hard to get right, and this makes it less likely that you'll have one that's exactly the right kind of wrong to cause memory corruption. Certainly it seems at odds with the notion that you want the exceptions to memory safety to be auditable.
Yes, you are correct that Java's guarantee is stronger.
> By contrast, in Go, all it takes to cause full-blown undefined behavior, in the same sense as C or C++ or Rust
It's a little more tricky than that. UB in C/C++/Rust is something that the compiler can use to transform the code. This can lead to other issues. Go's compiler will not do those kinds of things. So on one hand, yes, it can lead to arbitrary Bad Things, but on the other hand, it is different.
> Maybe it's the same in Go.
I was having a discussion about this topic last week, regarding Uber's paper from a few years back trying to analyze the prevalence of these issues: https://news.ycombinator.com/item?id=43336293 You'll notice the person replying to me has pointed out some additional mitigations that have happened since.
There is a real practical problem with the dichotomy in Go unfortunately, where on the one hand a single threaded program is safe, but on the other hand no go programs are single threaded. More mitigations are coming and synctest for example is quite welcome and is already helping where we've tested it, but this stuff just feels like the same old whack-a-mole as e.g. fuzzing for other solutions. gvisors checklocks for example isn't tenable for us without hugely more investment as there are tons of cases it just can't handle (like inline funcs, which we have more than we ought to). You're right that it's different, though - data races are often much harder to discover, arrange and leverage.
We've witnessed memory corruption events (from plain go code), and it's raised real concerns even among our strongest advocates. Our most recent case was actually a false-positive, in that there was a real race on a map, but it so happened it would never have reached a data race - still it tore down a process in production, and this is good and bad on multiple fronts. It doesn't make the solution invalid, and no one should be throwing internet punches over it, but it's absolutely reasonable to be concerned about memory corruption cases in complex go programs. In general my advice for Go usage is to write small programs with low concurrency and small heaps, this manages associated risks well, both in terms of authorship and exposure when events come up. Small container sized things are probably fine, essentially, but many tens of gb of user data in heaps with hundreds of constantly changed kloc is a place to be genuinely concerned.
Reflecting back on the starting context, and this advice, they align. The compiler has no high value user data to corrupt, if it suffers memory corruption the bad cases have to be pretty lucky not to end up in sufficiently total failure as to cause true end user problems. The runtime is short lived and compartmentalized, and it's not in a highly adversarial environment - this is a fine fitting use case. In an attacker heavy situation like the font system though, essentially I'm almost ready to drop maybe one layer of sandboxing once it's implemented with stronger guarantees and had some appropriate testing. I'm not sure I'd be ready to say that with less safety guarantees.
Java only has tearing for double and long, which are POD types and so are irrelevant to memory safety. Go has tearing for pointer-like objects (interfaces, slices), which causes the memory safety problems.
Data races on those pointer-like objects are undefined behavior in Go, whereas there isn't something comparable in Java. The reason why Go is considered a memory safe language is actually pretty mundane: it's simply that the data race issues are pretty hard to exploit in practice for a variety of reasons.
It's been quite a while since I worked with golang details but I seem to remember writes to the same map from multiple goroutines being UB if GOMAXPROCS>1? Did they eventually solve that, or is that excluded from the definition of memory-safe language because it's a different type of safety?
This is my understanding (both that that can occur, and that it does not count as memory safe).
I called out the types I did in my post specifically because they're the types where data races can result in arbitrary memory corruption (in the actual implementation, the spec is arguably not even that strict). Per https://go.dev/ref/mem#restrictions (the same linke as in Steve's reply to me)
So, there's Skia. Skia is a high-level library that converts texts to glyph indices, does high-level text layout, and caches glyphs (and it also makes GPU calls). But the actual parsing of the font file and converting glyphs to bitmaps happens below in FreeType.
Skia is made in C++. It's made by Google.
There's FreeType. It actually measures and renders glyphs, simultaneously supporting various antialiasing modes, hinting, kerning, interpreting TrueType bytecode and other things.
FreeType is made in C. It's not made by Google.
Question: why was it FreeType that got a Rust rewrite first?
Perhaps since FreeType is the one handling the more untrusted inputs (the font files themselves, downloaded from who-knows-where), it is more at-risk and thus stood to benefit from the conversion more?
But I don't really know anything about how all the parts fit together; just speculating.
Format parsing is generally considered some of the most risky type of code to have for memory safety. Skia is probably considered a less risky problem domain.
I've recently been learning about how fonts render based on subpixel layouts in monitor panels. Windows assumes that all panels use RGB layout, and their ClearType software will render fonts with that assumption in mind. Unfortunately, this leads to visible text fringing on new display types, like the alternative stripe pattern used on WOLED monitors, or the triangular pattern used on QD-OLED.
Some third-party tools exist to tweak how ClearType works, like MacType[1] or Better ClearType Tuner[2]. Unfortunately, these tools don't work in Chrome/electron, which seems to implement its own font rendering. Reading this, I guess that's through FreeType.
I hope that as new panel technologies start becoming more prevalent, that somebody takes the initiative to help define a standard for communicating subpixel layouts from displays to the graphics layer, which text (or graphics) rendering engines can then make use of to improve type hinting. I do see some efforts in that area from Blur Busters[3] (the UFO Test guy), but still not much recognition from vendors.
Note I'm still learning about this topic, so please let me know if I'm mistaken about any points here.
I'm pretty sure windows dropped subpixel anti-aliasing a few years ago. When it did exist there was a wizard to determine and set the subpixel layout.
Personally I don't bother anymore anyway since I have a HiDPI display (about 200dpi, 4K@24"). I think that's a better solution, simply have enough pixels to look smooth. It's what phones do too of course.
To be clear: Windows still does subpixel rendering, and the wizard is still there. The wizard has not actually worked properly for at least a decade at this point, and subpixel rendering is always enabled, unless you use hacks or third-party programs.
DirectWrite doesn’t apply subpixel anti-aliasing by default [0], and an increasing number of applications use it, including Microsoft Office since 2013. One reason is the tablet mode starting with Windows 8, because subpixel ClearType only works in one orientation. Nowadays non-uniform subpixel layouts like OLED panels use are another reason.
macOS dropped it a few years ago, primarily because there are no Macs with non-HiDPI displays any more (reducing benefit of subpixel AA) and to improve uniformity with iOS apps running on macOS via Catalyst (iOS has never supported subpixel AA, since it doesn’t play nice with frequently adjusted orientations).
Windows I believe still uses RGB subpixel AA, because OLED monitor users still need to tweak ClearType settings to make text not look bad.
> because there are no Macs with non-HiDPI displays any more
That is not true. Apple still sells Macs that don't come with a screen, namely Mac Mini, Mac Studio, and Mac Pro. People use these with non-HiDPI monitors they already own all the time.
That's not really the most charitable reading of GP's comment. I think they very clearly mean that Apple does not sell Macs with non-HiDPI displays anymore. It's not a configuration they sell, so they don't need to support those features anymore in their current offerings.
You're right that there's nothing stopping someone from hooking up an HDMI-to-VGA adapter for their 22" Trinitron from 2001, but that doesn't mean boat anchors are a meaningful market segment. It's not a consideration for why they should retain a font rendering feature for a modern OS. You're just going to have to suffer with fuzzy fonts for your retrogaming hobby.
So what is the "configuration they sell" for the desktop Macs? The Studio Display that costs way too much for what it is, so to no one's surprise, they're not selling all that many of those? Or the Pro Display XDR for which the stand alone costs more than an entry-level Mac Mini? Sure no one will buy a $1600 monitor to use with their $600 Mac Mini. They'll get a much cheaper third-party 2K one.
Apple put all their chips behind Retina/HiDPI displays. To that end, they've got really good HiDPI resolution scaling, they no longer sell displays incapable of Retina features (in laptops or stand-alone), and they have removed features that only serve to support sub-4k displays. To Apple, 4k is the minimum standard.
If you want a 2k monitor you can buy one and hook it up, but Apple isn't interested in making it look good. It's a not new decision, either. They stopped selling Macbooks without Retina displays in 2016. They haven't supported 2k scaling since the M1 Mac Mini over 5 years ago: https://www.macworld.com/article/549493/how-to-m1-mac-1440p-...
Apple is not a budget vendor. They're a premium vendor. That's not just what other people call them. It's what they themselves profess to be. That's why you can get an Apple Thunderbolt cable for $70. To Apple, if you buy a Mac Mini, yes they're expecting you to hook it up to a 4k monitor. They expect you to be getting a Mac Mini because you want a Mac, not because you can't afford a Macbook.
Well, in my particular case, I use an M1 Max MBP with a 2K monitor that I already had when I bought the MacBook.
The problem with 27" 4K monitors is that you can't have integer scaling on them. If you set the scaling factor to 1x, everything will be too small, if you set it to 2x, everything will be huge, and macOS can't properly do fractional scaling because what it actually does is render everything into a 2x framebuffer and downscale that for output.
And besides, only supporting HiDPI displays doesn't mean one can stop striving for pixel perfection. I hate SF Symbols icons because they're sizeless. They're an abhorrent blurry mess on my monitor but they're also not all that sharp on the MacBook screen. If you notice it once, it'll haunt you forever. Sorry. They do look fine-ish on iPhones though because those use OLED displays that lack the notion of a pixel grid anyway.
Since you are so sure about how Mac Mini's are used, is it 2k on 24" or 27" that these customers use?
My impressions based on limited anecdotal data I've is that most people with mac mini are using it as their secondary device (everyone has a Macbooks). Everyone is using 27" 4k monitors. 4k monitors are not that far from 2k monitors, and I think most people who are preferring to buy 2k are gamers that want higher refresh rate that their GPU can support at 2k. But gamers are not using Mac's anyway.
They don't sell it as part of the configuration options.
You can separately purchase whatever monitor you wish. There are now plenty of 27" 5K monitors out there. Asus, LG (for now), Viewsonic, Kuycon, others I'm probably forgetting. They're expensive as far as monitors go, but not as expensive as the Studio Display.
Sure, but they’re not going to optimize for that case because the bulk of their Mac sales are tied up in their laptops and a significant chunk (I’d hazard a guess over 50%) of people buying Studios/Pros especially but also Minis are pairing them with Studio Displays, Pro Display XDRs, or more recently the various third-party 2x HiDPI display offerings from the likes of Asus, BenQ, Dell, and Samsung.
They’re fine to my eye, at least as good as well tuned freetype (as found on Ubuntu) as long as you’re either using a 2x HiDPI display or are using a “normal” DPI monitor with above average density (e.g. 2560x1440 27”) and have subpixel AA forced on.
Where it falls apart is at densities any lower, for example it struggles on those awful 1366x768 15.6” panels that it seemed like every other laptop was built with for a while. Similarly 24” 1080p and 32” 2560x1440 are pretty bad.
It absolutely still does subpixel AA. Take a screenshot of any text and zoom way in, there's red and blue fringing. And the ClearType text tuner is still a functional builtin program in Win11 24H2.
I still have subpixel antialiasing on when using a 28" 4K display. It's the same DPI as a FHD 14" display, typical on laptops. Subpixel AA makes small fonts look significantly more readable.
But it only applies to Linux, where the small fonts can be made look crisp this way. Windows AA is worse, small fonts are a bit more blurred on the same screen, and amcOS is the worst: connecting a 24" FHD screen to an MBP ives really horrible font rendering, unless you make fonts really large. I suppose it's because macOS does not do subpxel AA at all, and assumes high DPI screens only.
As far as I'm aware, ClearType is still enabled by default in Windows.
Subpixel text rendering was removed from MacOS some time ago, though, presumably because they decided it was not needed on retina screens. Maybe you're thinking of that?
The standard is EDID-DDDB, and subpixel layout is a major part of that specification. However I believe display manufacturers are dropping the ball here.
For me, being old time user, (ab)using any subpixel layouts for text rendering and antialiasing is counterproductive and (especially with current pixel densities, but also in general) introduces much more issues that it actually ever solved
“Whole pixel/grayscale antialiasing” should be enough and then specialized display controller would handle the rest
Agreed, but layouts such as Pentile don't actually have all three subpixel components in a logical pixel, so you'll still get artifacts even with grayscale AA. You can compensate for this by masking those missing components.
surprising info, I thought this was supposed to be the part about "display controller taking care of any additional issues", thanks for link with details, will read it with interest
I may be totally off the mark here, but my understanding is that the alternative pixel arrangements found in current WOLED and QD-OLED monitors are suboptimal in various ways (despite the otherwise excellent qualities of these displays) and so panel manufacturers are working towards OLED panels built with traditional RGB subpixel arrangements that don’t forfeit the benefits of current WOLED and QD-OLED tech.
That being the case, it may end up being that in the near future, alternative arrangements end up being abandoned and become one of the many quirky “stepping stone” technologies that litter display technology history. While it’s still a good idea to support them better in software, that might put into context why there hasn’t been more efforts put into doing so.
Sub-pixel anti-aliasing requires outputing a pixel-perfect image to the screen, which is a challenge when you're also doing rendering on the GPU. You generally can't rely on any non-trivial part of the standard 3D-rendering pipeline (except for simple blitting/compositing) and have to use the GPU's compute stack instead to address those requirements. This adds quite a bit of complexity.
I wonder what this means, if anything, for the future of WUFFS. TTF support is on their roadmap. If they can get acceptable performance and safety from Rust, will they still drive on with WUFFS?
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.
> 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.
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].
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.
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
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".
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").
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.
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.
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.
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.
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
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.
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".
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.
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.
It's very annoying that Google's websites, including this blog, are automatically translated to my browser's preferred language.
Sillicon Valley devs clearly believe that machine translation is a magical technology that completely solved internationalization, like in Star Trek. No, it's far from it. Ever since internet has been flooded with automatically translated garbage, the experience of international users, at least bilingual ones, got much worse.
The worst offender to me is Google Maps. I'm a native Spanish speaker but set my phone to English because I hate app translations. The problem is when I want to read reviews it automatically translates them from Spanish (my native language) to English. It doesn't make any sense!
Hey, at least it's preferred language. It's much worse when it bases it on the country that I'm in, which I can only reasonably influence with a VPN, and calling that reasonable is a stretch.
This is the worst. I was in France recently and tons of mobile websites were just suddenly in French. It was a real chore to read through them, and I can only imagine how frustrating this is when you can't read the language put in front of you at all.
The thing I don't get is that there are plenty of Googlers traveling internationally. They've been aware of the problem for over a decade now, yet it persists. If I'm traveling from Spain to Poland with a browser set to use UK-English, why would the site immediately switch to Polish? It makes no sense that this common corner case isn't addressed at all after all this time.
At the very least sites that do this should detect that there's a mismatch between expected language given geolocation and the header and have a toast notification about how to change the language settings back manually.
I keep setting all my preferences *everywhere* to English, yet 50% of the time google search results are 100% Finnish. With a helpful "change to English" link that does not work.
Worst still Google Maps will insist on only showing street names, area names, an directions in Swedish.
Strong agree. I had worked at Google for four years before discovering that the API documentation I meticulously wrote was machine translated to other languages. Only by perusing these translations did I realize some API concepts had been translated; I had to overuse the backtick notation for code to suppress these translations.
This is not a just Silicon Valley problem though; Redmond had similar issues if you just use the newer parts of Windows in a non-English language.
Wouldn't the alternative be worse for most people?
If you're a global company it would be silly to assume all your readers speak/read a single language. AI translations (assuming that's what this is) are not perfect, but better than nothing.
I get how poor translation could be irritating for bilingual people who notice the quality difference though, but I guess you guys have the advantage of being able to switch the language.
I have `en-US` set as the second preference language, so just show me the content in `en-US` unless you have a real human-vetted translation into my primary language.
Look, a language that was conceived out of necessity to write a web browser in a safer way is being used just for that. It's a different, unrelated browser, but the language still reaches its design goals beautifully.
I get it, but switching to Rust places the codebase on an Island I can't easily get to. I am already switching between C++, Swift, Kotlin, and Python on an almost daily basis.
Was this a codebase you were working with regularly already? This project exposes a C FFI, so unless you were already working in the guts here, I don't think this should affect you terribly.
edit: I'm actually not seeing the C FFI, looking at the library. It must be there somewhere, because it's being used from a C++ codebase. Can somebody point to the extern C use? I'm finding this inside that `fontations` repository:
For me it was already hard to get into chromium's code base. It takes too long to build and there's just so much to understand about it before you can make changes.
It might help if there was some way to play around with the APIs without having to wait so long for it to build. But as far as i know that's not currently possible.
It is not a matter of understanding source code. It is matter of bridging, building, and linking another language with yet another binary layout and interface.
The best libraries are libraries that have a clearly defined goal, hit that goal, and then don't change until the goalposts get moved. Something that happens only very slowly in font land.
Its age is completely irrelevant other than as demonstration that it did what it set out to do, and still performs that job as intended for people who actually work on, and with fonts.
I don't think you understand how backwards it is.
My patch that makes SDF rendering 4x faster was not accepted, presumably because floating point-maths is some strange new-fangled technology. Freetype uses antiquated fixed-point integer maths everywhere. See https://gitlab.freedesktop.org/freetype/freetype/-/merge_req...
Did you check to see if Freetype supports platforms that don't have floating-point math, or where it's very slow? I agree that fixed-point math is unnecessary on modern hardware and architectures, but they may prioritize support for hardware you don't personally care about.
Sure, a compile-time option to use one or the other might sound reasonable, but then that's two different code paths that need to be maintained and tested. Are you willing to do that maintenance on an ongoing basis?
And can you be certain that switching to floating-point doesn't change the results of calculations in various ways that actually matter for rendering? Are you willing to put in the time to test that thoroughly?
Instead of engaging with the developer, you just ignored them and moved on. I certainly wouldn't want to merge a patch into one of my projects if it came from someone with your attitude.
I know how to read, and that MR comment sounds 100% reasonable to me. Normally you'd take a comment like that, go "oh, okay let me do some more investigations" and start a dialog instead of going "they rejected my MR on the first pass, they don't know what they're doing and their library is antiquated".
Because to be a clear: a reviewer comment is the start of the conversation, if you don't respond then the bad actor is you, not them. Ask them why they don't want to use math.h, ask them if there are dev documents that explain what can and can't be used, and why. If you don't, this failure is on you, not them.
I hope that if we switch away from FreeType, we'll still have a way to use TTF hinting instructions fully.
Windows/macOS don't seem to have a way to enable proper hinting anymore [0], and even FreeType (since 2.7 [1]) defaults to improper hinting (they call it "subpixel hinting", which doesn't make sense to me in theory, and practically still seems blurry, as if it's unhinted).
In case anyone's wondering what properly hinted text looks like, here's a screenshot [2]. This currently relies on setting the environment variable `FREETYPE_PROPERTIES=truetype:interpreter-version=35`, possibly some other configuration through fontconfig, and using a font with good hinting instructions (eg, DejaVu Sans and DejaVu Sans Mono in the screenshot).
My suspicion is that Windows moved away from font hinting after XP because it's very hard to create fonts with good sets of hinting instructions (aiui, OTF effectively only allows something like "autohinting"), so in the modern world of designer fonts it's easier to just have everyone look at blurry text. Some other minor reasons would be that UI scaling in Windows sometimes (or always?) introduces blurring anyway, and viewing raster images on screens of varying resolutions also introduces scaling blur.
[0] Windows still has a way to enable it, but it disables antialiasing at the same time. This is using an option called "Smooth edges of screen fonts" in "Performance Options"). This basically makes it look like XP, which imo is an improvement, but not as good as FreeType which can do hinting and antialiasing at the same time.
[1] https://freetype.org/freetype2/docs/hinting/subpixel-hinting...
[2] https://gist.githubusercontent.com/Maxdamantus/3a58d8e764b29...
> In addition, before the integration into Chromium, we ran a wide set of pixel comparisons in Skia, comparing FreeType rendering to Skrifa and Skia rendering to ensure the pixel differences are absolutely minimal, in all required rendering modes (across different antialiasing and hinting modes).
I'm hoping (but not sure) Skrifa will support hinting (though I'm not sure how it interacts with fontconfig). I noticed your screenshot uses full hinting (a subjective choice I currently don't use on my machines), presumably with integer glyph positioning/advance which isn't scale-independent (neither is Windows GDI), though this is quite a nonstandard configuration IMO.
I really want hinting, subpixel and anti-aliasing available on all systems, and i want to pick the appropriate set of techniques based on the dpi and font size to minimize error, fuzzy excesses, and balance computation cost. Obviously we still don't all have high DPI all the time and likely won't for a long while. Apple dropping support was a disaster, and I currently run Apple devices plugged into to regular DPI screens with a slightly downsized resolution to trick it into rendering in a sane way, but it's a bonkers process that's also expensive and unnecessary for non-font paint work.
That said, one of the horrors of using the old font stacks, and in many ways the very thing that drove me away from fighting Linux desktop configurations for now about 10y of freedom from pain, was dealing with other related disasters. First it's a fight to even get to things being consistent, and as seen in your screenshot there's inconsistency between the content renders, the title, and the address bar. Worse though the kerning in `Yes` in your screenshot is just too bad for constant use for me.
I hope as we usher in a new generation of font tech, that we can finally reach consistency. I really want to see these engines used on Windows and macOS as well, where they're currently only used as fall-back, because I want them to present extremely high quality results on all platforms, and then I can use them in desktop app work and stop having constant fights with these subsystems. I'm fed up with it after many decades, I just want to be able to recommend a solution that works and have those slowly become the consistently correct output for everyone everywhere.
> Merely keeping up with the stream of issues found by fuzzing costs Google at least 0.25 full time software engineers
I like this way of measuring extra work. Is this standard at Google?
Yes, a SWE-year is a common unit of cost.
And there are internal calculators that tell you how much CPU, memory, network etc a SWE-year gets you. Same for other internal units, like the cost of a particular DB.
This allows you to make time/resource tradeoffs. Spending half an engineer’s year to save 0.5 SWE-y of CPU is not a great ROI. But if you get 10 SWE out of it, it’s probably a great idea.
I personally have used it to argue that we shouldn’t spend 2 weeks of engineering time to save a TB of DB disk space. The cost of the disk comes to less than a SWE-hour per year!
Note that this can lead to horrid economics for the user.
An example being Google unilaterally flipping on VP8/VP9 decode, which at that time purely decoded on the CPU or experimentally on the GPU.
It saved Google a few CPU cycles and some bandwidth but it nuked every user's CPU and battery. And the amount of energy YouTube consumed wholesale (so servers + clients) skyrocketed. Tragedy of the Commons.
There's definitely some nuance around how many resources to consume at the client vs the server. Video decoding and ML inference are probably at the extreme end of what you can make a client do.
On the whole, since clients are so constrained, it usually pays to be efficient there - make websites load quickly to increase revenue, require only weak hardware to get more game/app sales, etc. Clients are also untrusted, so there's so many things you can only do on the backend.
How is that related to the tradeoff calculation at hand?
Implementing VP9, enabling it, transcoding videos and testing it COST SWE hours, it didn't save them. It also cost resources.
In what way did you envision the VP9 issue being related to SWE/resource hour computations here?
I think what they're suggesting is that yes, Google spent some SWE hours to implement it, but they have (or will, over time) saved more than that in equivalent compute (by pushing it onto users). So, from Google's point of view, they saved SWE hours on the company balance sheet, so it's a win.
But from the larger point of view of "everyone," this actually made the total cost worse. The cost/benefit analysis from Google's point-of-view was worth it, even though it made things overall worse in the larger perspective. Hence "tragedy of the commons," where the short-sighted behavior of some actors makes things worse overall.
I'm don't think that metric applies here - "SWE years" is when you want for determine whether investing in certain optimisation is worth doing.
In case of VP9, there was no such tradeoff - it used more storage, more CPU time and age SWE hours. What it saved was a very clearly quantifiable financial cost of bandwidth and SWE hour tradeoff didn't have much to do with it.
It would be applicable if the debate would be investing engineering time to speed up VP9 encoder for example.
It also saved licensing costs to MPEG-LA too I guess.
Do you have an article about this? What is the state now?
They did this during the period where Chrome was eating into Firefox usage, after telling Mozilla that they would drop H.264 in favor of open codecs but never keeping that promise. Here’s some period discussion:
https://www.osnews.com/story/24263/google-h264-stifles-innov...
What this meant in practice was that Firefox would play YouTube videos at close to 100% CPU and Chrome would use H.264 and play at like 5% CPU, and since it was VP8 the quality was noticeably worse than H.264 as well. Regular people talked about that a lot, and it helped establish Chrome’s reputation for being faster.
Pretty much every device these days decodes VP9 in hardware.
It's been a long time since I've seen a VP8 video on YT, so I'd assume it's not even used anymore due to worse compression.
FTE. Full time equivalent. Mosts costs are denominated in FTE - headcount as well as things like CPU/memory/storage/...
The main economic unit for most engineers is FTE not $.
This is also extremely extremely common in engineering services contracts, both for government and private sector contracting. RFPs (or their equivalent) will specifically lay out what level of effort is expected and will often denote effort in terms of FTE
Technically a measure of power, work/time.
Yeap, kinds of. It's preferred because whenever you propose/evaluate some changes, you can have a rough idea whether it was worth the time. Like you worked on some significant optimization then measure it and justify like the saving was 10 SWE-years where you just put 1 SWE-quarter.
Yes, all those well paid C-level managers cannot handle multiple units so they require everyone to use one “easy to understand unit so that everything is easy to compare and micromanage”
Yep, often things are measured in FTE or FTE-equivalent units. It’s not precise of course but is a reasonable shorthand for the amount of work required.
I think this means the engineer fuzzes 4 projects?
It means it costs them three months per year per employee. So, 'n' employees, n/4 years of man-power is spent fixing issues found by fuzzing. As others have said, FTE (full-time equivalent) is the more common name.
> Fonts are passed through the OpenType Sanitizer prior to processing.
Are font formats so bad that the files need to be sanitized?
Also, note that the identified integer overflows as one of causes of vulnerabilities. It is sad that today many languages do not detect overflows, and even modern architectures like RISC-V do not include overflow traps although detecting an overflow doesn't require many logic gates. C is old, ok, but why new languages like Rust do not have overflow traps, I cannot understand. Don't Rust developers know about this thing?
Rust traps on overflow in debug mode, and does two’s compliment overflow in release mode. You can turn the traps on in release if you wish, but the cost is deemed too expensive to do so by default, especially when bounds are always checked, so it isn’t as severe of an issue in Rust.
This is the true power of Rust that many are missing (like Microsoft with its TypeScript rewrite in Go): a gradual migration towards safety and the capability of being embedded in existing project.
You don't have to do the Big Rewrite™, you can simply migrate components one by one instead.
> like Microsoft with its TypeScript rewrite in Go
My understanding is that Microsoft chose Go precisely to avoid having to do a full rewrite. Of all the “modern” native/AoT compiled languages (Rust, Swift, Go, Zig) Go has the most straightforward 1:1 mapping in semantics with the original TypeScript/JavaScript, so that a tool-assisted translation of the whole codebase is feasible with bug-for-bug compatibility, and minimal support/utility code.
It would be of course _possible_ to port/translate it to any language (Including Rust) but you would essentially end up implementing a small JavaScript runtime and GC, with none or very little of the safety guarantees provided by Rust. (Rust's ownership model generally favors drastically different architectures.)
As I understood their arguments it was not about the effort needed to rewrite the project.
It was about being able to have two codebases (old and new) that are so structurally similar, that it won't be a big deal to keep updating both
No, it was absolutely about the effort needed to rewrite the project. They couldn't afford a rewrite, only a port. They're not going to keep maintaining the Typescript version once they have transitioned to the Go version.
Hi, I lead Chrome's Rust efforts. I think the Typescript folks made a great and well-reasoned decision.
Thank you, it's really nice seeing cooler heads prevail on the question of "why didn't they build in my favourite thing X?"
In entirely unrelated news, I think Chrome should totally switch engines from V8 to a Rust built one, like hmm... our / my Nova JavaScript engine! j/k
Great stuff on the font front, thank you for the articles, Rust/C++ interop work, and keep it up!
In a similar way Rust can be very useful for the hot path in programs written in Python, Ruby, etc. You don't have to throw out and rewrite everything, but because Rust can look like C you can use it easily anywhere C FFI is supported.
> like Microsoft with its TypeScript rewrite in Go
Go is also memory safe.
I'd argue technically not due to data races on interface values, maps, slices, and strings... but close enough for almost all purposes.
PS. Note that unlike most languages, a datarace on something like an int in go isn't undefined behavior, just non-deterministic and discouraged.
Yes, these issues are real, but as you say, it's not really the same as UB. As such, Go is generally considered a MSL.
For anyone not familiar with this, see https://go.dev/ref/mem#restrictions
Incidentally, Java is very similar: https://docs.oracle.com/javase/specs/jls/se8/html/jls-17.htm...
IIUC word tearing in Java cannot cause arbitrary memory corruption. Any read is guaranteed to see either the old value, or the new value, or half of each. Since these are just numbers we're talking about, not pointers, and the language doesn't otherwise allow memory-unsafe things like pointer arithmetic, a data race resulting in word tearing in Java can at worst result in a runtime crash or a logic bug, not arbitrary memory corruption.
By contrast, in Go, all it takes to cause full-blown undefined behavior, in the same sense as C or C++ or Rust, is accessing an interface/map/slice value in a racy way, not having the race detector on, and being sufficiently unlucky.
I agree that in practice this doesn't stop people from calling Go a memory-safe language. I think it's reasonable to argue that this statement is just wrong. That said, I think the Carbon people once said something along the lines of, in their experience, it's rare in practice for memory corruption bugs in C++ to be caused solely by data races. So a language that's memory-safe in single-threaded contexts, but where concurrency is not memory-safe, is "good enough". Maybe it's the same in Go.
I am still suspicious of this, though. Maybe it's just that concurrent operations are rarer in general because they're so famously hard to get right, and this makes it less likely that you'll have one that's exactly the right kind of wrong to cause memory corruption. Certainly it seems at odds with the notion that you want the exceptions to memory safety to be auditable.
Yes, you are correct that Java's guarantee is stronger.
> By contrast, in Go, all it takes to cause full-blown undefined behavior, in the same sense as C or C++ or Rust
It's a little more tricky than that. UB in C/C++/Rust is something that the compiler can use to transform the code. This can lead to other issues. Go's compiler will not do those kinds of things. So on one hand, yes, it can lead to arbitrary Bad Things, but on the other hand, it is different.
> Maybe it's the same in Go.
I was having a discussion about this topic last week, regarding Uber's paper from a few years back trying to analyze the prevalence of these issues: https://news.ycombinator.com/item?id=43336293 You'll notice the person replying to me has pointed out some additional mitigations that have happened since.
There is a real practical problem with the dichotomy in Go unfortunately, where on the one hand a single threaded program is safe, but on the other hand no go programs are single threaded. More mitigations are coming and synctest for example is quite welcome and is already helping where we've tested it, but this stuff just feels like the same old whack-a-mole as e.g. fuzzing for other solutions. gvisors checklocks for example isn't tenable for us without hugely more investment as there are tons of cases it just can't handle (like inline funcs, which we have more than we ought to). You're right that it's different, though - data races are often much harder to discover, arrange and leverage.
We've witnessed memory corruption events (from plain go code), and it's raised real concerns even among our strongest advocates. Our most recent case was actually a false-positive, in that there was a real race on a map, but it so happened it would never have reached a data race - still it tore down a process in production, and this is good and bad on multiple fronts. It doesn't make the solution invalid, and no one should be throwing internet punches over it, but it's absolutely reasonable to be concerned about memory corruption cases in complex go programs. In general my advice for Go usage is to write small programs with low concurrency and small heaps, this manages associated risks well, both in terms of authorship and exposure when events come up. Small container sized things are probably fine, essentially, but many tens of gb of user data in heaps with hundreds of constantly changed kloc is a place to be genuinely concerned.
Reflecting back on the starting context, and this advice, they align. The compiler has no high value user data to corrupt, if it suffers memory corruption the bad cases have to be pretty lucky not to end up in sufficiently total failure as to cause true end user problems. The runtime is short lived and compartmentalized, and it's not in a highly adversarial environment - this is a fine fitting use case. In an attacker heavy situation like the font system though, essentially I'm almost ready to drop maybe one layer of sandboxing once it's implemented with stronger guarantees and had some appropriate testing. I'm not sure I'd be ready to say that with less safety guarantees.
Java only has tearing for double and long, which are POD types and so are irrelevant to memory safety. Go has tearing for pointer-like objects (interfaces, slices), which causes the memory safety problems.
Data races on those pointer-like objects are undefined behavior in Go, whereas there isn't something comparable in Java. The reason why Go is considered a memory safe language is actually pretty mundane: it's simply that the data race issues are pretty hard to exploit in practice for a variety of reasons.
I haven’t seen any aligned double or long tearing for over 20 years on workstation or server CPUs.
Yes, I certainly agree that Java's guarantee is stronger, and that it's harder to exploit Go's issues than non-MSL's issues.
It's been quite a while since I worked with golang details but I seem to remember writes to the same map from multiple goroutines being UB if GOMAXPROCS>1? Did they eventually solve that, or is that excluded from the definition of memory-safe language because it's a different type of safety?
This is my understanding (both that that can occur, and that it does not count as memory safe).
I called out the types I did in my post specifically because they're the types where data races can result in arbitrary memory corruption (in the actual implementation, the spec is arguably not even that strict). Per https://go.dev/ref/mem#restrictions (the same linke as in Steve's reply to me)
I believe that post 1.6, the runtime will try and detect this, but it's not my area of expertise.
Java is not similar. It guarantees memory safety even for multithreaded code with data races.
It can result in stack overflows, infinite loops, but not in memory corruption.
That's not the case for Go, it's trivially easy to create memory corruption with multiple threads there.
"Similar" does not mean "the same," you are correct that Java's guarantee is stronger.
Since you've mentioned that you never see the annoying strike force threads that others complain about, you're in one.
I said that I do not see them happening at the rate that people say they happen. I never said they don't happen.
But can't be embedded in other projects as easily as Rust (FFI, WASM).
I don't disagree, but "not as easily" is different than "cannot be."
Go can have data races, so I would not consider it memory safe.
Odd comparison / statement in the context of MS rewriting GDI in Rust
You're saying choosing Go over Rust was a mistake? Why?
"If you build it they will come."
So, there's Skia. Skia is a high-level library that converts texts to glyph indices, does high-level text layout, and caches glyphs (and it also makes GPU calls). But the actual parsing of the font file and converting glyphs to bitmaps happens below in FreeType.
Skia is made in C++. It's made by Google.
There's FreeType. It actually measures and renders glyphs, simultaneously supporting various antialiasing modes, hinting, kerning, interpreting TrueType bytecode and other things.
FreeType is made in C. It's not made by Google.
Question: why was it FreeType that got a Rust rewrite first?
Perhaps since FreeType is the one handling the more untrusted inputs (the font files themselves, downloaded from who-knows-where), it is more at-risk and thus stood to benefit from the conversion more?
But I don't really know anything about how all the parts fit together; just speculating.
Skia's inputs are relatively less complex, so there is less risk of dangerous corner cases.
It has a smaller API surface into the consuming applications and platforms.
Skia tendrils run deep and leak all over the place.
There's also a different set of work to invest in, next-generation Skia is likely to look quite different, moving much of the work on to the GPU, and this work is being researched and developed: https://github.com/linebender/vello. Some presentations about this work too: https://youtu.be/mmW_RbTyj8c https://youtu.be/OvfNipIcRiQ
Format parsing is generally considered some of the most risky type of code to have for memory safety. Skia is probably considered a less risky problem domain.
You know what is even safer than all this? Not loading fonts from the web at all!
I've recently been learning about how fonts render based on subpixel layouts in monitor panels. Windows assumes that all panels use RGB layout, and their ClearType software will render fonts with that assumption in mind. Unfortunately, this leads to visible text fringing on new display types, like the alternative stripe pattern used on WOLED monitors, or the triangular pattern used on QD-OLED.
Some third-party tools exist to tweak how ClearType works, like MacType[1] or Better ClearType Tuner[2]. Unfortunately, these tools don't work in Chrome/electron, which seems to implement its own font rendering. Reading this, I guess that's through FreeType.
I hope that as new panel technologies start becoming more prevalent, that somebody takes the initiative to help define a standard for communicating subpixel layouts from displays to the graphics layer, which text (or graphics) rendering engines can then make use of to improve type hinting. I do see some efforts in that area from Blur Busters[3] (the UFO Test guy), but still not much recognition from vendors.
Note I'm still learning about this topic, so please let me know if I'm mistaken about any points here.
[1] https://github.com/snowie2000/mactype
[2] https://github.com/bp2008/BetterClearTypeTuner
[3] https://github.com/microsoft/PowerToys/issues/25595
I'm pretty sure windows dropped subpixel anti-aliasing a few years ago. When it did exist there was a wizard to determine and set the subpixel layout.
Personally I don't bother anymore anyway since I have a HiDPI display (about 200dpi, 4K@24"). I think that's a better solution, simply have enough pixels to look smooth. It's what phones do too of course.
To be clear: Windows still does subpixel rendering, and the wizard is still there. The wizard has not actually worked properly for at least a decade at this point, and subpixel rendering is always enabled, unless you use hacks or third-party programs.
DirectWrite doesn’t apply subpixel anti-aliasing by default [0], and an increasing number of applications use it, including Microsoft Office since 2013. One reason is the tablet mode starting with Windows 8, because subpixel ClearType only works in one orientation. Nowadays non-uniform subpixel layouts like OLED panels use are another reason.
[0] https://en.wikipedia.org/wiki/ClearType#ClearType_in_DirectW...
macOS dropped it a few years ago, primarily because there are no Macs with non-HiDPI displays any more (reducing benefit of subpixel AA) and to improve uniformity with iOS apps running on macOS via Catalyst (iOS has never supported subpixel AA, since it doesn’t play nice with frequently adjusted orientations).
Windows I believe still uses RGB subpixel AA, because OLED monitor users still need to tweak ClearType settings to make text not look bad.
> because there are no Macs with non-HiDPI displays any more
That is not true. Apple still sells Macs that don't come with a screen, namely Mac Mini, Mac Studio, and Mac Pro. People use these with non-HiDPI monitors they already own all the time.
That's not really the most charitable reading of GP's comment. I think they very clearly mean that Apple does not sell Macs with non-HiDPI displays anymore. It's not a configuration they sell, so they don't need to support those features anymore in their current offerings.
You're right that there's nothing stopping someone from hooking up an HDMI-to-VGA adapter for their 22" Trinitron from 2001, but that doesn't mean boat anchors are a meaningful market segment. It's not a consideration for why they should retain a font rendering feature for a modern OS. You're just going to have to suffer with fuzzy fonts for your retrogaming hobby.
> It's not a configuration they sell
So what is the "configuration they sell" for the desktop Macs? The Studio Display that costs way too much for what it is, so to no one's surprise, they're not selling all that many of those? Or the Pro Display XDR for which the stand alone costs more than an entry-level Mac Mini? Sure no one will buy a $1600 monitor to use with their $600 Mac Mini. They'll get a much cheaper third-party 2K one.
Apple put all their chips behind Retina/HiDPI displays. To that end, they've got really good HiDPI resolution scaling, they no longer sell displays incapable of Retina features (in laptops or stand-alone), and they have removed features that only serve to support sub-4k displays. To Apple, 4k is the minimum standard.
If you want a 2k monitor you can buy one and hook it up, but Apple isn't interested in making it look good. It's a not new decision, either. They stopped selling Macbooks without Retina displays in 2016. They haven't supported 2k scaling since the M1 Mac Mini over 5 years ago: https://www.macworld.com/article/549493/how-to-m1-mac-1440p-...
Apple is not a budget vendor. They're a premium vendor. That's not just what other people call them. It's what they themselves profess to be. That's why you can get an Apple Thunderbolt cable for $70. To Apple, if you buy a Mac Mini, yes they're expecting you to hook it up to a 4k monitor. They expect you to be getting a Mac Mini because you want a Mac, not because you can't afford a Macbook.
Well, in my particular case, I use an M1 Max MBP with a 2K monitor that I already had when I bought the MacBook.
The problem with 27" 4K monitors is that you can't have integer scaling on them. If you set the scaling factor to 1x, everything will be too small, if you set it to 2x, everything will be huge, and macOS can't properly do fractional scaling because what it actually does is render everything into a 2x framebuffer and downscale that for output.
And besides, only supporting HiDPI displays doesn't mean one can stop striving for pixel perfection. I hate SF Symbols icons because they're sizeless. They're an abhorrent blurry mess on my monitor but they're also not all that sharp on the MacBook screen. If you notice it once, it'll haunt you forever. Sorry. They do look fine-ish on iPhones though because those use OLED displays that lack the notion of a pixel grid anyway.
Since you are so sure about how Mac Mini's are used, is it 2k on 24" or 27" that these customers use?
My impressions based on limited anecdotal data I've is that most people with mac mini are using it as their secondary device (everyone has a Macbooks). Everyone is using 27" 4k monitors. 4k monitors are not that far from 2k monitors, and I think most people who are preferring to buy 2k are gamers that want higher refresh rate that their GPU can support at 2k. But gamers are not using Mac's anyway.
24"-ish 4K, 27" is 5K, 32" 6K. Outside of that is not HiDPI and will lead to fuzzy fonts (your eyes may vary). PPI needs to be near 220.
They don't sell it as part of the configuration options.
You can separately purchase whatever monitor you wish. There are now plenty of 27" 5K monitors out there. Asus, LG (for now), Viewsonic, Kuycon, others I'm probably forgetting. They're expensive as far as monitors go, but not as expensive as the Studio Display.
The Trinitron will blur itself at 1600x1200. The problem is the legions of low PPI 1080p LCDs in business settings.
Sure, but they’re not going to optimize for that case because the bulk of their Mac sales are tied up in their laptops and a significant chunk (I’d hazard a guess over 50%) of people buying Studios/Pros especially but also Minis are pairing them with Studio Displays, Pro Display XDRs, or more recently the various third-party 2x HiDPI display offerings from the likes of Asus, BenQ, Dell, and Samsung.
Subpixel AA for Macs is useless anyways, the fonts will look blurry no matter what you do on a Mac.
They’re fine to my eye, at least as good as well tuned freetype (as found on Ubuntu) as long as you’re either using a 2x HiDPI display or are using a “normal” DPI monitor with above average density (e.g. 2560x1440 27”) and have subpixel AA forced on.
Where it falls apart is at densities any lower, for example it struggles on those awful 1366x768 15.6” panels that it seemed like every other laptop was built with for a while. Similarly 24” 1080p and 32” 2560x1440 are pretty bad.
I didn't have to do any cleartype tuning on my LG C2. But maybe since it's a TV they have room for conventional subpixel layouts.
ohh maybe it was macOS I am confused with here. Sorry. I use every OS under the sun together.
Or it could have been the DirectWrite thing. I just don't remember where I read it.
I always thought cleartype was ugly by the way.
It absolutely still does subpixel AA. Take a screenshot of any text and zoom way in, there's red and blue fringing. And the ClearType text tuner is still a functional builtin program in Win11 24H2.
I still have subpixel antialiasing on when using a 28" 4K display. It's the same DPI as a FHD 14" display, typical on laptops. Subpixel AA makes small fonts look significantly more readable.
But it only applies to Linux, where the small fonts can be made look crisp this way. Windows AA is worse, small fonts are a bit more blurred on the same screen, and amcOS is the worst: connecting a 24" FHD screen to an MBP ives really horrible font rendering, unless you make fonts really large. I suppose it's because macOS does not do subpxel AA at all, and assumes high DPI screens only.
As far as I'm aware, ClearType is still enabled by default in Windows.
Subpixel text rendering was removed from MacOS some time ago, though, presumably because they decided it was not needed on retina screens. Maybe you're thinking of that?
It didn't. Some parts of the UI are using grayscale AA, some are on subpixel AA. And sometimes it's just a blur, to keep things fun I guess.
Pretty sure phones do grayscale AA.
The standard is EDID-DDDB, and subpixel layout is a major part of that specification. However I believe display manufacturers are dropping the ball here.
https://glenwing.github.io/docs/VESA-EEDID-DDDB-1.pdf
For me, being old time user, (ab)using any subpixel layouts for text rendering and antialiasing is counterproductive and (especially with current pixel densities, but also in general) introduces much more issues that it actually ever solved
“Whole pixel/grayscale antialiasing” should be enough and then specialized display controller would handle the rest
Agreed, but layouts such as Pentile don't actually have all three subpixel components in a logical pixel, so you'll still get artifacts even with grayscale AA. You can compensate for this by masking those missing components.
https://github.com/snowie2000/mactype/issues/932
surprising info, I thought this was supposed to be the part about "display controller taking care of any additional issues", thanks for link with details, will read it with interest
Windows has always allowed you to change subpixel layout, its right there in the clear type settings.
I may be totally off the mark here, but my understanding is that the alternative pixel arrangements found in current WOLED and QD-OLED monitors are suboptimal in various ways (despite the otherwise excellent qualities of these displays) and so panel manufacturers are working towards OLED panels built with traditional RGB subpixel arrangements that don’t forfeit the benefits of current WOLED and QD-OLED tech.
That being the case, it may end up being that in the near future, alternative arrangements end up being abandoned and become one of the many quirky “stepping stone” technologies that litter display technology history. While it’s still a good idea to support them better in software, that might put into context why there hasn’t been more efforts put into doing so.
Sub-pixel anti-aliasing requires outputing a pixel-perfect image to the screen, which is a challenge when you're also doing rendering on the GPU. You generally can't rely on any non-trivial part of the standard 3D-rendering pipeline (except for simple blitting/compositing) and have to use the GPU's compute stack instead to address those requirements. This adds quite a bit of complexity.
Mandatory reading when getting into this topic: http://rastertragedy.com/
TIL fonts have more than just a collection of vectorized glyphs in them
This is a wonderful write up. Reminiscent of the old google
G engineering write ups are usually well written with plenty of useful information to carry forward.
It’s G’s _business_ folks (ie, C-level executives) that I have no respect for. Their business model of exploiting users is just awful.
I appreciate the pun in the repository name https://github.com/googlefonts/fontations/
It looks like there is an extern C interface... I wonder if it is everything necessary for someone to use it via FFI.
Given that it's being used in a large C++ codebase, I would assume it has everything needed to use it in that API.
They just need to rewrite the rest of Chrome to use the native Rust<>Rust interface.
(in reality Google is investing a lot of effort into automating the FFI layer to make it safer and less tedious)
This is the kind of work that Brave et al will never do.
I wonder what this means, if anything, for the future of WUFFS. TTF support is on their roadmap. If they can get acceptable performance and safety from Rust, will they still drive on with WUFFS?
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.
Also, the act of breaking it into smaller functions itself may introduce more bugs.
> 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
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.
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".
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.
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.
C and modern C++ are so different that lumping them together in a blanket assertion doesn't really carry much meaning.
If only didn't exist so many folks that insist in using C types, and C headers, in modern C++ code.
Indeed.
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.
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.
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.
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
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.
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.
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.
It's very annoying that Google's websites, including this blog, are automatically translated to my browser's preferred language.
Sillicon Valley devs clearly believe that machine translation is a magical technology that completely solved internationalization, like in Star Trek. No, it's far from it. Ever since internet has been flooded with automatically translated garbage, the experience of international users, at least bilingual ones, got much worse.
The worst offender to me is Google Maps. I'm a native Spanish speaker but set my phone to English because I hate app translations. The problem is when I want to read reviews it automatically translates them from Spanish (my native language) to English. It doesn't make any sense!
Hey, at least it's preferred language. It's much worse when it bases it on the country that I'm in, which I can only reasonably influence with a VPN, and calling that reasonable is a stretch.
This is the worst. I was in France recently and tons of mobile websites were just suddenly in French. It was a real chore to read through them, and I can only imagine how frustrating this is when you can't read the language put in front of you at all.
This is always infuriating, because browsers send the Accept-Language header, that these sites just ignore.
The thing I don't get is that there are plenty of Googlers traveling internationally. They've been aware of the problem for over a decade now, yet it persists. If I'm traveling from Spain to Poland with a browser set to use UK-English, why would the site immediately switch to Polish? It makes no sense that this common corner case isn't addressed at all after all this time.
At the very least sites that do this should detect that there's a mismatch between expected language given geolocation and the header and have a toast notification about how to change the language settings back manually.
Just imagine the mess in Belgium!
Actually I can imagine that multilingualism would force the devs to rely on Accept-Language instead of GeoIP. Talking out of my arse here :)
It cuts in both ways.
I'm trying to learn the language of the country I now live in. And yet, Google thinks they know better than me, my preference, at the moment.
And this preference is quite circumstantial, mind you.
It would be nice to have a browser setting that says: Use the original version of the text, if it is written in one of my preferred languages.
I keep setting all my preferences *everywhere* to English, yet 50% of the time google search results are 100% Finnish. With a helpful "change to English" link that does not work.
Worst still Google Maps will insist on only showing street names, area names, an directions in Swedish.
Strong agree. I had worked at Google for four years before discovering that the API documentation I meticulously wrote was machine translated to other languages. Only by perusing these translations did I realize some API concepts had been translated; I had to overuse the backtick notation for code to suppress these translations.
This is not a just Silicon Valley problem though; Redmond had similar issues if you just use the newer parts of Windows in a non-English language.
Translation technology has gotten so much better in the meanwhile, I didn't even notice it at first.
Wouldn't the alternative be worse for most people?
If you're a global company it would be silly to assume all your readers speak/read a single language. AI translations (assuming that's what this is) are not perfect, but better than nothing.
I get how poor translation could be irritating for bilingual people who notice the quality difference though, but I guess you guys have the advantage of being able to switch the language.
Excluded middle. It doesn't have to be automatic, it could well be a choice. Best of all worlds if you ask me.
I have `en-US` set as the second preference language, so just show me the content in `en-US` unless you have a real human-vetted translation into my primary language.
Look, a language that was conceived out of necessity to write a web browser in a safer way is being used just for that. It's a different, unrelated browser, but the language still reaches its design goals beautifully.
I get it, but switching to Rust places the codebase on an Island I can't easily get to. I am already switching between C++, Swift, Kotlin, and Python on an almost daily basis.
Was this a codebase you were working with regularly already? This project exposes a C FFI, so unless you were already working in the guts here, I don't think this should affect you terribly.
edit: I'm actually not seeing the C FFI, looking at the library. It must be there somewhere, because it's being used from a C++ codebase. Can somebody point to the extern C use? I'm finding this inside that `fontations` repository:
We're using https://cxx.rs/ to create the bindings and FFI interface. That's not provided with Fontations, but this bit is part of the Chromium and Skia integration. The code is here: https://source.chromium.org/chromium/chromium/src/+/main:thi...
Chromium is >35 million lines of code, switching languages all in one go just isn't happening.
For me it was already hard to get into chromium's code base. It takes too long to build and there's just so much to understand about it before you can make changes.
It might help if there was some way to play around with the APIs without having to wait so long for it to build. But as far as i know that's not currently possible.
just get the AI to understand it for you /s
It is not a matter of understanding source code. It is matter of bridging, building, and linking another language with yet another binary layout and interface.
It's an extern c interface. That's not any different than dealing with a c library
That is good to know.
FreeType is a dinosaur that should be replaced regardless of Rust or not.
It already is replaced by HarfBuzz https://harfbuzz.github.io
Harfbuzz is designed to run on top of the FreeType Renderer. https://harfbuzz.github.io/what-does-harfbuzz-do.html
I stand corrected, thank you for follow up
The best libraries are libraries that have a clearly defined goal, hit that goal, and then don't change until the goalposts get moved. Something that happens only very slowly in font land.
Its age is completely irrelevant other than as demonstration that it did what it set out to do, and still performs that job as intended for people who actually work on, and with fonts.
I don't think you understand how backwards it is. My patch that makes SDF rendering 4x faster was not accepted, presumably because floating point-maths is some strange new-fangled technology. Freetype uses antiquated fixed-point integer maths everywhere. See https://gitlab.freedesktop.org/freetype/freetype/-/merge_req...
Did you check to see if Freetype supports platforms that don't have floating-point math, or where it's very slow? I agree that fixed-point math is unnecessary on modern hardware and architectures, but they may prioritize support for hardware you don't personally care about.
Sure, a compile-time option to use one or the other might sound reasonable, but then that's two different code paths that need to be maintained and tested. Are you willing to do that maintenance on an ongoing basis?
And can you be certain that switching to floating-point doesn't change the results of calculations in various ways that actually matter for rendering? Are you willing to put in the time to test that thoroughly?
Instead of engaging with the developer, you just ignored them and moved on. I certainly wouldn't want to merge a patch into one of my projects if it came from someone with your attitude.
I know how to read, and that MR comment sounds 100% reasonable to me. Normally you'd take a comment like that, go "oh, okay let me do some more investigations" and start a dialog instead of going "they rejected my MR on the first pass, they don't know what they're doing and their library is antiquated".
Where's the follow-up, or did you just walk away?
Because to be a clear: a reviewer comment is the start of the conversation, if you don't respond then the bad actor is you, not them. Ask them why they don't want to use math.h, ask them if there are dev documents that explain what can and can't be used, and why. If you don't, this failure is on you, not them.