Hacker News new | past | comments | ask | show | jobs | submit | gw2's comments login

> even Rust isn't really memory-safe.

Yeah, and this points at a deeper issue: the concept of a language being either (binary) memory safe or not does not really make sense. Memory safety is a spectrum and most GC'd languages are safer than Rust (but you won't see a lot of "memory safety" proponents acknowledge this).

Also, there are mitigations that can make "unsafe" languages as secure as something like Rust, but those are deliberately overlooked and hence languages like Zig are constantly bashed using security as the reason.


Questions to anyone using Crystal in production:

* How is the GC latency, considering that Crystal uses the Boehm GC?

* Have you encountered any problems in long running programs due to the conservative nature of Boehm?


We wrote https://github.com/compumike/idle-gc to run GC when the long-running process is otherwise mostly idle. It’s been fine for us.


> gc latency I don't know, never care much about it, haven't cause any issue the 6 years I run my web services using Crystal.

> long running programs depends, I write several services that running 24/7. Some runs fine for months, some just refuses to response after a few day. Too busy to track for the cause so I just automatically reset the affected services at 4AM.


A question to security experts reading this thread:

What is your opinion on deploying C++ codebases with mitigations like CFI and bounds checking? Let's say I have a large C++ codebase which I am unwilling to rewrite in Rust. But I:

* Enable STL bounds checking using appropriate flags (like `-DGLIBCXX_ASSERTIONS`).

* Enable mitigations like CFI and shadow stacks.

How much less safe is "C++ w/ mitigations" than Rust? How much of the "70% CVE" statistic is relevant to such a C++ codebase?

(I've asked this in an earlier thread and also in other forums, but I never really got a response that does not boil down to "only Rust is safe, suck it up!". It also doesn't help that every other thread about C++ is about its memory unsafety...)


It helps, however there is also a culture mindset that is required.

Back in the old Usenet flamewars, C developers would to say coding in languages like Object Pascal, Modula-2, Ada,... was like programming with straightjacket, and we used to call them cowboy programming.

When C++ came into the scene with its improved type system, it seemed a way we could have the best of both worlds, better safety and UNIX/C like ecosystem.

However this eventually changed as more and more people started to adopt C++, and thanks to its C subset, many C++ projects are actually mostly C code compiled with a C++ compiler.

So hardned runtimes help a lot, as does using static analysers like clang tidy, VC++ analyse, Sonar, PVS Studio, Clion analysers, ....

However many of them exist for the last 30 years, I was using Parasoft in 1999.

The biggest problem is culture, thinking that such tools are only required by those that aren't good enough to program C or C++, naturally those issues only happen to others, we are good drivers.


STL bounds checking isn't bounds checking. Your code (or other libraries you use) can still have simple pointer arithmetic that goes outside bounds.

But the larger problem is that bounds checking (even ASAN) isn't as good as statically checking code. ie. Your code with bounds checking still crashes at run time, which can be a denial of service attack, whereas with static checking your code would never have compiled in the first place.

Nevertheless if you don't want to rewrite the world, then using these mitigations is much better than not using them. I would also add fuzzing to the mix.


DoS is vastly better than an RCE. And safe code can still panic.

But as you mention, unfortunately enabling bound checking in the STL wouldn't catch a lot of pointer manipulation.

It would still be better than the the status-quo.


Good question. If I had to bet I'd say something like half of the 70% would be prevented. Yeah it wouldn't really help with lifetime issues or type confusion but a huge proportion of that 70% is simple out-of-bounds memory accesses.

But don't forget lots of open source code is written in C and this barely helps there.


> something like half of the 70% would be prevented

Sure, but the other half are use-after-frees and those would not be exploitable anyway because of CFI and shadow stacks.


That is a very bold claim!



For the first one, a lot of this depends on how modern your codebase is. STL bounds checks work great (and have remarkably low overhead) if the vast majority of your code is working with standard library types. Maybe all of the code that might have been a c-style array in the past is now using std::vector, std::span, or std::array and so you've got built in lengths. Not perfect, of course, since you can still have all sorts of spatial safety issues with custom iterator implementations or whatever, but great.

