Perhaps in part because the sponsors are invested in using go and benefit from its inclusion in a list of memory safe languages.
Perhaps in part because the sponsors are invested in using go and benefit from its inclusion in a list of memory safe languages.
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.
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.
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.
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?
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?
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?
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.
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.
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.
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.
By the same token can I say your comment here is representative of all HN comments?
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?
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.
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).
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
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.
See: https://blog.stalkr.net/2015/04/golang-data-races-to-break-m...
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
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.
What about this one ? "Futurelock in Tokyo" ? https://rfd.shared.oxide.computer/rfd/0609
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.
'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
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.
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.
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...
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.
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.
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
Politicians
So I think Go is absolutely not in the same bucket as C, C++, or unsafe Rust.
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)
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.
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".
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.
Waiting for the traditional Rust reply.
What standard?