Why Safety Profiles Failed

(circle-lang.org)

64 points | by pjmlp 3 hours ago ago

28 comments

  • SubjectToChange an hour ago

    At this point I'm wondering if the purpose of safety profiles is simply to serve as a distraction. In other words, safety profiles are something people can point to when the topic of memory safety comes up. The objectives of the initiative always seemed hopelessly optimistic, if not absurd. In particular, I don't understand why littering a codebase with auto, const, constexpr, inline, [[nodiscard]], noexcept, etc is wonderful, yet lifetime annotations are somehow an intolerable tyranny.

  • alilleybrinker 2 hours ago

    The article makes the particularly good point that you generally can’t effectively add new inferences without constraining optionality in code somehow. Put another way, you can’t draw new conclusions without new available assumptions.

    In Sean’s “Safe C++” proposal, he extends C++ to enable new code to embed new assumptions, then subsets that extension to permit drawing new conclusions for safety by eliminating code that would violate the path to those safety conclusions.

  • loeg 6 minutes ago

    Section 6 seems to propose adding essentially every Rust feature to C++? Am I reading that right? Why would someone use this new proposed C++-with-Rust-annotations in place of just Rust?

    • ijustlovemath a minute ago

      Because the millions of lines of existing C++ aren't going anywhere. You need transition capability if you're ever gonna see widespread adoption. See: C++'s own adoption story; transpiling into C to get wider adoption into existing codebases.

    • steveklabnik 4 minutes ago

      Here’s the actual proposal: https://safecpp.org/draft.html

      It explains its own motivation.

  • steveklabnik 2 hours ago

    Really glad to see this thorough examination of the weaknesses of profiles. Safe C++ is a really important project, and I hope the committee ends up making the right call here.

    • SubjectToChange 26 minutes ago

      >...I hope the committee ends up making the right call here.

      WG21 hasn't been able to solve the restrict type qualifier, or make a better alternative, in over twenty years. IMO, hoping that WG21 adequately solves Safe C++ is nothing more than wishful thinking, to put it charitably.

      • steveklabnik 3 minutes ago

        I am intimately familiar with the dysfunctions of various language committees.

        I never said it would be easy, or probable. But I’m also the kind who hopes for the best.

    • wyager an hour ago

      > Safe C++ is a really important project

      What makes you say this? It seems to me like we already have a lower-overhead approach to reach the same goal (a low-level language with substantially improved semantic specificity, memory safety, etc.); namely, we have Rust, which has already improved substantially over the safety properties of C++, and offers a better-designed platform for further safety research.

      • alilleybrinker an hour ago

        Not everything will be rewritten in Rust. I've broken down the arguments for why this is, and why it's a good thing, elsewhere [1].

        Google's recent analysis on their own experiences transitioning toward memory safety provide even more evidence that you don't need to fully transition to get strong safety benefits. They incentivized moving new code to memory safe languages, and continued working to actively assure the existing memory unsafe code they had. In practice, they found that vulnerability density in a stable codebase decays exponentially as you continue to fix bugs. So you can reap the benefits of built-in memory safety for new code while driving down latent memory unsafety in existing code to great effect. [2]

        [1]: https://www.alilleybrinker.com/blog/cpp-must-become-safer/

        [2]: https://security.googleblog.com/2024/09/eliminating-memory-s...

      • steveklabnik an hour ago

        I am pro any movement towards memory safety. Sure, I won't stop writing Rust and start moving towards C++ for this. But not everyone is interested in introducing a second toolchain, for example. Also, as this paper mentions, Safe C++ can improve C++ <-> Rust interop, because Safe C++ can express some semantics Rust can understand. Right now, interop works but isn't very nice.

        Basically, I want a variety of approaches, not a Rust monoculture.

      • tptacek an hour ago

        This is a thread about a C++ language feature; it's probably most productive for us to stipulate for this thread that C++ will continue to exist. Practical lessons C++ can learn moving forward from Rust are a good reason to talk about Rust; "C++ should not be improved for safety because code can be rewritten in Rust" is less useful.

      • SubjectToChange an hour ago

        Things like web browsers will continue to have millions of lines of C++ code regardless of how successful Rust becomes. It would be a huge improvement for everyone if such projects had a tractable path towards memory safety

      • akira2501 an hour ago

        Cool.

        Do you mind if we have more than one approach?

  • o11c an hour ago

    "No mutable aliases" is a mistake; it prevents many useful programs.

    Now that virtual address space is cheap, it's possible to recompile C (or presumably C++) with a fully-safe runtime (requiring annotation only around nasty things like `union sigval`), but this is an ABI break and has nontrivial overhead (note that AddressSanitizers has ~2x overhead and only catches some optimistic cases) unless you mandate additional annotation.

    • mananaysiempre an hour ago

      > AddressSanitizer has ~2x overhead

      I’ve got some programs where the ASan overhead is 10× or more. Admittedly, they are somewhat peculiar—one’s an interpreter for a low-level bytecode, the other’s largely a do-nothing benchmark for measuring the overhead of a heartbeat scheduler. The point is, the overhead can be vary a lot depending on e.g. how many mallocs your code does.

      This does not contradict your point in any way, to be clear. I was just very surprised when I first hit that behaviour expecting ASan’s usual overhead of “not bad, definitely not Valgrind”, so I wanted to share it.

    • tialaramex an hour ago

      > "No mutable aliases" is a mistake; it prevents many useful programs.

      Does it? You didn't list any. It certainly prevents writing a tremendous number of programs which are nonsense.

      • o11c an hour ago

        The entirety of Rust's `std::cell` is a confession that yes, we really do need mutable aliases. We just pretend they the aliases aren't mutable except for a nanosecond around the actual mutation.

        • steveklabnik an hour ago

          It’s more than that, they disable the aliasing based optimizations, and provide APIs that restrict how and when you can mutate in order to make sure data races don’t happen.

          Controlled mutable aliasing is fine. Uncontrolled is dangerous.

        • alilleybrinker an hour ago

          Alternatively, Rust's cell types are proof that you usually don't need mutable aliasing, and you can have it at hand when you need it while reaping the benefits of stronger static guarantees without it most of the time.

        • JoshTriplett 25 minutes ago

          Cells still don't allow simultaneous mutable aliases; they just allow the partitioning of regions of mutable access to occur at runtime rather than compile time.

    • stouset an hour ago

      > it prevents many useful programs

      Every set of constraints prevents many useful programs. If those useful programs can still be specified in slightly different ways but it prevents many more broken programs, those constraints may be a net improvement on the status quo.

    • murderfs an hour ago

      virtual address space is cheap, but changing it is massively expensive. If you have to do a TLB shootdown on every free, you're likely going to have worse performance than just using ASan.

      • o11c an hour ago

        Dealing with malloc/free is trivial and cheap - just give every allocated object a couple of reference counts.

        The hard part is figuring out which words of memory should be treated as pointers, so that you know when to alter the reference counts.

        Most C programs don't rely on all the weird guarantees that C mandates (relying on asm, which is also problematic, is probably more common), but for the ones that do it is quite problematic.

        • steveklabnik 2 minutes ago

          The borrow checker works irrespective of the heap. Memory safety involves all pointers, not just ones that own a heap allocation.

        • acbits 12 minutes ago

          https://github.com/acbits/reftrack-plugin

          I wrote a compiler extension just for this issue since there wasn't any.

        • akira2501 an hour ago

          > just give every allocated object a couple of reference counts.

          Works great with a single thread.

          • o11c an hour ago

            Multi-threaded refcounts aren't actually that hard?

            There's overhead (depending on how much you're willing to annotate it and how much you can infer), but the only "hard" thing is the race between accessing a field and and changing the refcount of the object it points to, and [even ignoring alternative CAS approaches] that's easy enough if you control the allocator (do not return memory to the OS until all running threads have checked in).

            Note that, in contrast the the common refcount approach, it's probably better to introduce a "this is in use; crash on free" flag to significantly reduce the overhead.