LWN: Comments on "A discussion of Rust safety documentation" https://lwn.net/Articles/990273/ This is a special feed containing comments posted to the individual LWN article titled "A discussion of Rust safety documentation". en-us Fri, 12 Sep 2025 11:52:24 +0000 Fri, 12 Sep 2025 11:52:24 +0000 https://www.rssboard.org/rss-specification lwn@lwn.net Why this code possibly has undefined behavior using strict providence https://lwn.net/Articles/993066/ https://lwn.net/Articles/993066/ hkBst <div class="FormattedComment"> For others wondering how this code can be UB: this code triggers a UB error from Miri due to provenance issues, the exact rules of which are still being worked out, but which do have a simple superset, called strict provenance. The exact rule which is relevant for this example is that a pointer derived from a reference/slice only has valid provenance if it points to where that reference/slice can point to. Given this analysis it is simple to satisfy Miri with a small change to the code[1]:<br> <p> ```rust<br> use std::{mem,ptr};<br> <p> fn bad_load_int_le(buf: &amp;[u8; 32], i: usize) -&gt; u32 {<br> assert!(i + mem::size_of::&lt;u32&gt;() &lt;= buf.len());<br> let mut data = 0u32;<br> unsafe {<br> ptr::copy_nonoverlapping(<br> buf.get_unchecked(i), // provenance problem because only references the first byte<br> //buf.get_unchecked(i..i + mem::size_of::&lt;u32&gt;()).as_ptr(), // reference all four bytes<br> //buf.as_ptr().add(i), // reference entire buf<br> &amp;mut data as *mut _ as *mut u8,<br> mem::size_of::&lt;u32&gt;(),<br> );<br> }<br> data.to_le()<br> }<br> <p> // this let's you use Miri<br> fn main() {<br> let data = [0u8; 32];<br> bad_load_int_le(&amp;data, 0);<br> }<br> ```<br> <p> [1]:<a rel="nofollow" href="https://play.rust-lang.org/?version=stable&amp;mode=debug&amp;edition=2021&amp;gist=44f1c005f3b633a2f31a589af6bbf6a8">https://play.rust-lang.org/?version=stable&amp;mode=debug...</a><br> <p> <p> </div> Sun, 06 Oct 2024 18:13:31 +0000 Slice to `[u8;4]` https://lwn.net/Articles/992898/ https://lwn.net/Articles/992898/ Wol <div class="FormattedComment"> <span class="QuotedText">&gt; So... you're saying that the job _isn't_ done when the Rust compiler stops complaining, and that the resultant code might not actually _work_ even though the compiler "proved" it to be "correct"?</span><br> <p> But isn't that *always* true? Just because the *maths* is correct, doesn't mean the *logic* is sound.<br> <p> I have a production system that uses bell-curve statistics on a skewed distribution. It mostly works because the data is USUALLY a strong peak with a weak tail on one side. But feed it a double-peak, or a strong tail, and the results will be rubbish. That's a risk we've chosen to accept. The mathematical model is sound. It's just the fit to reality isn't quite right ...<br> <p> Cheers,<br> Wol<br> </div> Fri, 04 Oct 2024 13:12:42 +0000 Slice to `[u8;4]` https://lwn.net/Articles/992896/ https://lwn.net/Articles/992896/ farnz <p>As with anything, it depends what you require the compiler to prove. My experience is that Rust code is more likely to use <tt>enum</tt>s, <tt>struct</tt>s and other such type system to make it impossible to represent impossible states, rather than clever code that allows for this sort of bug to slip past. <p>In other words, the problem here is clever code where you're trying to beat the optimizer, rather than trusting that the optimizer will get it right. And my experience of cheap coders (offshore outsourcing body shops) is that they trust the optimizer instead of trying to be clever, so they'll do the right thing in Rust; I have, however, had a pile-on for expressing that in the past. Fri, 04 Oct 2024 12:21:05 +0000 Slice to `[u8;4]` https://lwn.net/Articles/992895/ https://lwn.net/Articles/992895/ pizza <div class="FormattedComment"> <span class="QuotedText">&gt; You're right - that's the other fun of using "clever" code, in that you can confuse someone trying to refactor it, and the compiler won't complain. </span><br> <p> So... you're saying that the job _isn't_ done when the Rust compiler stops complaining, and that the resultant code might not actually _work_ even though the compiler "proved" it to be "correct"?<br> <p> (Yeah, yeah, I know you're not one of the obnoxious evangelists making that idiotic claim, but I've been piled upon here multiple times here for making this point..)<br> </div> Fri, 04 Oct 2024 12:08:48 +0000 Slice to `[u8;4]` https://lwn.net/Articles/992893/ https://lwn.net/Articles/992893/ farnz <p>The reason there's so much code for one asm instruction is that most of the code is concerned with things that asm doesn't care about - asm doesn't care if you're reading out of bounds (that's a CPU fault at worst, and a program bug at best), or if you're asking it to read from the "wrong" location, or a whole host of other things that programming languages care about. <p>And it's similar in size to the dance you need to do with standard C to get the same instruction. Fri, 04 Oct 2024 11:55:40 +0000 Slice to `[u8;4]` https://lwn.net/Articles/992892/ https://lwn.net/Articles/992892/ geert <div class="FormattedComment"> About your original: Ah, adding -Wunused helps.<br> About the new version: Wow, writing that much code to generate a function with a single asm instruction...<br> </div> Fri, 04 Oct 2024 11:41:01 +0000 Slice to `[u8;4]` https://lwn.net/Articles/992887/ https://lwn.net/Articles/992887/ farnz <p>You're right - that's the other fun of using "clever" code, in that you can confuse someone trying to refactor it, and the compiler won't complain. <p>A better translation would be <a href="https://rust.godbolt.org/z/6vsro5nb5">this Godbolt link</a>, which makes the use of <tt>unsafe</tt> very clearly about not panicking on error, and uses safe functionality for all of the data transformation. It also makes it clear that this function <em>should</em> be marked as <tt>unsafe</tt>, since as a precondition it requires <tt>buf</tt> to be long enough. Fri, 04 Oct 2024 10:42:01 +0000 Slice to `[u8;4]` https://lwn.net/Articles/992878/ https://lwn.net/Articles/992878/ geert <div class="FormattedComment"> Seems you have dropped using the "i" input parameter value?<br> </div> Fri, 04 Oct 2024 08:19:49 +0000 Unsafety can be subtle https://lwn.net/Articles/991142/ https://lwn.net/Articles/991142/ ralfj <div class="FormattedComment"> khim, I understand you are passionate about Rust-for-Linux and want to see that project succeed, but I think unnecessarily aggressive comments like this are hurting the cause. It is not necessary to repeat the point ("one element" vs "entire buffer") so many times in your answer, nor is it appropriate to suggest people forgot basic things taught early in school. Such a comment will not manage to convince anyone of your position, it will just make people uninterested in engaging with you. Please re-think your communication strategy and try to be a little more empathetic towards the position of others. :)<br> <p> Kind regards,<br> Ralf<br> </div> Sat, 21 Sep 2024 06:45:28 +0000 Unsafety can be subtle https://lwn.net/Articles/991137/ https://lwn.net/Articles/991137/ ralfj <div class="FormattedComment"> <span class="QuotedText">&gt; Ralf Jung has also explored the idea of modifying Stacked Borrows to make it legal [2].</span><br> <p> Unfortunately those modifications wouldn't make this particular code legal. I don't know any way to achieve that without going to something like Tree Borrows.<br> </div> Sat, 21 Sep 2024 06:22:31 +0000 comments can end up being very good at _hiding_ bugs https://lwn.net/Articles/991135/ https://lwn.net/Articles/991135/ ralfj <div class="FormattedComment"> Personally, I find such comments to be invaluable when reviewing tricky unsafe code -- I can compare the comments (expressing the authors intent in a fine-grained way) against the actual code in a fairly local way, which is a lot easier than trying to figure out how everything in the current function works together to make this line correct. It's the difference between things being checkable in a local way vs having to globally keep everything in my head at once.<br> </div> Sat, 21 Sep 2024 06:21:36 +0000 Unsafety can be subtle https://lwn.net/Articles/991133/ https://lwn.net/Articles/991133/ ralfj <div class="FormattedComment"> Note that the error Miri shows for this code has the following:<br> <p> = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental<br> = help: see <a href="https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md">https://github.com/rust-lang/unsafe-code-guidelines/blob/...</a> for further information<br> <p> It is hard to find a set of rules for these aliasing requirements that is precise, can be automatically checked, and allows the desired optimizations. We don't have the final answer yet. That's why there are no strong warnings against this kind of code in the docs: It is deep inside the "gray area", and it is not something we actually already use for optimizations. Restricting references to only access the field/element they point to is something I strongly think we should relax (and that's what the discussion at <a href="https://github.com/rust-lang/unsafe-code-guidelines/issues/134">https://github.com/rust-lang/unsafe-code-guidelines/issue...</a> is about). This is especially true for your case, where the reference points into an array, for the reasons you give -- pointer arithmetic inside arrays is legal even in C, so we should avoid such pitfalls in that space as much as we can. (Unlike C, Rust also permits pointer arithmetic in structs if you use raw pointers instead of references.) But it's hard to make Stacked Borrows accept this code without making Stacked Borrows accept *too much* code.<br> <p> Nobody forces you to make your code compatible with Stacked Borrows, it is an *experimental* model after all. But if you want to be as sure as you can currently be that your code is fine with whatever the future aliasing model ends up being, then it is a good idea to do the extra work and fix Stacked Borrows errors. Think of it like adding a safety margin -- we don't know where the edge between "UB" and "okay" will be, so it is better to err on the side of staying a bit conservative and avoiding the gray area. If you are okay with living a bit more "on the edge" and an increased risk of having to adjust your code in the future as the aliasing model solidifies, you can use "-Zmiri-tree-borrows" to switch to a different, even more experimental aliasing model that *will* accept your code. This model should still be able to catch all UB that is exploited by today's optimizer (but the optimizer can change in the future, and we're not ready yet to commit to a hard set of rules here).<br> <p> <span class="QuotedText">&gt; so I am fairly confident that this is actually undefined behavior, and not just extra paranoia</span><br> <p> It is Undefined Behavior under *experimental* rules, as the error clearly indicates. The rules are deliberately conservative, so there is some extra paranoia involved here. We don't currently instruct the optimizer to actually make us of this particular UB, but there is other Stacked Borrows UB that we *do* use in the optimizer, and a bunch of Stacked Borrows UB that we *may want to* use in the optimizer. It's unclear how to tell these apart, hence this error.<br> </div> Sat, 21 Sep 2024 06:18:05 +0000 Unsafety can be subtle https://lwn.net/Articles/991117/ https://lwn.net/Articles/991117/ apoelstra <div class="FormattedComment"> This idea of using `unreachable_unchecked` to just tell the compiler what I know to be true, then using safe unwrapping methods from there on out (since the optimizer will now definitely be able to make the error paths go away), is really cool, and very general!<br> <p> But I will add my voice to several others asking that you take a kinder tone and offer others the benefit of the doubt (or even, just stop assuming the worst). It makes these technical insights much harder to read and less likely to be noticed.<br> </div> Fri, 20 Sep 2024 23:02:42 +0000 Unsafety can be subtle https://lwn.net/Articles/990987/ https://lwn.net/Articles/990987/ daroc <div class="FormattedComment"> Let's stop discussing this here. It doesn't look like you're likely to change NYKevin's mind, and it seems like this comment doesn't really contribute any new technical information. Sometimes the best thing you can say is just "I still don't agree with you, but thanks for having this discussion with me."<br> </div> Fri, 20 Sep 2024 11:20:30 +0000 Unsafety can be subtle https://lwn.net/Articles/990965/ https://lwn.net/Articles/990965/ comex <div class="FormattedComment"> FYI, the main pattern you cited - where you take a reference to part of an allocation, then convert it to a pointer and index out of bounds of the referenced type (but still in bounds of the allocation) - may end up becoming defined behavior.<br> <p> It is undefined behavior according to Stacked Borrows. But it's not undefined behavior [1] according to Tree Borrows, which is an alternative model that Rust may end up officially adopting instead of Stacked Borrows. Ralf Jung has also explored the idea of modifying Stacked Borrows to make it legal [2]. See also the canonical issue report about this pattern [3].<br> <p> Broadly speaking, this pattern is something that would be nice to make legal at least for immutable references / reads, because there aren't any current optimizations, or highly-desired future optimizations, that would break it.<br> <p> The other pattern you cited - aliasing with mutable references - is different. It needs to be UB in _some_ form, because it's used to justify an important optimization: marking function parameters of reference type with LLVM's `noalias` attribute, equivalent to C `restrict`. Since most C code does not use `restrict`, this is and will remain an area where Rust unsafe is harder to reason about than C.<br> <p> That said, Tree Borrows affects this pattern as well, and at least reduces the amount of UB compared to Stacked Borrows. Specifically, if you create an aliasing mutable reference but don't actually write through it (at least not to the same bytes that you later read from), then you're probably okay under Tree Borrows. [5]<br> <p> (For pedantry's sake, I should mention that even Stacked Borrows' rule is less strict than how you phrased it, but only slightly.)<br> <p> [1] <a href="https://github.com/BoxyUwU/rust-quiz/issues/11">https://github.com/BoxyUwU/rust-quiz/issues/11</a><br> [2] https://rust-lang.zulipchat.com/#narrow/stream/136281-t-opsem/topic/Making.20Stacked.20Borrows.20better.20with.20ugly.20hacks<br> [3] <a href="https://github.com/rust-lang/unsafe-code-guidelines/issues/134">https://github.com/rust-lang/unsafe-code-guidelines/issue...</a><br> [4] <a href="https://github.com/rust-lang/unsafe-code-guidelines/issues/419">https://github.com/rust-lang/unsafe-code-guidelines/issue...</a><br> [5] <a href="https://perso.crans.org/vanille/treebor/protectors.html#not-always-possible-anticipated-writes">https://perso.crans.org/vanille/treebor/protectors.html#n...</a><br> </div> Fri, 20 Sep 2024 02:48:16 +0000 Unsafety can be subtle https://lwn.net/Articles/990954/ https://lwn.net/Articles/990954/ khim <font class="QuotedText">&gt; I literally just told you a story like that, and you responded by making up a bunch of things I didn't say,</font> <p>How is it different from how you make up piece of documentation that never existed and write “<code>slice::get_unchecked</code> is documented to have the same semantic meaning as C pointer arithmetic” then use that “a bunch of things [others] didn't say” as justification for your assertions?</p> <p>I have even gave you benefit of doubt and <a href="https://lwn.net/Articles/990778/">asked</a> just <b>where</b> it was documented that way.</p> <p>And in the end, instead of showing us something like that you <a href="https://lwn.net/Articles/990785/">decided to blame</a> the documentation for your inability to read: “it is perfectly reasonable to interpret the two as synonymous when reading documentation casually”.</p> <p>And when I <a href="https://lwn.net/Articles/990778/">ridiculed it</a> editor only had to say this: “This is an on-topic discussion, but please remember to keep things polite”. <p>And yes, I agree, I wasn't polite, but I, at least, stick to the facts.</p> <font class="QuotedText">&gt; and then ridiculing those things.</font> <p>You want to say that only you can lie (that one even you admitted as a lie: “but literally nobody follows the strict provenance rules anyway, since they're explicitly marked as experimental and non-normative“) and then use these lies to misrepresent things? Others couldn't do that?</p> <p>Let me quite myself, for a change (you haven't misquoted me, just ignored what I say): Rust developer would like to hear “hey, I don't know how to implement this kind of design while staying in the boundaries outlined by the strict provenance approach” stories. <b>Not</b> stories related to someone's inability to read or understand the documentation (documentation writers do accept patches for such cases, but, as noted, it's not clear how to change the documentation and force someone to actually try to read and understand it… I'm not even sure that's possible at all)!</p> <p>And you tell me that we are discussing exactly such story here. But that's big fat lie, author of the original example even admitted that original code that was discussed <a href="https://lwn.net/Articles/990886/">was brought to compliance with stacked borrows</a> (and the whole example that we are discussing <b>here</b> really-really doesn't need any pointers and thus stacked borrows or other such horrors, if you want to eliminate bounds checking then call to one <code>unsafe</code> function with literally zero arguments <a href="https://lwn.net/Articles/990958/">is absolutely enough</a>).</p> <p>Thus it doesn't see an example of design that is limited by strict provenance. Not even remotely close to it. Sorry.</p> Fri, 20 Sep 2024 00:51:39 +0000 Unsafety can be subtle https://lwn.net/Articles/990958/ https://lwn.net/Articles/990958/ khim <font class="QuotedText">&gt; In this case your code appears to be correct, but I don't think "avoid pointers, always reach for transmute first" is a reasonable policy for authors of unsafe code.</font> <p>Why? Generally the advice is to use the safest approach if possible and while, technically, <code>transmute</code> have <i>pretty-much unlimited chaos potential</i>, but it have fewer failure modes than <code>transmute_copy</code> (compiler can at least verify that sizes of objects match) and, of course, <code>transmute_copy</code> have fewer failure modes then <code>copy_nonoverlapping</code> (in addition to all failure modes that <code>transmute_copy</code> you now have to deal with possibilities of having two objects overlapping and pointer being invalid, etc).</p> <font class="QuotedText">&gt; You have replaced code which "narrowly" uses unsafe to do an unchecked array index with code that uses `transmute`, which has pretty-much unlimited chaos potential!</font> <p>That's still a good change. Heck, C++20 even <a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0476r2.html">added their own version of transmute</a> citing precisely <a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0476r2.html#bg">pifalls of correct use of memcpy</a> (C/C++ version of <code>copy_nonoverlapping</code>).</p> <p>P.S. I wanted to avoid discussion about <b>why</b> your approach to the whole thing is more-or-less ridiculous by assuming that you just wanted to show how it's not easy to use pointers in Rust, but if your goal is to just read integer then Rust documentation, of course, includes pretty good example which explains how to do what you want to do properly, without <b>any</b> unsafe code <a href="https://doc.rust-lang.org/std/primitive.u32.html#method.from_le_bytes">here</a>. And if you want to avoid panic there, then the simplest way is to just literally tell the compiler that you know what you are doing:</p> <pre> pub fn read_le_u32(input: &amp;[u8]) -&gt; u32 { if input.len() &lt; 4 { unsafe { std::hint::unreachable_unchecked() } } let (int_bytes, _) = input.split_at(std::mem::size_of::&lt;u32&gt;()); u32::from_le_bytes(int_bytes.try_into().unwrap()) } </pre> <p>That's it. It would be compiled into one instruction and there are really no need to invoke horrors of <code>transmute</code>, <code>transmute_copy</code> or <code>copy_nonoverlapping</code> if you really just want to eliminate the bounds check.</p> Fri, 20 Sep 2024 00:38:17 +0000 Unsafety can be subtle https://lwn.net/Articles/990951/ https://lwn.net/Articles/990951/ NYKevin <div class="FormattedComment"> <span class="QuotedText">&gt; Rust developers are ready to accommodate certain requests to help these people, but “fuck everyone without C experience and make their life miserable for the sake of 10% of Rust users who are using it as C replacement” doesn't sound like a reasonable request.</span><br> <p> Please stop making quotes up and attributing them to other people. It is extremely rude.<br> <p> <span class="QuotedText">&gt; Nope. This doesn't work like this. “I will ignore any and all rules that you may place on me” is an attitude problem, not documentation problem.</span><br> <p> Ibid.<br> <p> <span class="QuotedText">&gt; It's one thing to say “hey, I don't know how to implement this kind of design while staying in the boundaries outlined by the strict provenance approach”. Such stories (if justified and without any simple solution that would make them strict-provenance compliant) are always welcome on the URLO and IRLO or even just the bugtracker.</span><br> <p> I literally just told you a story like that, and you responded by making up a bunch of things I didn't say, and then ridiculing those things.<br> <p> Since this conversation is clearly going nowhere, I'm going to bow out.<br> </div> Thu, 19 Sep 2024 23:03:04 +0000 Unsafety can be subtle https://lwn.net/Articles/990931/ https://lwn.net/Articles/990931/ khim <font class="QuotedText">&gt; This is an incredible inference from example code I posted to illustrate pointer provenance rules and which has never actually been deployed in the form I described.</font> <p>That's not not <i>inference from the example code</i>, but more of <i>inference from your comments</i>. You are using <code>unsafe</code> function to do some manipulations that usually are done with normal, safe, code in an unsafe way by using function that's sole purpose is to save a tiny amount of execution time by bypassing the usual safety checks. And then you add <code>debug_assert</code> that, essentially, restores error-checking that is normally used by Rust programs unconditionally in debug build. And then complain that function that you used to bypass normal safety checks have poor documentation – while asking for clarifications that are <b>already present</b> in the sibling version of that same function, that's already referred as “safe alternative” there and which is one click away. Which means that, you probably, have never read the documentation for the safe variant: how else would you not notice that this variant already addresses all you concerns?</p> <p>Forgive me, but I fail to see how one would end up in that situation except if one have apriori decided for oneself that one is <b>not</b> interested in writing normal, safe code and would stick to the removal of Rust-provided guardrails as much as possible.</p> <p>Note: I'm not even saying that's it's <b>wrong</b> to write code that way. Maybe, for the kernel needs, it's even the best way and you haven't forgotten to erect manual check after you removed the normal Rust-provided provided check there.</p> <p>But that definitely puts you into a different usage mode: normally it's expected that Rust developer would stick to normal, “safe” interface as much as possible and would only remove guardrails where that's truly justified.</p> <p>Going down <b>that</b> “normal” road it's almost impossible to miss detailed specification that explains what <a href="https://doc.rust-lang.org/std/primitive.slice.html#method.get">get</a> function works, how is it supposed to be used, there are examples with a single argument and a range, etc.</p> Thu, 19 Sep 2024 19:35:34 +0000 Unsafety can be subtle https://lwn.net/Articles/990929/ https://lwn.net/Articles/990929/ apoelstra <div class="FormattedComment"> <span class="QuotedText">&gt;Your situation is a bit unusual because you have immediately decided to skip all the range-checking without testing and without verifying that these are the bottlenecks and are worth eliminating </span><br> <p> This is an incredible inference from example code I posted to illustrate pointer provenance rules and which has never actually been deployed in the form I described.<br> </div> Thu, 19 Sep 2024 19:09:06 +0000 Slice to `[u8;4]` https://lwn.net/Articles/990908/ https://lwn.net/Articles/990908/ atnot <div class="FormattedComment"> Personally I've never needed this because usually if you're reading bytes from a file, you'll be dealing with the `Read` trait, which means you can just `reader.read_exact(&amp;mut array[..])` which will let you handle it as an EOF.<br> <p> I do sometimes wish there was a function to return an array directly in the standard library and save that line of code, but honestly there's enough utility crates like bytemuck, binrw etc. that you'll probably want to be using anyway if you're doing a lot of reading bytes into filetypes.<br> </div> Thu, 19 Sep 2024 17:02:47 +0000 Unsafety can be subtle https://lwn.net/Articles/990895/ https://lwn.net/Articles/990895/ khim <font class="QuotedText">&gt; Though having said that, `get_unchecked` is a very old method and one of the classic "here's a case where you'd need to use unsafe" methods, so I'm skeptical that many users will carefully (or even casually) read the docs.</font> <p>Note that <code>get_unchecked</code> is, actually, range-check-skipping version of <a href="https://doc.rust-lang.org/std/primitive.slice.html#method.get">get</a> and it even <a href="https://doc.rust-lang.org/std/primitive.slice.html#method.get_unchecked">explicitly tells</a> you: <i>For a safe alternative see <a href="https://doc.rust-lang.org/std/primitive.slice.html#method.get">get</a></i> (with clickable link!), which actually then tells you that you may either access one element or range of elements with this method.</p> <p>Your situation is a bit unusual because you have immediately decided to skip all the range-checking without testing and without verifying that these are the bottlenecks and are worth eliminating (note that if they are easy to eliminate for human then often compiler can easily eliminate them, too, after inlining, which means these checks are not, necessarily, a performance bottlenecks and often where they <b>are</b> performance bottlenecks they are, often, desirable because if compiler couldn't prove that they are not needed then chances are high that it's not actually guaranteed by the structure of your code, either).</p> <p>That's why you have missed all these explanations (that are there for <a href="https://doc.rust-lang.org/std/primitive.slice.html#method.get">get</a>, but not for it's range-check-skipping sibling).</p> <p>That's <b>not</b> how slice is supposed to be used, normally! I guess documentation was just not written with people which would try to remove as many guardrails as possible as early as possible.</p> <p>Are you even sure in your case use of <a href="https://doc.rust-lang.org/std/primitive.slice.html#method.get_unchecked">get_unchecked</a> actually brings measurable performance wins over the use of <a href="https://doc.rust-lang.org/std/primitive.slice.html#method.get">get</a>?</p> Thu, 19 Sep 2024 14:20:46 +0000 Slice to `[u8;4]` https://lwn.net/Articles/990887/ https://lwn.net/Articles/990887/ farnz <p>Note that you can use <a href="https://doc.rust-lang.org/std/primitive.array.html#impl-TryFrom%3C%26%5BT%5D%3E-for-%5BT;+N%5D"><tt>try_from</tt></a> to convert a slice of the correct size into an array. Assuming that you've verified that the slice is big enough, this can't actually fail - and you'd expect the compiler to optimize out the failure path as a result. <p>And, indeed, when I go that route (and yes, this is slightly obscure), I get <a href="https://rust.godbolt.org/z/KG88aqxaf">the optimal form that cannot panic at runtime</a>: <pre> <code> use std::convert::TryInto as _; pub fn load_int_le(buf: &amp;[u8; 32], i: usize) -&gt; u32 { let slice = &amp;buf[0..4]; u32::from_le_bytes(slice.try_into().expect("load_int_le slicing issue Q1234Qload_int_leQ32Z32Z")) } </code> </pre> <p>The string "Q1234Qload_int_leQ32Z32Z" is in there as something that's unlikely to appear in the compiled binary by mistake; you can thus have release-mode CI grep for that string and fail if it appears, because you want the failure path to be resolved at compile time; if it does appear, you know where to check. Thu, 19 Sep 2024 13:46:21 +0000 Unsafety can be subtle https://lwn.net/Articles/990886/ https://lwn.net/Articles/990886/ apoelstra <div class="FormattedComment"> <span class="QuotedText">&gt;So what's so special about get_unchecked() that makes it different, exactly?</span><br> <p> To restate khim's post much more briefly: the difference is that as_ptr returns a raw pointer while get_unchecked returns a reference.<br> <p> I agree that it'd be helpful to say this in the docs (as well as to mention that you can call get_unchecked with a range if you want access to more than one element, which is how I ended up fixing my original code). I don't even think you need to mention C.<br> <p> Though having said that, `get_unchecked` is a very old method and one of the classic "here's a case where you'd need to use unsafe" methods, so I'm skeptical that many users will carefully (or even casually) read the docs.<br> </div> Thu, 19 Sep 2024 13:42:32 +0000 Unsafety can be subtle https://lwn.net/Articles/990861/ https://lwn.net/Articles/990861/ khim <font class="QuotedText">&gt; It is quite unreasonable to assume that people writing unsafe Rust have no preconceptions from C whatsoever.</font> <p>Yet it would be even more unreasonable, some would even say preposterious, to assume that <b>everyone</b> who uses Rust and even <code>unsafe</code> Rust is a C programmer.</p> <p>People who are using Rust and who never used C <b>do</b> exists and there would be more of them over the time.</p> <p>I wouldn't be surprised to find out that there are more of them already than Rust users that know C.</p> <p>The desire to bring Rust in kernel is driven, in large part, by the desire to bring precisely these people into the mix.</p> <font class="QuotedText">&gt; The bytes that make up the element are also the bytes that make up the buffer, so it is perfectly reasonable to interpret the two as synonymous when reading documentation casually.</font> <p>That's not true for the majority of the languages. If we only include popular languages then it's, essentially, true only for C and C++. C#, Go, Java, JavaScript, Python… nowhere would you find such equation. Most of these languages don't give you access to the part of the object, but if such ability is there then you get to touch that part and nothing else.</p> <font class="QuotedText">&gt; Rust cannot escape the shadow of C, as you can see by the the functions as_ptr() and friends, since they exist primarily for interoperation with C (as_ptr_range() says this explicitly).</font> <p>That's true, for some degree, but you can write lots of apps for years in Rust and never hit the need to know that dark corner of the language. Pushing its existence in the description of various perfectly normal, “safe” function would definitely be strange.</p> <p>Equally as strange as saying that you have to go and learn C before you would attempt Rust.</p> <p>Remember that <b>Rust wasn't even imagined as a replacement for C and C++, it was originally not developed for that audience and such work is still not it's primary focus</b>.</p> <p>Rust developers are ready to accommodate certain requests to help these people, but “fuck everyone without C experience and make their life miserable for the sake of 10% of Rust users who are using it as C replacement” doesn't sound like a reasonable request.</p> <font class="QuotedText">&gt; Either you tell everyone what the rules are in a highly explicit and unambiguous way, or some programmers will misunderstand them,</font> <p>Nope. This doesn't work like this. “I will ignore any and all rules that you may place on me” is an attitude problem, not documentation problem. And the only solution is social. Rust community <a href="https://steveklabnik.com/writing/a-sad-day-for-rust">does well there thus there's a chance</a>.</p> <b>Unsafe Rust is hard</b>. You just have to accept it. Yes, in an ideal world it would be easy. Yes, people <a href="https://www.ralfj.de/blog/2019/01/12/rust-2019.html">know it's a mess</a> and <a href="https://faultlore.com/blah/fix-rust-pointers/">try to fix that</a>. But right now the story is: you have to be careful.</p> <p>Sticking with strict provenance is your best bet right now (after you have looked on safe <a href="https://raphlinus.github.io/rust/2020/01/18/soundness-pledge.html">sound</a> wrapper around unsafety and couldn't find a suitable one for your usecase, of course). If you can do that. These are very strict, yet sensible, rules and they allow 99% of code that needs <code>unsafe</code> to be written. And the remaining 1%… they are still working on it.</p> <p>Complaining about the fact that something that is known to be underdocumented and hard and just saying that it's underdocumented and hard wouldn't help you if you have no constructive ideas about how to change that situation.</p> <font class="QuotedText">&gt; and then compiler writers will once again be stuck having to stick flags all over their shiny new optimizer because it breaks some legacy code that was wrong when it was written.</font> <p>Not if they would proactively kick out people who are writing code that ignores the rules.</p> <p>It's one thing to say “hey, I don't know how to implement this kind of design while staying in the boundaries outlined by the strict provenance approach”. Such stories (if justified and without any simple solution that would make them strict-provenance compliant) are always welcome on the <a href="https://users.rust-lang.org/">URLO</a> and <a href="https://internals.rust-lang.org/">IRLO</a> or even just <a href="https://github.com/rust-lang/unsafe-code-guidelines/issues">the bugtracker</a>.</p> <p>But the first line of defense should always be an attempt to <b>not use the <code>unsafe</code> code in the first place</b>! And the second line is to use <a href="https://raphlinus.github.io/rust/2020/01/18/soundness-pledge.html">sound</a> API. And third line is strict provenance. And only after <b>all these possibilities are exhausted</b> you go to these forums in a search of a solution.</p> <p>You tell us: <i>nobody is going to carefully scrutinize every word of docs.rust.org trying to figure out whether Professor Plum did it with the misaligned pointer in the .text section</i> – but that's <b>exactly</b> how fully conforming C code is supposed to be written! You <b>already</b> have to look on subtle nuiances of wording of the C standard and defect reports and other such things… Rust just makes it easier because there are various forums where you can ask Rust language developers for clarification.</p> <p>Unfortunately “we code for the hardware” people don't even stop to think about whether it's possible to do something while staying within boundaries – but that's social problem and can not be solved by technical means.</p> <p>Technology may just make conformance easier. And Rust language developers are trying to help with documentation and tooling (Miri is a must-have for someone who develops <code>unsafe</code> code in Rust), but, ultimately, only developer can be responsible for the conformance with the rules. Part where compiler does it's magic and where you <b>don't</b> have to <i>carefully scrutinize every word</i> exists <b>on the other side</b> of <code>unsafe</code>!</p> Thu, 19 Sep 2024 13:18:00 +0000 Unsafety can be subtle https://lwn.net/Articles/990881/ https://lwn.net/Articles/990881/ apoelstra <div class="FormattedComment"> <span class="QuotedText">&gt;As a bonus, the bounds check will apply in release mode too</span><br> <p> This isn't a bonus. The point of the original code was to avoid the bounds check and associated panic path.<br> <p> <span class="QuotedText">&gt;you can implement it with `unsafe` but without any tricky references or pointers:</span><br> <p> Aside from your new code now having `try_into` and an explicit panic path, it also illustrates my comment perfectly :). You have replaced code which "narrowly" uses unsafe to do an unchecked array index with code that uses `transmute`, which has pretty-much unlimited chaos potential! In this case your code appears to be correct, but I don't think "avoid pointers, always reach for transmute first" is a reasonable policy for authors of unsafe code.<br> </div> Thu, 19 Sep 2024 12:55:35 +0000 Unsafety can be subtle https://lwn.net/Articles/990879/ https://lwn.net/Articles/990879/ apoelstra <div class="FormattedComment"> The method you are quoting takes a [u8; 4], not a slice or a larger array.<br> </div> Thu, 19 Sep 2024 12:50:38 +0000 Unsafety can be subtle https://lwn.net/Articles/990859/ https://lwn.net/Articles/990859/ daroc <div class="FormattedComment"> This is an on-topic discussion, but please remember to keep things polite. Specifically:<br> <p> <span class="QuotedText">&gt; You couldn't tell the difference between “one” and “many”? That's explained pretty early in most schools. Maybe you forgot?</span><br> <p> This is not polite or respectful, and doesn't add anything interesting to your technical point. Please avoid insulting other commenters.<br> </div> Thu, 19 Sep 2024 11:53:32 +0000 Provenance rules not yet formalised https://lwn.net/Articles/990849/ https://lwn.net/Articles/990849/ farnz <p>You're right to say that the rules for provenance haven't yet been fully formalised, and I suspect that the operation you're talking about is in that set. <p>Right now, the "real" rules for pointer provenance are "whatever LLVM happens to do on this machine at this version, given that LLVM doesn't want to do anything that will shock C or C++ programmers". Strict provenance is a set of rules that are guaranteed to be stricter than whatever the final rules will be; the intention is that the final formalization of provenance rules will end up being equivalent to "strict provenance, except that these things banned by strict provenance are actually allowed in the final rules". <p>It'll probably not be written that way, though; there will be strict provenance rules (as today), and then a set of rules that are verified to be a superset of strict provenance rules. There may even be multiple tiers of this, where each tier is both less strict and harder to verify your code against than the tier above. <p>The idea remains, though, that if your code is compliant with strict provenance rules, it will definitely be compliant with the final rules for pointer provenance; whether those be <a href="https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2676.pdf">PVNI-ae-udi from draft N2676 for the C language</a>, or something with more subtleties in it. And there's thus a promise from the Rust compiler developers that they'll avoid breaking unsafe code that complies with strict provenance, even though the final provenance rules haven't yet been determined. Thu, 19 Sep 2024 09:11:00 +0000 Unsafety can be subtle https://lwn.net/Articles/990848/ https://lwn.net/Articles/990848/ donald.buczek <div class="FormattedComment"> <span class="QuotedText">&gt; Can we, please, stop the language lawyering.</span><br> <p> I don't understand why you have to devalue your otherwise interesting answers by using unnecessary fighting words. <br> <p> <span class="QuotedText">&gt; You don't say “can you identify a concrete rule which is violated?”</span><br> <span class="QuotedText">&gt; This asserts that only documentation and rules included in it matters and everything outside of it just simply doesn't exist or could be ignored.</span><br> <p> This interpretation of my question is wrong. <br> </div> Thu, 19 Sep 2024 09:01:41 +0000 Unsafety can be subtle https://lwn.net/Articles/990785/ https://lwn.net/Articles/990785/ NYKevin <div class="FormattedComment"> <span class="QuotedText">&gt; If Rust would have been a new version of C then sure. But Rust is not a new version of C and, in general, in Rust, you don't get the permission to access something that lies outside of that object that function gives you and, most importantly, nowhere near that point raw pointers are even discussed.</span><br> <p> Rust cannot escape the shadow of C, as you can see by the the functions as_ptr() and friends, since they exist primarily for interoperation with C (as_ptr_range() says this explicitly). It is quite unreasonable to assume that people writing unsafe Rust have no preconceptions from C whatsoever.<br> <p> <span class="QuotedText">&gt; There are big difference betwee a reference to an element or subslice and pointer to the slice’s buffer.</span><br> <p> The bytes that make up the element are also the bytes that make up the buffer, so it is perfectly reasonable to interpret the two as synonymous when reading documentation casually. If this is really an important distinction, then it needs an entire section of the 'nomicon, not just a couple of stray words in std::ptr and then a minor difference in phrasing here or there in other parts of std. This is not a game of Clue - nobody is going to carefully scrutinize every word of docs.rust.org trying to figure out whether Professor Plum did it with the misaligned pointer in the .text section.<br> <p> Either you tell everyone what the rules are in a highly explicit and unambiguous way, or some programmers will misunderstand them, and then compiler writers will once again be stuck having to stick flags all over their shiny new optimizer because it breaks some legacy code that was wrong when it was written.<br> </div> Thu, 19 Sep 2024 03:34:41 +0000 Unsafety can be subtle https://lwn.net/Articles/990783/ https://lwn.net/Articles/990783/ atnot <div class="FormattedComment"> Not to call the pot black as a kettle, but I would greatly appreciate if you could stop having the same near-identical heated argument under every C or Rust related post, and presumably so would others that haven't muted you yet.<br> </div> Thu, 19 Sep 2024 00:03:41 +0000 Unsafety can be subtle https://lwn.net/Articles/990778/ https://lwn.net/Articles/990778/ khim <font class="QuotedText">&gt; Because the reference was returned by slice::get_unchecked, and slice::get_unchecked is documented to have the same semantic meaning as C pointer arithmetic (but with the added constraint that it is illegal to construct a "one past the end" pointer, unlike in C where that is legal).</font> <p>Where is it documented that way? Official documentation is <a href="https://doc.rust-lang.org/std/primitive.slice.html#method.get_unchecked">pretty clear</a>: <i>returns a reference to <b>an element or subslice</b>, without doing bounds checking</i>. And subslice there means not <i>any random subslice</i> but specifically subslice specified by something like <a href="https://doc.rust-lang.org/std/ops/struct.Range.html">Range</a>. That's not how it was used in the discussed example, thus we can ignore that case.</p> <p>Nowhere does it tell is that you get permission to access anything outside of that single element (or slice).</p> <font class="QuotedText">&gt; C pointer arithmetic is generally understood to return a pointer with provenance over the whole array, so if you're going to change that rule, you really ought to do so explicitly.</font> <p>If Rust would have been a new version of C then sure. But Rust is not a new version of C and, in general, in Rust, you don't get the permission to access something that lies outside of that object that function gives you and, most importantly, nowhere near that point raw pointers are even discussed.</p> <p>Why function from not C, that returns something that C doesn't support and in a fashion that is typical for that language should include warning in the form of “hey, if you know about C then remember that this function works like a Rust function and not like a C function”. That would be really very strange. Obnoxious and repetitive (remember that most Rust developers don't, actually, know C, they come from Java or Python background).</p> <font class="QuotedText">&gt; Note also that a completely literal interpretation of your argument would equally well apply to slice::as_ptr()</font> <p>Sure, but result would be different. Because that one <a href="https://doc.rust-lang.org/std/primitive.slice.html#method.as_ptr">is different</a>: it <i>returns a raw pointer <b>to the slice’s buffer</b>.</i></p> <p>There are big difference betwee <i>a reference to an element or subslice</i> and <i>pointer to the slice’s buffer</i>.</p> <p>Element is, well, element. Singular. One byte. Buffer is <b>not</b> one element, it's content of the entire slice.</p> <font class="QuotedText">&gt; Nothing in either function's documentation clarifies that there is a meaningful distinction.</font> <p>You couldn't tell the difference between “one” and “many”? That's explained pretty early in most schools. Maybe you forgot?</p> <font class="QuotedText">&gt; So what's so special about get_unchecked() that makes it different, exactly?</font> <p>Well… the fact that it does different thing?</p> <font class="QuotedText">&gt; Unfortunately, in this case, we have the option of saying that it is indeed legal to do pointer arithmetic on pointers derived from get_unchecked(),</font> <p>Whoa, whoa, whoa. Of course you can do pointer aritmetic – as long as you don't go beyond boundaries of that one, single, byte that you have got access to!</p> <p>What else do you expect if you have got reference <b>to one byte</b> and not reference to <b>the whole buffer</b>?</p> <font class="QuotedText">&gt; or we have the option of saying that it is not possible to use as_ptr_range() for anything other than accessing the first element.</font> <p>Whoa, whoa, whoa. Why would that be the case? One function returns reference to one, <b>single</b>, element (or subslice), another function returns pointer <b>to buffer</b> and third one <a href="https://doc.rust-lang.org/std/primitive.slice.html#method.as_ptr_range">returns</a> <i>two raw pointers spanning the slice</i>.</p> <p>Why would they behave identically if they return references and/or pointers that deal with <b>different entities</b>. How is that ever logical?</p> <font class="QuotedText">&gt; If it is the second one (stricter provenance for references than for raw pointers), what exactly are those rules, and where can I read about them?</font> <p>Why would you need any such rules? If your pointer or reference are pointing to <b>one element</b>, then you can touch that element and nothing else. If your pointer or reference are pointing to <b>the entire buffer</b> then the whole buffer is fair game.</p> <p>It's really as simple as that: there are no radical difference between pointer and reference in the [naïve] approach to their provenance (experimental models relax the restrictions, don't add a new ones), but these functions return references (or pointers) <b>to a different objects</b>, why should they behave identically?</p> Wed, 18 Sep 2024 23:26:09 +0000 Unsafety can be subtle https://lwn.net/Articles/990775/ https://lwn.net/Articles/990775/ NYKevin <div class="FormattedComment"> <span class="QuotedText">&gt; How is this even relevant? There are no “shrinkage of provenance” in that example. You have reference that's pointing to one, single byte. That means that you get to access just one, single, byte and nothing more.</span><br> <p> Because the reference was returned by slice::get_unchecked, and slice::get_unchecked is documented to have the same semantic meaning as C pointer arithmetic (but with the added constraint that it is illegal to construct a "one past the end" pointer, unlike in C where that is legal). C pointer arithmetic is generally understood to return a pointer with provenance over the whole array, so if you're going to change that rule, you really ought to do so explicitly.<br> <p> Note also that a completely literal interpretation of your argument would equally well apply to slice::as_ptr(), because the return type of that function is const *T, not some nonexistent unsafe slice type (and so a pedantically literal interpretation is that you may only access the first element of the slice through said pointer, because it is a pointer to T, not a pointer to unsafe-slice-ish of T).<br> <p> In fact, I cannot find a solid reason to allow one and not the other. Nothing in either function's documentation clarifies that there is a meaningful distinction. At the same time, it is obvious (by the existence of e.g. as_ptr_range()) that this is at least meant to be allowed in the case of as_ptr(). So what's so special about get_unchecked() that makes it different, exactly?<br> <p> <span class="QuotedText">&gt; That's direct consequence of refusal to adopt insanity of C/C++ TBAA: if we no longer consider memory as typed where different pieces of memory turn into differently typed objects magically, then boundaries of objects are now parts of pointers and references, for how else can we reason about them?</span><br> <p> It sounds as if you're saying that the rules for pointers are the same as the rules for references, which I agree makes logical sense. Unfortunately, in this case, we have the option of saying that it is indeed legal to do pointer arithmetic on pointers derived from get_unchecked(), we have the option of saying that references have stricter provenance rules than raw pointers, or we have the option of saying that it is not possible to use as_ptr_range() for anything other than accessing the first element. The latter is obviously ridiculous and untenable, so which of the first two is your interpretation of this case? If it is the second one (stricter provenance for references than for raw pointers), what exactly are those rules, and where can I read about them?<br> </div> Wed, 18 Sep 2024 22:39:24 +0000 Unsafety can be subtle https://lwn.net/Articles/990771/ https://lwn.net/Articles/990771/ khim <font class="QuotedText">&gt; I still cannot find a single, authoritative source which explicitly documents all of the operations that can shrink provenance, and I'm not 100% convinced that it has even been formalized in the first place.</font> <p>How is this even relevant? There are <b>no</b> “shrinkage of provenance” in that example. You have reference that's pointing to one, single byte. That means that you get to access just one, single, byte <b>and nothing more</b>.</p> <p>That's direct consequence of refusal to adopt insanity of C/C++ <a href="https://www.cs.cornell.edu/courses/cs6120/2019fa/blog/tbaa/">TBAA</a>: if we no longer consider memory as typed where different pieces of memory turn into differently typed objects magically, then boundaries of objects are now parts of pointers and references, for how else can we reason about them?</p> <p>This automatically and immediately makes this example illegal. Which is good for everyone concerned: given the fact that out-of-object accesses are core issue with 90% of all exploits we <b>don't</b> want to declare such accesses “normal”.</p> <font class="QuotedText">&gt; But if something is marked as "non-normative and experimental" in the documentation, I personally am going to ignore it until such time as that label goes away.</font> <p>Then you couldn't do many things then these “non-normative and experimental” models give you. You are left, essentially, with this: <a href="https://doc.rust-lang.org/std/ptr/index.html#safety">The result of casting a reference to a pointer is valid for as long as the underlying object is live and no reference (just raw pointers) is used to access the same memory</a>.</p> <p>All other usages (in particular the potential ability to go from a single byte to something larger) need these “non-normative and experimental” models because without them they <b>all</b> these operations fall under the <i>the precise rules for validity are not determined yet</i> clause.</p> <p>This reading, most definitely, doesn't give you the ability to access anything outside of that one, single, byte that you received from <code>get_unchecked</code> Wed, 18 Sep 2024 21:37:16 +0000 Unsafety can be subtle https://lwn.net/Articles/990770/ https://lwn.net/Articles/990770/ NYKevin <div class="FormattedComment"> OK, "nobody" was maybe an exaggeration. But if something is marked as "non-normative and experimental" in the documentation, I personally am going to ignore it until such time as that label goes away.<br> <p> The other problem is that you have to read these rules extremely carefully to even notice that this is illegal in the first place, because they're almost exclusively focused on the usize -&gt; ptr conversion, and barely acknowledge that "shrinking provenance" is a thing that can happen through other operations. I still cannot find a single, authoritative source which explicitly documents all of the operations that can shrink provenance, and I'm not 100% convinced that it has even been formalized in the first place.<br> </div> Wed, 18 Sep 2024 18:37:22 +0000 Unsafety can be subtle https://lwn.net/Articles/990705/ https://lwn.net/Articles/990705/ khim <font class="QuotedText">&gt; ...And what do you do if the rules are ambiguous or do not match reality?</font> <p>The important thing is what you <b>don't do</b>. You don't say “can you identify a concrete rule which is violated?”</p> <p>This asserts that only documentation and rules included in it matters and everything outside of it just simply doesn't exist or could be ignored.</p> Wed, 18 Sep 2024 13:03:27 +0000 Unsafety can be subtle https://lwn.net/Articles/990704/ https://lwn.net/Articles/990704/ pizza <div class="FormattedComment"> <span class="QuotedText">&gt; No. The “entire point” of Rust is to make program safer. Highly-opinionated rules (as well as any other rules) help as long as they are followed.</span><br> <p> ...And what do you do if the rules are ambiguous or do not match reality?<br> <p> while (&lt;undesireable behavior occurs&gt;) {<br> if (&lt;behavior allowed by spec&gt;) {<br> if (!&lt;we care&gt;) {<br> break; // The typical answer of C language stewards<br> } else {<br> // bug in specification<br> fix_spec(); // The typical answer of Rust language stewards<br> }<br> } else { <br> // bug in compiler/tooling<br> fix_implementation();<br> }<br> }<br> <p> </div> Wed, 18 Sep 2024 12:35:52 +0000 Unsafety can be subtle https://lwn.net/Articles/990702/ https://lwn.net/Articles/990702/ khim <font class="QuotedText">&gt; Language lawyering is how "problems" with your language are identified</font> <p>Sure. That's how you cause dissent and doubt. Why is that needed here?</p> <font class="QuotedText">&gt; Strongly enforcing a still-growing set of highly opinionated rules is the *entire point* of Rust.</font> <p>No. The “entire point” of Rust is to make program safer. Highly-opinionated rules (as well as any other rules) help as long as they are followed.</p> <p>And language lawyering (attempt to use the documentation as holy gospel while forcibly ignoring things that exist outside of it) is not how rules are followed, but the exact opposite: it's the way to dig extra rules from the exact same text.</p> <p>It's useful activity only as long as you are planning to improve the documentation itself. To show that documentation contradicts the implementation or is deficient for some other reason (e.g. if it have self-contradictions or something that couldn't be supported), etc.</p> <p>When you are doing that to find an excuse to do or not do something… this just splinters the community, because different people may “discover” different things in the exact same “holy” text.</p> Wed, 18 Sep 2024 12:19:37 +0000 Unsafety can be subtle https://lwn.net/Articles/990701/ https://lwn.net/Articles/990701/ pizza <div class="FormattedComment"> <span class="QuotedText">&gt; Can we, please, stop the language lawyering. That's how C turned into the disaster, there are no need to repeat that story.</span><br> <p> Language lawyering is how "problems" with your language are identified [1]. How those "problems" are handled/resolved is another matter entirely.<br> <p> [1] Strongly enforcing a still-growing set of highly opinionated rules is the *entire point* of Rust. <br> </div> Wed, 18 Sep 2024 11:51:17 +0000