But my hunch is that the vast majority of C++ codebases aren't using std::span or std::array everywhere because there is just a lot of much older code. And there's no comparable option for handling lifetime bugs.

Tools like CFI or hardware memory tagging or pointer authentication help, but skilled exploit creators have been defeating techniques like these for a while so they don't have the "at least I know this entire class of issue is prevented" confidence as bounds checks inserted into library types.

The general industry recommendation is "if you are starting something new that has security implications, please seriously explore Rust" and "if you have a legacy C++ codebase that is too expensive to port please seriously explore these mitigation techniques and understand their limitations."


My two cents, I'm wearing my exploit writer's hat, but my current day job is SWE on legacy/"modern-ish" C++ codebases.

> Enable STL bounds checking using appropriate flags

This rarely helps. Most of the nice-to-exploit bugs were in older codes, which weren't using STL containers. Or they are even just write in C. However, if enabling these flags do not hurt you, please still do as it does make non-zero contribution.

> Enable mitigations like CFI and shadow stacks.

Shadow stack is meh. CFI helps a bit more, however there's some caveats depending on which CFI implementation you are talking about, i.e. how strong is it, for example, is it typed or not? But in best case it still just makes the bug chain one bug longer and maybe completely kills some bugs, which isn't enough to make your exploits impossible. It just raises the bar (that's important too though). It also depends on what the specific scenario. For example, for browser renderer without sandbox / site-isolation etc, CFI alone makes almost no impact, as in this case achieving arbitrary R/W is usually easier than taking over $rip, and it's obvious you can do data-only attack to have UXSS, which is a serious enough threat. On the other hand, if it's a server and you are mainly dealing with remote attackers and there's inherently no good leak primitive etc, various mitigations soup could make real difference.

So, all in all, it's hard to tell without your project details.

> How much of the "70% CVE" statistic is relevant to such a C++ codebase?

Uh, I'd guess, half or more of that. But still, it just raises the bar.


First of all, thanks for your response.

> This rarely helps. Most of the nice-to-exploit bugs were in older codes, which weren't using STL containers.

While I agree with this, is not modifying those code to use STL containers much cheaper than rewriting into an entirely new language?

> Shadow stack is meh.

Are you referring to the idea of shadow stacks in general or a particular implementation of them?

> For example, for browser renderer without sandbox / site-isolation etc

I may be wrong, but I think you are referring to JIT bugs leading to arbitrary script execution in JS engines. I don't think memory safety can do anything about it because those bugs happen in the binding layer between the C++ code and JS scripts. Binding code would have to use unsafe code anyway. (In general, script injection has nothing to do with memory safety, see Log4j)

> Uh, I'd guess, half or more of that.

I mean, if you are after RCEs, don't CFI and shadow stacks halt the program instead of letting the CPU jumping to the injected code?

Now, let me get more specific - can you name one widespread C++ exploit that:

* would have happened even if the above mentioned mitigations were employed.

* would not have happened in a memory safe language?


All good questions.

> is not modifying those code to use STL containers much cheaper

That's right. However, I'd add that most exploited bugs these days (in high-profile targets) are temporal memory safety (i.e. lifetime) bugs. The remaining spatial (out of bound) bugs are mostly in long forgotten dependencies.

> Are you referring to the idea of shadow stacks in general or a particular implementation of them?

The idea. Shadow stack (assuming perfect hardware assisted implementation) is a good backward-edge control flow integrity idea, and ruins one of the common ways to take over $rip (write a ROP chain to stack), but that's it. Besides making exploitation harder, both forward-edge and backward-edge CFI also kill some bugs. However, IMO we are long past non-linear stack buffer overflow days, once in a while there may still be news about one, but it could be news because it is an outlier. Hence, compared to CFI, the bugs shadow stack kills are pretty irrelevant now.

> JIT bugs leading to arbitrary script execution in JS engines

Not necessarily JIT bugs. Could also be an UAF and people went a bloody path to convert it to an `ArrayBuffer` with base address = 0 and size = 0x7FFFFFFFFFFFFFFF accessible from JavaScript. Chrome killed this specific primitive. But there's more, I'm not going to talk about them here.

You may have a slight confusion here. In case of browser renderer, people starts with arbitrary JavaScript execution, the goal here is to do what JavaScript (on this page!) can't do, via memory corruption - including, but not limited to executing arbitrary native code. For example, for a few years, being able to access Chrome-specific JS APIs to send arbitrary IPC message to browser process (out of renderer sandbox), is one `bool` flag on .bss away from JavaScript. If we managed to get arbitrary R/W (that is, can read / write all memory within the renderer process, within JavaScript, see my ArrayBuffer example above), we just change it and run our sandbox escape against browser process in JavaScript, who needs that native code execution?

Or, if you do want native code execution. For a few years in V8 the native code WASM gets compiled to, is RWX in memory, so you just use your arb R/W to write that. You can kill that too, but then people starts coming up with bizarre tricks like overwriting your WASM code cache when you load it from disk and before making it R/X, and there're enough fishes in the pool that you likely can't patch em'all.

> I mean, if you are after RCEs, don't CFI and shadow stacks halt the program instead of letting the CPU jumping to the injected code?

Yeah. But as I said, nowadays people usually use temporal memory safety bugs, and they want arbitrary R/W before they attempt to take over $rip. Don't get me wrong, this is because of the success of CFI and similar mitigations! So they did work, they just can't stop people from popping your phones.

> can you name one widespread C++ exploit that:

I just google'd "Chrome in the wild UAF" and casually found this in the first page: https://securelist.com/the-zero-day-exploits-of-operation-wi...

I assume "in the wild exploited" fits your "widespread" requirement.

Granted, it's five years old, but if you are okay with non-ITW bugs I can come up with a lot of more recent ones (in my mind).

This is an UAF. So it would not have happened in a memory safe language. While back then the exploited chrome.exe may not have enabled CFG (it was enabled late 2021 IIRC), I don't see how the exploit path could be blocked by CFI.


> Zig is essentially a skin on a subset of C++, one that is in practice less safe than C++

Give it a rest please. Given your association with Rust, endlessly attacking competing languages is not a good look, regardless of whether your points are technically correct or not.


Looks fine to me.


I find VS Code to be unmanageable for anything beyond a medium sized project. Maybe the LSPs I use are to be blamed, but I find nvim less problematic in this regard.


If the application is free (with no strings attached), I would not really complain. But the main offenders are apps by large companies that have revenues in billions. The problem is that most of the userbase do not complain.


C#. While a popular language, it is criminally overlooked for high-performance programming. Obviously, you can't use it for embedded or kernel development. For other use cases though, it can almost reach the performance of C/C++/Rust when written with proper care.


> Obviously, you can't use it for embedded

Embedded is diverse. I would not use .NET for small embedded, i.e. stuff running on Arduino or ESP32.

However, I have successfully used .NET runtime in production for embedded software running on top of more performant SoCs, like 4 ARMv7 cores, couple GB RAM, Linux kernel. The software still has large pieces written in C and C++ (e.g. NanoVG rendering library) but all higher-level stuff like networking, file handling, and GUI are in memory-safe C#.



I sometimes write C# in my day job. But I think I don't know much about how to write really fast C#. Do you have any recommendations for learning resources on that topic?


Sure. Here are some resources:

* Span<T>: https://learn.microsoft.com/en-us/archive/msdn-magazine/2018...

* C# now has a limited borrow checker-like mechanism to safely handle local references: https://em-tg.github.io/csborrow/

* Here is a series of articles on the topic: https://www.stevejgordon.co.uk/writing-high-performance-csha...

* In general, avoid enterprise style C# (ie., lots of class and design patterns) and features like LINQ which allocate a lot of temporaries.


LINQ is fine (but enterprise style never is, yes), it’s a matter of scale and what kind of a domain the code is targeted too. C# needs to be approached a little like C++ and Rust in this regard. Having standard performance optimization knowledge helps greatly.

Also can recommend reading all the performance improvements blog posts by Stephen Toub as well as learning to understand disassembly at a basic level which .NET offers a few convenient tools to get access to.


And I can recommend listening to @neonsunset when it comes to C# performance :)

Helped me a bunch to get Sharpl spinning, much appreciated.

https://github.com/codr7/sharpl


Thank you. I once read a bit about Span<T>, but some of this reference stuff is very new to me. Interesting, definitely. C# really is a big language nowadays...


Spans are just a slice type, but those which any type based on contiguous memory can be coerced to (usually). I’m sure you’re already using them somewhere without realizing that. Their main use case in regular code is zero-cost slicing e.g. text.AsSpan(2..8).


C# is specifically designed for enterprise-style OOP, so if you want to avoid that, why use C# at all?


You're thinking of Java, which is Enterprize Buzzword Compliant to the maximum extent possible.

C# is Java-but-with-lessons-learnt, and is significantly less verbose and "enterprisey" in typical usage.

Modern .NET 9 especially embraces compile-time code generation, a "minimal" style, and relatively high performance code compared to Java.

Even if the JVM is faster in benchmarks for hot loops, typical Java code has far more ceremony and overhead compared to typical C# code.


> Even if the JVM is faster in benchmarks for hot loops, typical Java code has far more ceremony and overhead compared to typical C# code.

Can you give an example? I don't think this is true anymore for modern Java (Java 21+)


It's a heavily gamed benchmark, but TechEmpower Fortunes is pretty good at revealing the max throughput of a language runtime for "specially tuned" code (instead of idiomatic code).

Java currently beats .NET by about 40%: https://www.techempower.com/benchmarks/#hw=ph&test=fortune&s...

I judge more idiomatic / typical code complexity by the length of stack traces in production web app crashes. Enterprise Java apps can produce monstrous traces that are tens of pages long.

ASP.NET Core 9 is a bit worse than ASP.NET Web Forms used to be because of the increased flexibility and async capability, but it's still nowhere near as bad as a typical Java app.

In terms of code length / abstraction nonsense overhead, have a look at the new Minimal APIs for how lightweight code can get in modern C# web apps: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/m...


For those interested in performance ceiling, https://benchmarksgame-team.pages.debian.net/benchmarksgame/... provides additional data points.

What matters in practical scenarios is that ASP.NET Core is significantly faster than Spring Boot. If you have a team willing to use ActiveJ or Vert.x, you are just as likely have a team willing to customize their C# implementation to produce numbers just as good at web application tasks and much better at something lower level. There are also issues with TechEmpower that make it highly sensitive to specific HW/Kernel/Libraries combination in ways which alter the rankings significantly. .NET team hosts a farm to do their own TechEmpower runs and it just keeps regressing with each new version of Linux kernel (for all entries), despite CPU% going down and throughput improving in separate more isolated ASP.NET Core evaluations. Mind you, the architecture of ASP.NET Core + Kestrel, in my opinion, leaves some performance on the table, and I think Techempower is a decent demonstration of where you can expect the average framework performance to sit at once you start looking at specific popular options most teams use.


How's modern Java in a game/sim scenario? C# has value types to reduce the GC load, for example. Do Java records close the gap there?


No, records are a reduction in boilerplate for regular classes (the result also happens to be read-only — not deeply immutable, mind you). Value types are in the works:

https://openjdk.org/jeps/401


Hmm looking at that it seems like being a struct type is a non-goals they seem to explicitly call out C# value types as a different thing...

Smaller objects from dropping identity is nice but it really doesn't seem like it gives you more explicit memory layout, lifecycle, c interop etc that C# has with their structs. Maybe I'm missing something.


> C# is specifically designed for enterprise-style OOP

Then why would they add Span<T>, SIMD types and overhaul ref types in the first place?


Because some people wanted to use C# for low-level programming, so they added these things as an afterthought.


You’ve clearly never used it and have no idea what you are talking about.


I have used it a few years ago and the enforced OOP boilerplate was too much for me.


You can write procedural or functional style as well, and with top-level statement you can write without any OOP or boilerplate whatsoever.


Trying to write it as if it was a different language instead or, for whatever reason, copying the worst style a team could come up with does happen and must be avoided, but that’s user error and not a language issue. Also the tooling, especially CLI, is excellent and on par with what you find in Rust, far ahead of Java and C++.

If you link an example snippet of the type of code that gave you pause, I’m sure there is a better and more idiomatic way to write it.


C# was originally a clone of Java. It was almost literally copy/paste compatible.


I have the same issues with JVM-like languages, like Java. I only write Java if I am getting financially compensated for it!


Span<T>, ReadOnlySpan<T>, Memory<T>, CollectionsMarshal, CollectionsExtensions, ref struct, ref return, ArrayPool, ArraySegment, ValueTuple, and using interfaces/structs/generics carefully.

That is if you don't want to get into unsafe code.


A few important ones: - Avoid memory allocations as much as you can. That's a primary thing. For example, case insensitive string comparisons using "a.ToUpper() == b.ToUpper()" in a tight loop are a performance disaster, when "string.Equals(a, b, StringComparison.CurrentCultureIgnoreCase)" is readily available. - Do not use string concatenation (which allocates), instead prefer StringBuilder, - Generally remember than any string operation (such as extracting a substring) means allocation of a new string. Instead use methods that return Span over the original string, in case of mystr.Substring(4,6) it can be a.AsSpan(4,6), - Beware of some combinations of Linq methods, such as "collection.Where(condition).First()" is faster than "collection.First(condition)" etc.

Apart from that (which simply concerns strings, as they're the great source of performance issues, all generic best practices, applicable to any language, should be followed.

There are plenty resources on the net, just search for it.


You actually can use it for embedded and kernel development! See .NET Nano Framework [1] for embedded - works on microcontrollers like ESP32. For kernel development there's nothing really built in to support it but people have built tools [2] to do it.

[1] https://nanoframework.net/ [2] https://gocosmos.org/


Pour one out for Midori, which would have replaced Windows with a capability-based OS completely written from kernel to shell in a C# dialect. Async/await, spans, and immutable support came from it, along with an (opt-in) Rust-like borrow checker. Satya canceled it, and all the work was lost to history. Singularity was the early public prototype.


The only thing Singularity and Midori share is the idea.

You should also pour one out for Longhorn, where internal politics tanked the idea, and eventually Windows team redid all those .NET based ideas into COM/C++, and were even proud of doing so (see Hilo sample documentation), hence why nowadays COM based libraries are the main way to expose modern Windows APIs (aka post Windows XP).

Had they collaborated instead, probably Windows would be closer to something like Android userspace nowadays.

Or for Ironclad, another one from Microsoft research, lesser known, also from the same research group, which even includes type safe Assembly,

https://www.microsoft.com/en-us/research/publication/safe-to...

Microsoft Research has plenty of work in such domains, they also had a LLVM like compiler framework, based on MSIL, called Phoenix, among other stuff, e.g. Dafny, FStar, Drawbridge, also come from OS projects.

Unfortunely classical Microsoft management has been more like it isn't Windows, it isn't shipping.


Partly off-topic: which well-known companies have research groups? I knew about Microsoft and IBM. Google, probably. Others? Might be interesting to browse their sites for nuggets to explore or use.


If you hear the name “lab126”, that’s Amazon’s team.

Nokia owns the shambling corpse that is Bell Labs. Looking beyond the English speaking world, I wouldn’t discount that the chaebols (LG, Samsung, Mitsubishi, etc) all have a few companies dedicated to research at the Bell Labs level.



And arguably it beats the performance of C/C++/Rust when written without proper care: https://blog.codinghorror.com/on-managed-code-performance-ag...

The big take-away I got from this (admittedly quite old now) experiment is that getting advertised performance out of unmanaged languages for typical real-world (i.e., non-benchmark) tasks often requires a lot more care than people really account for. Nowadays memory dominates performance more so than CPU, and the combination of a JIT compiler and a good generational, compacting garbage collector - like C# and Java developers typically enjoy - often does a better job of turning idiomatic, non-hand-optimized code into something that minimizes walks of shame to the RAM chips.


Well in that case, Java :)

I've been having a lot of fun with Java lately, the maturity of the language/implementation and libraries allows me to focus on the actual problem I'm solving in ways no other language can currently match.

https://github.com/codr7/tyred-java https://github.com/codr7/eli-java


D's "Better C"[1] mode looks like what you describe. Has syntax similar to C with a real module system, metaprogramming, slice types etc.,

1 - https://dlang.org/spec/betterc.html


What is your opinion on deploying C++ codebases with mitigations like CFI and bounds checking?

Let us say I have a large C++ codebase which I am unwilling to rewrite in Rust. But I:

* Enable STL bounds checking using appropriate flags (like `-DGLIBCXX_ASSERTIONS`).

* Enable mitigations like CFI and shadow stacks.

How much less safe is "C++ w/ mitigations" than Rust? How much of the "70% CVE" statistic is relevant to my codebase?


We recorded an episode (there's a transcript) about this exact issue:

https://securitycryptographywhatever.com/2024/10/15/a-little...


With due respect, the blog you have linked looks like the average Rust marketing material. It does absolutely nothing to address my concerns. I did a `Ctrl-F` and found zero hits of any of the following terms:

* CFI

* isoheaps or type-stable allocators

* Shadow stacks

(There is just a single hit of "C++"...)

Ignoring the appeal to authority, I have a hard time believing that incrementally rewriting my C++ code in Rust or just writing new code in Rust ("vulnerabilities exponentially decay" and all that) is going to give me more actual security than the mitigations stated above. Most, if not all, high-profile exploits stem from out-of-bounds accesses and type confusions, which these mitigations prevent at very low cost.

Thanks for replying, though.


If what you're interested in is an "everything must be Rust" vs. "everything must be C++" knock-down drag-out, I'm not interested.


They prevent but do not entirely mitigate.


I am not interested in adhering to some arbitrary purity standard (like "memory safety" in this case). Almost always, purity ideologies are both irrational and harmful. What I am actually interested is to prevent real problems like remote code execution and Heartbleed-esque leakage of private data and for this, mitigations like CFI, shadow stacks and bounds checking are enough.

> They prevent but do not entirely mitigate.

Ignoring the semantic difference between "prevent" and "mitigate", if at the end of the day, the security provided by the two different approaches are quite similar, I don't get the problem.

If you have an example of a successful widespread exploit that would have happened even with these mitigations, please share.


They’re not enough. For example the field I work in (mobile exploits) continues to bypass CFI (PAC) via clever data-only attacks or abusing TOCTOU issues.


I may be wrong, but that issue is specific to PA. Shadow stacks can't be tampered with. Smartphones probably went with PA because shadow stacks require more memory. My use case specifically is targeting desktop/server systems with Clang CFI and Intel CET.

Note that I am not very knowledgeable in security, and I am really willing to be educated but it feels like most of the replies to my comments are just trying to prove me wrong.


PAC as implemented is stronger than shadow stacks, as it aims to provide CFI for more cases and not just function returns. Overwriting function pointers gives code execution under shadow stacks (which only protect return addresses) but is much more difficult to do so when the pointers are signed. Mobile platforms are very memory sensitive (one of the major reasons that MTE hasn't rolled out, for example) but I don't really see them wanting to adopt shadow stacks.

I can't really speak to your comments as you haven't posted many of them. I'm not here to prove you wrong but just to share my views on these mitigations. I'm not an expert by any means but I do get to think about these for work so I can usually do at least a quick once-over to try to figure out how effective they might be.


Thanks for your reply.

> Overwriting function pointers gives code execution under shadow stacks

As you are probably aware, there are two kinds of CFI - forward-edge and backward-edge. Forward-edge CFI prevents tampered function pointers, vtables and such from being invoked. Whereas backward-edge CFI protects does the same for return addresses. Clang's and MSVC's (CFG) implementations of CFI only provide forward-edge protection, hence the need for shadow stacks. Without hardware support, shadow stacks can not be prevented from tampered, which is why Intel (CET) and AMD added shadow stacks.

> Mobile platforms are very memory sensitive

Agreed. I'd guess this applies to embedded too. But all things considered, I do hold the opinion that language-level memory safety is being overplayed a lot.


> IME you can't reliably extract the intent from the C code, much less the binary, so you can't really fix these bugs without a human rewriting the source.

I am pretty sure that the parent is talking about hardware memory safety which doesn't require any "human rewriting the source".


> I am pretty sure that the parent is talking about hardware memory safety which doesn't require any "human rewriting the source".

It does though. The hardware might catch an error (or an "error") and halt the program, but you still need a human to fix it.


> but you still need a human to fix it.

The same thing can be said about a Rust vector OOB panic or any other bug in any safe language. Bugs happen which is why programmers are employed in the first place!


> The same thing can be said about a Rust vector OOB panic or any other bug in any safe language. Bugs happen which is why programmers are employed in the first place!

Sure, the point is you're going to need the programmer either way, so "hardware security lets us detect the problem without rewriting the code" isn't really a compelling advantage for that approach.


If a program halts, that is a narrow security issue that will not leak data. Humans need to fix bugs, but that is nothing new. A memory bug with such features would be hardly more significant than any other bug, and people would get better at fixing them over time because they would be easier to detect.


> If a program halts, that is a narrow security issue that will not leak data.

Maybe. Depends what the fallback for the business that was using it is when that program doesn't run.

> Humans need to fix bugs, but that is nothing new. A memory bug with such features would be hardly more significant than any other bug

Perhaps. But it seems to me that the changes that you'd need to make to fix such a bug are much the same changes that you'd need to make to port the code to Rust or what have you, since ultimately in either case you have to prove that the memory access is correct. Indeed I'd argue that an approach that lets you find these bugs at compile time rather than run time has a distinct advantage.


>Perhaps. But it seems to me that the changes that you'd need to make to fix such a bug are much the same changes that you'd need to make to port the code to Rust or what have you, since ultimately in either case you have to prove that the memory access is correct.

No, you wouldn't need to prove that the memory access is correct if you relied on hardware features. Or I should say, that proof will be mostly done by compiler and library writers who implement the low level stuff like array allocations. The net lines of code changed would definitely be less than a complete rewrite, and would not require rediscovery of specifications that normally has to happen in the course of a rewrite.

>Indeed I'd argue that an approach that lets you find these bugs at compile time rather than run time has a distinct advantage.

It is an advantage but it's not free. Every compilation takes longer in a more restrictive language. The benefits would rapidly diminish with the number of instances of the program that run tests, which is incidentally one metric that correlates positively with how significant bugs actually are. You could think of it as free unit tests, almost. The extra hardware does have a cost but that cost is WAAAY lower than the cost of a wholesale rewrite.


> No, you wouldn't need to prove that the memory access is correct if you relied on hardware features. Or I should say, that proof will be mostly done by compiler and library writers who implement the low level stuff like array allocations. The net lines of code changed would definitely be less than a complete rewrite, and would not require rediscovery of specifications that normally has to happen in the course of a rewrite.

I don't see how the hardware features make this part any easier than a Rust-style borrow checker or avoid requiring the same rediscovery of specifications. Checking at runtime has some advantages (it means that if there are codepaths that are never actually run, you can skip getting those correct - although it's sometimes hard to tell the difference between a codepath that's never run and a codepath that's rarely run), but for every memory access that does happen, your compiler/runtime/hardware is answering the same question either way - "why is this memory access legitimate?" - and that's going to require the same amount of logic (and potentially involve arbitrarily complex aspects of the rest of the code) to answer in either setting.


The human might say, sorry my C program is not compatible with your hardware memory safety device. I won't/can't fix that.


That's possible but unlikely. I would be OK with requiring software bugs like that to be fixed, unless it can be explained away as impossible for some reason. We could almost certainly move toward requiring this kind of stuff to be fixed much more easily than we could do the commonly proposed "rewrite it in another language bro" path.


There's no such thing as hardware memory safety, with absolutely no change to the semantics of the machine as seen by the compiled C program. There are going to be false positives.


> There are going to be false positives

Of course, but compare it with rewriting it to a completely different language.


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

Search: