False.
C and C++ are not memory safe if you use the most common and most performant implementations, sure.
At some point these folks are going to have to accept that caveat
I don’t think the spec says one way or another (but please correct me if you find verbiage indicating that the language must be memory unsafe).
It’s possible to make the whole language memory safe, including unions. It’s tricky, but possible.
Someone else mentioned Fil-C but Fil-C builds on a lot of prior art. The fact that C and C++ can be memory safe is no secret to those who understand language implementation.
But yes, fil-c is a huge improvement (afaik though it doesn’t solve the UB problem - it just guarantees you can’t have a memory safety issue as a result)
This statement doesn't make sense to me.
Memory safety is a property of language implementations, which is all about what happens when the programmer does not follow the rules.
> The problem is that the rules cannot be automatically checked and in practice are the source of unenumerable issues from straight up bugs to subtle standards violations that trigger the optimizer to rewrite your code into what you didn’t intend.
They can be automatically checked and Fil-C proves this. The prior art had already proved it before Fil-C existed.
> But yes, fil-c is a huge improvement (afaik though it doesn’t solve the UB problem - it just guarantees you can’t have a memory safety issue as a result)
Fil-C doesn't have UB. If you find anything that looks like UB to you, please file a GH issue.
Let's also be clear that you're referring to nasal demons specifically, not UB generally. In some contexts, like CPU ISAs, UB means a trap, rather than nasal demons. So let's use the term "nasal demons".
C and C++ only have nasal demons because:
- Policy decisions. For example, making signed integer addition have nasal demons is because someone wanted to cook a benchmark.
- Lack of memory safety in most implementations, combined with a refusal to acknowledge what happens when the wrong kind of memory access occurs. (Note that CPU ISAs like x86 and ARM are not memory safe, but have no nasal demons, because they do define what happens when any kind of memory access occurs.)
So anyway, Fil-C has no nasal demons, because:
- I turned off all of those silly policy decisions for cooking benchmarks.
- The memory safety means that I define what happens when the wrong kind of memory access occurs: the program gets killed with a panic.
That’s good to know about nasal demons. Are you saying you somehow inhibit the optimizer from injecting a security vulnerability due to UB ala https://www.cve.org/CVERecord?id=CVE-2009-1897 ? I’m kinda curious how you trick LLVM into not optimizing through UB since it’s UB model is so tuned to the C/C++ standard.
Anyway, Fil-C is only currently working on (a lot of, but not all yet I think right?) Linux userspace while C and C++ as a standard language definition span a lot more environments. I agree the website should call out Fil-C as memory safe but I think it’s also fair to say that Fil-C is more an independent dialect of C/C++ (eg you do have to patch some existing software) - IMHO it’s too confusing for communicating out to say that C/C++ is memory safe and I’d rather it say something like Fil-C is memory safe or C/C++ code running under Fil-C is memory safe.
> Memory safety is a property of language implementations, which is all about what happens when the programmer does not follow the rules.
By this argument no language is memory safe because every language has bugs that can result in memory safety issues. Certainly rustc definitely has soundness issues that haven’t been fixed and I believe this is also true of Python, JavaScript, etc but I think it’s an unhelpful bar or framing of the problem. The language itself is memory safe and any safety issues within the language spec or implementation are a bug to be fixed. That isn’t true of C/C++ where there’s going to always exist environments where it’s impossible to even have a memory safe implementation (eg microcontrollers) let alone mandate one in the spec. And also fil-C does have a performance impact so some software may not ever be a good fit for it (eg video encoders/decoders). For example, a non memory safe conforming implementation of JavaScript is not possible. Same goes for safe rust, Python or Java. By comparison that isn’t true for c/c++.
Reasonable people will disagree about what memory safety (and type safety) mean to them. Personally, bounds checking for arrays and strings, some solution for safe deallocation of memory, and an obviously correct way to write manual bounds checks is more interesting than (for example) no access to machine addresses and no FFI.
Regarding bounds checking, GNAT offers some interesting (non-standard) options: https://gcc.gnu.org/onlinedocs/gnat_ugn/Management-of-Overfl... Basically, you can write a bounds check in the most natural way, and the compiler will evaluate the check with infinite precision (or almost, to improve performance). In standard, you might end up with an exception in some corner cases where the check should pass. I wish more languages would offer something like this. Among widely used languages, only Python offers this capability because it uses infinite-precision integers.
Yes that is inhibited. There’s no trick. LLVM (and other compilers) choose to do those stupid things by policy, and the policy can be turned off. It’s not even hard to do it.
> Fil-C is more an independent dialect of C/C++ (eg you do have to patch some existing software)
Fil-C is not a dialect. The patches are similar to what you’d have to do if you were porting a C program to a new CPU architecture or a different compiler.
> By this argument no language is memory safe because every language has bugs that can result in memory safety issues.
You rebutted this argument for me:
> any safety issues within the language spec or implementation are a bug to be fixed
Exactly this. A memory safe language implementation treats outstanding memory safety issues as a bug to be fixed.
This is what makes almost all JS implementations, and Fil-C, memory safe.
Now, certain implementations of C might give your more guarantees for some (or all) of the behavior that the standard says is undefined. Fil-C is an example of an implementation taking this to the extreme. But it's not what is meant when one just says "C." Otherwise I would be able to compile my C code with any of my standard-compliant compilers and get a memory-safe executable, which is definitely not the case.
My meager understanding of unions is that they allow data of different types to be overlayed in the same area of memory, with the typical use case being for data structures that may contain different types of data (and the union typically being embedded in a struct that identifies the data type). This certainly presents problems with the interpretation of data stored in the union, but it also strikes me that the union object would have a clearly defined sized and the compiler would be able to flag any memory accesses outside of the bounds of the union. While this is clearly problematic, especially if at least one of the elements is a pointer, it also seems like the sort of problem that a compiler can catch (which is the benefit of Rust on this front).
Please correct me if I'm wrong. This sort of software development is a hobby for me (anything that I do for work is done in languages like Python).
Rust avoids this by having sum types, as well as preventing the user from constructing a tag that’s inconsistent with the union member. So it’s not that a union is inherent unsafe, but that the language’s design needs to control the construction and invariants of a union.
union {
char* p;
long i;
};
Then say that the attacker can write arbitrary integers into `i` and then trigger dereferences on `p`.The union example is not particularly problematic in this regard. Much more challenging is pointer arithmetic through uintptr_t because it's quite common. It's probably still solvable, but at a certain point, changes the sources becomes easier, even at at scale (say if something uses the %p format specifier with sprintf/sscanf).
Real C programs use these kinds of unions and real C compilers ascribe bitcast semantics to this union. LLVM has a lot of heavy machinery to make sure that the programmer gets exactly what then expected here.
The spec is brain damage. You should ignore it if you want to be able to reason about C.
> This is not just hypothetical: existing implementations with pointer capabilities (Fil-C, CHERI targets, possibly even compilers for IBM i) already do this
Fil-C does not abort when you use this union. You get memory safe semantics:
- you can use `i` to change the pointer’s intval. But the capability can’t be changed that way. So if you make a mistake you’ll end up with an OOB pointer.
- you can use `i` to read the pointer’s current intval just as if you had done an ptrtoint cast.
I think CHERI also does not abort on the union itself. I think storing to `i` removes the capability bit so `p` crashes on deref.
> The union example is not particularly problematic in this regard. Much more challenging is pointer arithmetic through uintptr_t because it's quite common.
The union problem is one of the reasons why C is not memory safe, because C compilers give unions the expected structured assembly semantics, not whatever nonsense is in the spec.
Doesn't modern C++ offer the ability to write memory safe code? The primary distinguishing difference from Rust, on this front, is that Rust is memory safe by default (and allows them to override memory safety with code that is explicitly declared as unsafe) while C++ requires the developer to make a conscious effort to avoid unsafe code (without providing facilities to declare code as safe or unsafe). While this means that C++ is problematic, it does not make Rust automagically safer - particularly when interfacing with C/C++ code (as would be the case when interfacing with Linux syscalls or most C or C++ based libraries).
I guess what I'm saying is that Rust is great when dealing exclusively with Rust libraries since it is either memory safe by default or because it is easier to audit (since it is either declared explicitly or implicitly as unsafe). On the other hand, it is not guaranteed to be memory safe. While this may sound like nitpicking, the distinction is important from the perspective of the end user who is unlikely to ever audit the code yet may be swayed by being told that it is written in a memory safe language.
For example, everyday operations in Rust are almost all defined. But in C++, it is extremely easy to run into undefined behavior by accident and make your code do something bizarre. On the practical side, I have never ever gotten a segfault when writing rust, but have many times in C++.
The problem is much worse than how you put it. I've written C++ for more than a decade and it's painful to constantly having to worry about memory safety due to enormous complexity of the language. Even if you are super diligent, you will make a mistake and it will bite you when you expect it the least. Relying on clang-tidy, non-default compiler flags, sanitizers and other tools is not only not enough, but a constant source of headache on how to integrate them with your build systems and project requirements.
It'll still let you do a bunch of stuff Rust doesn't, which is up to the programmer to decide whether this is good or not.
Use-after-free is still possible in modern C++ via std::span/std::string_view/etc. outliving the backing object.
Doesn't modern C++ offer the ability to write memory safe code?
Can you name an example of a non-trivial C++ program that's memory safe? The only examples I can think of went to extraordinary lengths with formal methods and none of them are widely used.And then Ada software caused the loss of US$370 million with Ariane 5.
> And then Ada software caused the loss of US$370 million with Ariane 5.
This seems like a bit of a non-sequitur? Ariane is an EU rocket and the flight you're referring to was carrying an EU payload, and I don't think it was ever subject to the US DoD Ada mandate or an EU equivalent (which I'm not sure ever existed?).
(Also a bit of a nitpick, but I don't think the US DoD Ada Mandate was a law per se; it was a DoD policy and not something the US Congress passed).
It's probably somewhat disputable as to whether the Ariane failure was "due to Ada" or whether other higher-level concerns were responsible (e.g., reusing the Ariane 4 software without revalidation)
1. "I don't care what my program does."
Why write it though?
2. "I don't care what the standard says, I've put text into a compiler and it gave me a binary that does the thing."
What if you want to put the same text into a different compiler in the future, or the same compiler again? Are you certain the binary is going to continue doing the thing? Have you even fully tested the binary?
3. "I use a special runtime that makes memory unsafety defined again."
One, I don't believe you unless you're part of a very small group of people and two, why are you accepting the serious drawbacks (performance, process death, all the broader issues of UB) that come with this?
It's genuinely hard for me to understand why you wouldn't think memory safety is important Don't you want to write code that's portable and correct? Don't you want to execute other people's programs and trust they won't segfault? Doesn't it frustrate you that the language committees have spent years refusing to address even the lowest-hanging fruit?
(In other words: curl is using Rust, just not a specific Rust HTTP/1 backend anymore. But the site doesn’t limit its scope to just that backend.)
Prossimo gets 6.8%. Does that money go to programmers? Are people whose works are being rewritten and plagiarized offered money to do the rewrite themselves or does it go to friends and family?
Why does an org that takes donations not produce a proper report?
Solaris and Linux SPARC since 2015, for example.
https://docs.oracle.com/en/operating-systems/solaris/oracle-...
https://docs.kernel.org/arch/sparc/adi.html
ARM MTE, as another one,
https://learn.arm.com/learning-paths/mobile-graphics-and-gam...
It is kind of interesting how all attempts to improve security are akin to arguing about usefulness of seatbelts when people still die wearing them.
> Doing the same thing in software on a contemporary commercially established CPU is going to be much, much faster.
In what sense? Do you know if there's been proper research done in this area? Surely implementing the bounds checking / permissions would be faster in hardware.
Regarding performant implementations of capability architectures, Fil-C running on modern CPUs is eventually going to overtake Arm's Morello reference board because it doesn't look like there's going to be a successor to the board. Morello was based on Arm's Neoverse-N1 core and produced using TSMC's N7 process. It was a research project, but it's really an outlier because such projects hardly ever have access to these kinds of resources (both CPU IP and tape-out on a previous-generation process). It seems all other implementations of CHERI are FPGA-based.
It's actually quite easy to create a C bindings for a Go library, using CGo and -buildmode=c-shared.
I'm not sure what effect the Go runtime has on the overall application, but it doesn't seem like it would be "less possible" than with Java.
https://www.graalvm.org/latest/reference-manual/native-image...
Then again, many times OS IPC is a much better option.
Somewhat controversially, I think Java is actually doing fine on null safety: it uses the same approach for it as it does for array index safety. The latter is a problem for any language with arrays without dependent types: out-of-bounds accesses (if detectable at all) result in exceptions (often named differently because exceptions are controversial).
Java's advantage here is that it doesn't pretend that it doesn't have exceptions. I think it's quite rare to take down a service because handling a specific request resulted in an exception. Catching exceptions, logging them, and continuing seems to be rather common. It's not like Rust and Go, where unexpected panics in libraries are often treated as security vulnerabilities because panics are expected to take down entire services, instead of just stopping processing of the current request.
Proper null safety (sometimes called void safety) is to actually systematically eliminate null values, to force in the type system a path of either handling or explicitly crashing. This is what many newer expressive multi-paradigm languages have been able to achieve (and something functional programming languages have been doing for ages), but remains out of reach for Java. Java does throw an exception on errant null value access, but allows the programmer to forget to handle it by making it a `RuntimeException`, and by the time you might try to handle it, you've lost all of the semantics of what went wrong - what value was actually missing and what a missing value truly means in the domain.
> Catching exceptions, logging them, and continuing seems to be rather common. It's not like Rust and Go, where unexpected panics in libraries are often treated as security vulnerabilities because panics are expected to take down entire services, instead of just stopping processing of the current request.
Comparing exceptions to panics is a category error. Rust for example has great facilities for bubbling up errors as values. Part of why you want to avoid panicking so much is that you don't need to do it, because it is just as easy to create structured errors that can be ignored by the consumer if needed. Java exceptions should be compared to how errors are actually handled in Rust code, it turns out they end up being fairly similar in what you get out of it.
Regarding the category error, on many platforms, Rust panics use the same underlying implementation mechanism as C++ exceptions. In general, Rust library code is expected to be panic-safe. Some well-known Rust tools use panics for control flow (in the same way one would abuse exceptions). The standard test framework depends on recoverable panics, if I recall correctly. The Rust language gives exceptions a different name and does not provide convenient syntax for handling them, but it still has to deal with the baggage associated with them, and so do Rust library authors who do not want to place restrictions on how their code is reused. It's not necessarily a bad approach, to be clear: avoiding out-of-bounds indexing errors completely is hard.
But if you're going to argue about the mere presence of null being problematic, you might as well complain about the ability to use "unsafe" code in Rust too.
> Memory safe languages include Rust, Go, C#, Java, Swift, Python, and JavaScript. Languages that are not memory safe include C, C++, and assembly.
codys•1mo ago
Perhaps in part because the sponsors are invested in using go and benefit from its inclusion in a list of memory safe languages.
websiteapi•1mo ago
muricula•1mo ago
websiteapi•1mo ago
Yoric•1mo ago
Go has a memory model that basically guarantees that the language is memory-safe except with a few marked "unsafe" functions or in case of race conditions involving interfaces or arrays. It's pretty easy to come up with an example of such a race condition that will cause reads or writes from/to unpredictable memory addresses. I imagine it's quite feasible to turn this into reads or writes from/to crafted memory addresses, which would be a mean to defeat pretty much any security measure implemented in the language.
The Rust community caters to people who are a bit obsessive about safety (including myself) and Rust developers tend to consider this a bug in the design of the Go language (there are a few, albeit much harder to achieve, issues that are vaguely comparable in Rust and they are considered bugs in the current design of Rust). The Go community tends to attract people who are more interested in shipping than in guarantees, and Go developers who are aware of this issue tend not care and assume that this is never going to happen in practice (which may or may not be true, I haven't checked).
awesome_dude•1mo ago
To my knowledge, no.
> if the existence of races makes a language unsafe, then aren't all languages unsafe?
Are we talking about "data races" or "race conditions" One can lead to the other, but race conditions are a much bigger set.
AIUI It's impossible for any language level controls to prevent any and all race conditions, because some are happening outside of the binary/process/computer.
Data races, OTOH are almost trivial to protect against - a contestable thing must have a guard that ensures a writer has exclusive access to that thing for the duration of the write.
Some languages do this with mutually exclusive locks (mutex/semaphore/go channels), some languages/paradigms do this by never having shareable objects (Functional Programming/Pass by Value), and some (Rust) are doing this with the compile time checks and firm rules on a single writer.
Edit: Never having shareable objects should really be "never allowing an outside thread/coroutine/process/whatever mutate your copy of an object" meaning that an object is immutable to them, and they have to have a copy that they can mutate to their heart's content. They have to communicate any changes back, and then you choose whether to integrate those changes, or not
i_am_a_peasant•1mo ago
SkiFire13•1mo ago
torginus•1mo ago
It'd be very hard to make something that offers that guarantee in the real world. One of the most common, IRL exploitable race conditions are ones that involve multiple services/databases, and even if your programming language would have such a feature, your production system would not.
muricula•1mo ago
pjmlp•1mo ago
K0nserv•1mo ago
See: https://blog.stalkr.net/2015/04/golang-data-races-to-break-m...
lomase•1mo ago
Dylan16807•1mo ago
steveklabnik•1mo ago
tekne•1mo ago
lenkite•1mo ago
https://materialize.com/blog/rust-concurrency-bug-unbounded-...
Lockbud: project detailing memory, concurrency bugs and panics for Rust. https://github.com/BurtonQin/lockbud
USENIX paper on model checking for Rust OS kernels uncovered 20 concurrency bugs across 12 modules in projects like Redox OS and Tock, including data races, deadlocks, and livelocks
https://www.usenix.org/system/files/atc25-tang.pdf
codys•1mo ago
Go allowing torn writes for their slices and interfaces (their fat pointer types) is intentional behavior in the go implementation and has no sign of being fixed.
Some one getting unsafe code unintentionally wrong is not an indication that any language lacks memory safety.
lenkite•1mo ago
What about this one ? "Futurelock in Tokyo" ? https://rfd.shared.oxide.computer/rfd/0609
aw1621107•1mo ago
Deadlocks are not memory safety issues by the definition used in the OP. Furthermore, safe Rust is only intended to guarantee protection against data races, not race conditions in general.
lenkite•1mo ago
'static closures/FnDefs/futures with non-'static return type are unsound https://github.com/rust-lang/rust/issues/84366
Resolve unsound interaction between noalias and self-referential data (incl. generators, async fn) https://github.com/rust-lang/rust/issues/63818
aw1621107•1mo ago
But anyways, at least from a quick glance those would at the very least seem to run into codys' unintentional bug vs. intentional behavior distinction. The bugs you linked are... well... bugs that the Rust devs fully intend to fix regardless of whether any in-the-wild exploits ever arise. The Go data race issue, on the other hand, is an intentional implementation decision and the devs have not indicated any interest in fixing it so far.
tptacek•1mo ago
tptacek•1mo ago
pjmlp•1mo ago
Which also overlook how Rust type system can be subverted to actually allow for data races, with some help of linker scripts and OS IPC primitives.
jkdjfdsnjsdf•1mo ago
Dylan16807•1mo ago
What standard?
crawshaw•1mo ago
1. attempting to retcon garbage collected languages as not memory safe, or
2. discussing a particular implementation choice of the standard Go runtime that was made because it is not a practical source of bugs (see https://research.swtch.com/gorace, it is not an inherent feature of the language, just the implementation, and it is the right practical choice)
But either way: this is the sort of thing I have seen again and again in the Rust "community" that I find deeply off-putting. Build good things, do not play snooty word games.
saagarjha•1mo ago
crawshaw•1mo ago
saagarjha•1mo ago
tptacek•1mo ago
saagarjha•1mo ago
pjmlp•1mo ago
Make those in-memory data structures writable via OS IPC and all bets are open, regarding what other processes, or kernel extensions, do to the memory segment.
Fearless concurrency is welcomed, but lets not overlook the fine print in systems programming.
saagarjha•1mo ago
pjmlp•1mo ago
saagarjha•1mo ago
SkiFire13•1mo ago
pjmlp•1mo ago
AnthonyMouse•1mo ago
So then we see an enormous amount of effort being spent to try to replace everything written in C with Rust when that level of effort should have been able to e.g. come up with something which is easy enough for ordinary people to use that it could plausibly displace WordPress but has a better security posture. Or improve the various legacy issues with distribution package managers so that people stop avoiding them even for popular packages in favor of perilous kludges like npm and Docker.
aw1621107•1mo ago
TypeScript exists? So I'm not too sure that everyone is focusing entirely on memory safety...
> So then we see an enormous amount of effort being spent to try to replace everything written in C with Rust when that level of effort should have been able to e.g. come up with something which is easy enough for ordinary people to use that it could plausibly displace WordPress but has a better security posture.
I feel like this is somewhat... inconsistent? At the risk of oversimplifying a bit (or more), Rust is "something which is easy enough for ordinary people to use that it could plausibly displace [C/C++] but has a better security posture" (not saying that it's the only option, of course). So now that all that effort has been expended in producing Rust, you want to just... forgo applying the solution and redirect that effort to working on solutions to other problems? What happens when you come up with solutions to those? Drop those solutions on the floor as well in favor of solving yet other issues?
I think another explanation for allocation of effort here is due to the difference between creating a solution and applying a solution. At the risk of oversimplifying yet again, "replace C with Rust" is applying a known solution with known benefits/drawbacks to a known problem. Can you say the same about "[i]mprov[ing] the various legacy issues with distribution package managers so that people stop avoiding them even for popular packages in favor of perilous kludges like npm and Docker", let alone coming up with an easy-to-use more secure WordPress replacement?
AnthonyMouse•1mo ago
TypeScript is JavaScript with a moderate improvement to one of its many flaws. An actual solution would look like choosing/developing a decent modern scripting language and getting the web standards people to add it to browsers and have access to the DOM, which would in turn cause that to be the first language novices learn and temper the undesirably common practice of people using JavaScript on the back end because it's what they know.
> Rust is "something which is easy enough for ordinary people to use that it could plausibly displace [C/C++] but has a better security posture"
It's kind of the opposite of that. It's something that imposes strict constraints which enables professional programmers to improve the correctness of their software without sacrificing performance. But it does that by getting in your way on purpose. It's not an easy thing if you're new. And there's a place for that, but it's an entirely different thing.
The problem with WordPress isn't that it's designed for performance over security. It's not fast, and a replacement with a better design could easily improve performance while doing significantly more validation. And it's full of low-hanging fruit in terms of just removing a lot of the legacy footguns.
> So now that all that effort has been expended in producing Rust, you want to just... forgo applying the solution and redirect that effort to working on solutions to other problems?
In general when you come up with some new construction methods that are better able to withstand earthquakes, you apply them whenever you build a new building, and maybe to some specific buildings that are especially important or susceptible to the problem, but it's not worth it to raze every building in the city just to build them again with the new thing. After all, what happens when you get the new new thing? Start all over again, again?
aw1621107•1mo ago
I'm certainly not going to say that nothing better could emerge, but nevertheless it's effort towards improving something that isn't memory safety.
In other words, I don't really agree that there's a "singular focus" on memory safety. Memory safety rewrites/projects get headlines, absolutely, but that doesn't mean everyone else has dropped what they were doing. Generally speaking, different groups, different projects, etc.
> It's kind of the opposite of that.
I don't think I quite agree? What I was thinking is that there have been efforts to make memory-safe dialects/variants/etc. of C/C++, but none of them really got significant traction in the domains Rust is now finding so much success in. I'm not saying this is because Rust is easy, but (at least partially) because it took concepts from those previous efforts and made them easy enough to be accessible to ordinary devs, and as a result Rust could become a plausible more-secure replacement for C/C++ where those earlier efforts could not.
> The problem with WordPress isn't that it's designed for performance over security. It's not fast, and a replacement with a better design could easily improve performance while doing significantly more validation. And it's full of low-hanging fruit in terms of just removing a lot of the legacy footguns.
Sure, and I'm not denying that. My point is just that unlike Rust vs. C/C++, as of this moment we don't know what an analogous plausible replacement for WordPress could be (or at least I don't know; perhaps you're more in-the-know than I am). Again, it's the difference between having a plausible solution for a problem in hand vs. sitting at the drafting desk with some sketches.
> In general when you come up with some new construction methods that are better able to withstand earthquakes, you apply them whenever you build a new building, and maybe to some specific buildings that are especially important or susceptible to the problem, but it's not worth it to raze every building in the city just to build them again with the new thing.
I feel like perhaps where the analogy breaks down is that unlike rebuilding a building, the Rust version of something can be built while the old version is still being used. Rust 4 Linux didn't require Linux and/or driver development to halt or for existing drivers to be removed in order to start and/or continue its development, Dropbox didn't have to tear out its old sync engine before starting work on the new one, etc.
And because of that, I feel like in general Rust is already mostly being used for new/important things? Or at the very least, I don't think "raze every building in the city just to build them again with the new thing" is an apt description of what is going on; it's more akin to building a "shadow" copy of a building in the same space using the new techniques with the possibility of swapping the "shadow" copy in at some point.
Or maybe I'm just too charitable here. Wouldn't be the first time.
> After all, what happens when you get the new new thing? Start all over again, again?
If the cost-benefit analysis points in that direction, sure, why not?
AnthonyMouse•1mo ago
Well yes, but we're talking about the Rust people, which is why Typescript was a red herring to begin with. The complaint is that they've got a new hammer and then start seeing nails everywhere.
> What I was thinking is that there have been efforts to make memory-safe dialects/variants/etc. of C/C++, but none of them really got significant traction in the domains Rust is now finding so much success in.
This was mostly because they didn't solve the performance problem. In the domains where that matters less, other languages did make significant inroads. Java, Python, etc. have significant usage in domains that before them were often C or C++.
> My point is just that unlike Rust vs. C/C++, as of this moment we don't know what an analogous plausible replacement for WordPress could be (or at least I don't know; perhaps you're more in-the-know than I am). Again, it's the difference between having a plausible solution for a problem in hand vs. sitting at the drafting desk with some sketches.
The primary thing WordPress needs is a fresh implementation that takes into account sound design principals the original never did and which at this point would be compatibility-breaking changes. Give each plugin its own namespace by default, have a sane permissions model etc.
It doesn't require any great novelty, it's just a lot of work to re-implement a complex piece of software from scratch in a different language. But that's the analogous thing, with an analogous level of effort, being proposed for rewriting a lot of software in Rust whose predecessors have significantly fewer vulnerabilities than WordPress.
> I feel like perhaps where the analogy breaks down is that unlike rebuilding a building, the Rust version of something can be built while the old version is still being used.
That has little to do with it. If you really wanted to rebuild every building in the city, you could build a new building on every available empty lot, move the people from existing buildings into the new buildings, raze the buildings they just moved out of to turn them into empty lots and then repeat until every building is replaced.
The reason that isn't done is that building a new thing from scratch requires a significant amount of resources, so it's something you only force outside of its natural replacement cycle if the incremental improvement is very large.
> If the cost-benefit analysis points in that direction, sure, why not?
The point is that it doesn't. Rewriting a large amount of old C code, especially if it doesn't have a lot of attack surface exposed to begin with, is a major cost with a smaller benefit. Meanwhile there are many other things that have medium costs and medium benefits, or large costs and large benefits, and those might be a better use of scarce resources.
aw1621107•1mo ago
Ah, my apologies for misreading the original comment I replied to then.
> This was mostly because they didn't solve the performance problem. In the domains where that matters less, other languages did make significant inroads. Java, Python, etc. have significant usage in domains that before them were often C or C++.
Which is true! But even after Java/Python/etc. made their inroads the memory-safe dialects/variants/etc. of C/C++ still didn't attract much attention, since while Java/Python/etc. made memory safety easy enough for devs, as you said they didn't make performant memory safety easy enough, which left C/C++ their niche. While Rust is far from a perfect solution, it seems to have made performant memory safety easy enough to get to where it is today.
> If you really wanted to rebuild every building in the city, you could build a new building on every available empty lot, move the people from existing buildings into the new buildings, raze the buildings they just moved out of to turn them into empty lots and then repeat until every building is replaced.
I took "raze every building in the city just to build them again with the new thing" as specifically implying a destroy -> rebuild order of operations, as opposed to something more like "replace every building with the new thing". Too literal of a reading on my end, I guess?
> The reason that isn't done is that building a new thing from scratch requires a significant amount of resources, so it's something you only force outside of its natural replacement cycle if the incremental improvement is very large.
I mean, that's... arguably what is being done? Obviously different people will disagree on the size of the improvement, and the existence of hobbyists kind of throws a wrench into this as well since their resources are not necessarily put towards an "optimal" use pretty much by definition.
> The point is that it doesn't. Rewriting a large amount of old C code, especially if it doesn't have a lot of attack surface exposed to begin with, is a major cost with a smaller benefit. Meanwhile there are many other things that have medium costs and medium benefits, or large costs and large benefits, and those might be a better use of scarce resources.
That's a fair conclusion to come to, though it's evidently one where different people can come to different conclusions. Whether one stance or the other will be proven right (if the situation can even be summed up as such), only time will tell.
And again, I feel like I should circle back again to the "solution in hand vs. sitting at the drafting table" thing. Maybe an analogy to moonshot research a la Xerox PARC/Bell Labs might be better? One can argue that more resources into a WordPress replacement might yield more benefits than rewriting something from C to Rust, but there are much larger uncertainty bars attached to the former than the latter. It's easier to get resources for something with more concrete benefits than something more nebulous.
actionfromafar•1mo ago
aw1621107•1mo ago
That being said, I wouldn't be surprised if it (and similar capabilities from Graal, etc.) grabbed yet more market share due to making those languages more viable where they historically had not been.
Gibbon1•1mo ago
Also remember a conversation with someone at netscape about JS. The idea was partly as an interpreted language it could be safe unlike binaries. Considering binaries on pre 2000 hardware, running an arbitrary binary oof. But that it wasn't as easy as assumed.
tptacek•1mo ago
testdelacc1•1mo ago
By the same token can I say your comment here is representative of all HN comments?
jojomodding•1mo ago
So what is it now? If the implementation is correct in allowing you to cause UB with data races, then this is very much a feature of the language, making the language not memory-safe. Alternatively, the implementation is buggy here, in which case there should be a bug report somewhere.
Is there such a bug report (github issue)? Is there a line in the spec saying this is the intended behavior?
AlotOfReading•1mo ago
Ultimately, "memory safety" is a conversation about what a program is intended to do and what semantics the language guarantees that program will have when executed. For the vast majority of programs, you can be just as confident that your Go and Python code will do the right things at runtime as your safe Rust. It's good enough.
vlovich123•1mo ago
AlotOfReading•1mo ago
vlovich123•1mo ago
hackermailman•1mo ago
llmslave2•1mo ago
codys•1mo ago
Go's implementation allows torn writes for interfaces (which are 2 words in size). These torn writes allow arbitrary memory reads/writes (a superset of out of bounds reads/writes)
llmslave2•1mo ago
codys•1mo ago
Please fully provide your definition of memory safety. Not interested in trying to figure out what it is in a 20-questions-over-hn way.
llmslave2•1mo ago
codys•1mo ago
And then note that memorysafety.org says this (in case folks haven't read it):
> Memory safety is a property of some programming languages that prevents programmers from introducing certain types of bugs related to how memory is used.
They then provide an examine of out-of-bounds read/write. Which is the exact example I noted in my linked comment.
(Note: memorysafety.org does not provide a concrete definition of memory safety, but we get enough from what it says in this case)
The site does not require the known existence of an exploit in popular software (and does not require that _any_ exploit be possible, a bug is sufficient), merely that the language fails to block "certain types of bugs".
llmslave2•1mo ago
codys•1mo ago
I found this by searching for places where folks reload there config at runtime, as they are generally a place where people forget to synchronize correctly in go.
1. A viper.OnConfigChange callback is set up to call readConfig(): https://github.com/OdyseeTeam/chainquery/blob/48c092515dea5c...
2. Inside readConfig(), we assign to a slice `twillio.RecipientList` (https://github.com/OdyseeTeam/chainquery/blob/48c092515dea5c...
3. Note that in Go, slices are objects composed of 3 words (https://go.dev/blog/slices-intro#slice-internals) And there isn't syncronization built-in over updating them. As a result, if something reads the slice while it's being updated we will mix together a data pointer & length & capacity that correspond to different real slice objects. If the length we read is from a slice that has real length 10, but the data pointer we read is from a slice with real length 1, when iterating we'll read memory out of bounds.
4. in the context of this particular program, we may send SMSs to recipients who were never in the configured list if a config change occurs at the right time. Or a segfault. Entirely unclear if reading the memory will result in reasonable behavior.
Note: I'm not familiar with this repo otherwise. This is from a quick search.
woodruffw•1mo ago
codys•1mo ago
Folks have shown this allows the kinds of arbitrary memory reads/writes that folks normally ban in their definition of memory safe (and this post's website has a definition does as well):
https://research.swtch.com/gorace
https://blog.stalkr.net/2015/04/golang-data-races-to-break-m...
https://www.ralfj.de/blog/2025/07/24/memory-safety.html
aw1621107•1mo ago
codys•1mo ago
aw1621107•1mo ago
Maybe something like "Go is effectively/practically memory safe at the moment" would be better? Or if you want to put on your lawyer hat "Go is not known to be memory unsafe at this time", but that's rather cumbersome at best.
codys•1mo ago
Which does get us to why defining the properties of a language based on what people have written in that language _so far_ is weird. It's not really a property of the language that no one has screwed up yet. It's perhaps an indication that it might be less likely that folks will screw up, which is where the "probabilistic" comes in. It assumes that given the lack of a counter example (a screw up) so far, and given the time that Go has existed, it _appears_ that it's low-likelyhood to screw up go programs in that particular way.
Agreed that the word is non-targeted in one way, but it's better than the alternate (implying go would have to change to become memory unsafe), if one wants to talk about how-memory-safe-is-go.
aw1621107•1mo ago
I agree that "at the moment" could imply that Go would need to change for that statement to change, but I think it could also imply that "effectively/practically" could change as well since "effectively/practically" in this context implies a particular state of knowledge about known exploits (i.e., that there are none). If someone releases a practical data race exploit for real-world Go codebases tomorrow, "effectively/practically" would no longer hold, and therefore the statement would no longer hold despite Go not changing. The representation of the state of knowledge is part of why I suggested the lawyer-y version :P
fweimer•1mo ago
So I think Go is absolutely not in the same bucket as C, C++, or unsafe Rust.
pjmlp•1mo ago
Waiting for the traditional Rust reply.
rurban•1mo ago
Politicians