Want to read Slashdot from your mobile device? Point it at m.slashdot.org and keep reading!

 



Forgot your password?
typodupeerror
×
Programming

An Alternative to Rewriting Memory-Unsafe Code in Rust: the 'Safe C++ Extensions' Proposal (theregister.com) 105

"After two years of being beaten with the memory-safety stick, the C++ community has published a proposal to help developers write less vulnerable code," reports the Register.

"The Safe C++ Extensions proposal aims to address the vulnerable programming language's Achilles' heel, the challenge of ensuring that code is free of memory safety bugs..." Acknowledging the now deafening chorus of calls to adopt memory safe programming languages, developers Sean Baxter, creator of the Circle compiler, and Christian Mazakas, from the C++ Alliance, argue that while Rust is the only popular systems level programming language without garbage collection that provides rigorous memory safety, migrating C++ code to Rust poses problems. "Rust lacks function overloading, templates, inheritance and exceptions," they explain in the proposal. "C++ lacks traits, relocation and borrow checking. These discrepancies are responsible for an impedance mismatch when interfacing the two languages. Most code generators for inter-language bindings aren't able to represent features of one language in terms of the features of another."

Though DARPA is trying to develop better automated C++ to Rust conversion tools, Baxter and Mazakas argue telling veteran C++ developers to learn Rust isn't an answer... The Safe C++ project adds new technology for ensuring memory safety, Baxter explained, and isn't just a reiteration of best practices. "Safe C++ prevents users from writing unsound code," he said. "This includes compile-time intelligence like borrow checking to prevent use-after-free bugs and initialization analysis for type safety." Baxter said that rewriting a project in a different programming language is costly, so the aim here is to make memory safety more accessible by providing the same soundness guarantees as Rust at a lower cost. "With Safe C++, existing code continues to work as always," he explained. "Stakeholders have more control for incrementally opting in to safety."

The next step, Baxter said, involves greater participation from industry to help realize the Safe C++ project. "The foundations are in: We have fantastic borrow checking and initialization analysis which underpin the soundness guarantees," he said. "The next step is to comprehensively visit all of C++'s features and specify memory-safe versions of them. It's a big effort, but given the importance of reducing C++ security vulnerabilities, it's an effort worth making."

This discussion has been archived. No new comments can be posted.

An Alternative to Rewriting Memory-Unsafe Code in Rust: the 'Safe C++ Extensions' Proposal

Comments Filter:
  • Complicate much? (Score:4, Insightful)

    by JamesTRexx ( 675890 ) on Sunday October 20, 2024 @07:16PM (#64880001) Journal

    "Rust lacks function overloading, templates, inheritance and exceptions,"

    They say this as if it's a bad thing.

    • They also didn't mention that Rust does have macros (lisp-ish macros, not silly string substitutions like C macros). These are used for many of the things that would be done with templates in C++.

    • Re:Complicate much? (Score:5, Interesting)

      by caseih ( 160668 ) on Sunday October 20, 2024 @10:05PM (#64880167)

      It is if you want to migrate a C++ application over to something safer. A complete rewrite is not always feasible.

      Circle C++ is pretty impressive. I'm glad to see the ideas developed there move into mainstream C++. From what I've seen in Circle, this should dramatically reduce the learning curve for C++ developers.

    • I depend on all of those things. I'm a bit surprised, though, I thought Rust had templates at least.
    • by Pieroxy ( 222434 )

      Moreover, adding safe extensions to C++ will get manager the stamp they need as "having a safe language" while nothing will be done on the project to actually adhere to these extensions. Migrating your C++ code to these extensions will require a major rewrite of your app, while still not guaranteeing everything is safe in your codebase.

      • by Uecker ( 1842596 )

        In practice Rust code will be littered with "unsafe" and questionable dependencies.

        I start to believe hat this is all partially driven to avoid product liability: "Nobody can write C/C++ code so we can not be responsible for our mistakes, this will all change in the future with Rust, but please leave us alone for now!" In reality, when you look most mistakes are very basic and as many pointed out, memory safety is just one issue of many. So I do not expect a huge different with Rust.

    • Re:Complicate much? (Score:5, Interesting)

      by Scythal ( 1488949 ) on Monday October 21, 2024 @02:03AM (#64880409)
      Those are quite annoying limitations, indeed. Templates aren't really a major concern, and I understand the issue with exceptions - they're thinking about removing unwinding, too. But overloading and inheritance are quite important concepts in a modern language, so it's weird they're so fierce about it when it can make the code much cleaner (no wonder the GUI frameworks are so cumbersome in Rust). I see many people are very confused about inheritance. I think it comes from a misinterpretation of what the Gang of Four said about it, so they keep repeating that we should do composition instead, like a badly understood dogma. It's simply not true, as many patterns are much better off with inheritance than the awkward composition (prone to induce bugs and miscomprehension of the code structure).
      • Zig makes similar choices for overloading and inheritance. In Zig-land, this is due to the language focus on zero-cost abstractions. If you want to implement overloading or inheritance, you can, but you are subject to the mechanics of how that actually has to happen (e.g., writing a vtable for inheritance, or providing switches over structures args for overloading).

        ELF also doesn't have any concept of function overloading for shared libraries, if I'm not mistaken. So your code tends to mold closer to FFI.

    • I didn't realize it was even possible to write memory unsafe code in Rust.
      • It is. Due to long (8 years and counting) standing bugs, it's even possible to segfault even without Rust's "unsafe" keyword.

        Don't believe the hype (religion).

    • Yes it is.
      Or why do you think I prefer C++ over Rust?

    • "Rust lacks function overloading, templates, inheritance and exceptions,"

      They say this as if it's a bad thing.

      It's also not true, except for function overloading, which isn't really a big issue. Rust absolutely has generics which aren't precisely the same as C++ templates, but accomplish the same tasks. If you include Rust's macros, the result is actually much more powerful than C++ templates (and, no, Rust's macros aren't anything like the simplistic string substitution C/C++ provide). Rust's traits provide all of the really important benefits of inheritance, but avoid most of the pitfalls. The one thing C++ inhe

      • the most common programming environments are OSes where allocation can never really fail anyway. For example, with Linux and normal libraries, allocation always succeeds because what it really allocates is a chunk of virtual address space (I guess you can exhaust that on 32-bit platforms), not physical RAM.

        Always is a strong word, and it's the exception to the ill-conceived rule that fucks you.
        It is correct that allocations will not usually fail.
        However, heap is expanded with either an sbrk() or mmap(), both of which can fail.

        In the modern world of cgroup-aware init() processes, assuming your malloc() cannot fail is bloody fucking dangerous.

    • Yes and no. These are features that can be extremely useful but in practice often serve to bloat or obfuscate code, or have a more bug prone solution.

      Function Overloading I've never been fond of, mostly because it confuses so many readers of the code. The intent seems to be to act like true object oriented languages like Smalltalk, where all functions are inherently object methods, including arithmetic. In practice it leads to cases of "that + does not do what you think it does" confusion.

      Templates while

  • 2 dimensional silicon memory binary memory will not manage itself. And you can't just assume that on that vast plane a byte will stop and start where you want it to. You have to know. Isn't that how the bad guys do it? Knowing where your byte is AFTER you ASSUME it its somewhere else?

    • A lot of programmers don't understand how 2 dimensional silicon memory binary memory works. You can't find enough programmers who do understand it, so you hire people who don't.

      Instead of training them, you just give them Rust or Python and don't worry about it.
    • by SirSlud ( 67381 )

      could you speak on this more? I would love some more of this word salad

      • by drnb ( 2434720 )

        could you speak on this more? I would love some more of this word salad

        I think it's a Star Trek: The Next Generation reference, the Android "Data" explaining a problem to someone. :-)

  • by lsllll ( 830002 ) on Sunday October 20, 2024 @07:50PM (#64880045)

    It seems to me from CVE breakdown by type [cvedetails.com] that memory issues result in a somewhat small subset of total CVEs. Where is this concerted effort of making more languages police the programmers' use of memory coming from? Sees like XSS is much more of a culprit in regard to vulnerabilities, despite modern browsers' locking down of XSS interactions. Is it because the languages are trying to adapt to corporations seeking cheaper and cheaper programmers?

    • by FeelGood314 ( 2516288 ) on Sunday October 20, 2024 @08:04PM (#64880061)
      Memory issues can be found by noobs running scans on executables. The real bugs are in people completely missing what the attack is and having no mitigations at all against the attack. If you want secure software:
      1: list out what you are protecting - a secret, authentication for something else to do something, control to something
      2: list out what your opponents are, their motivation, their resources, their access - is it a script kiddy, a foreign government, do they have physical access
      3: list what the attacks could be - physically damaging your device, bypassing it, signal blocking, replaying an old command...
      4: come up with mitigations to all the attacks. ***All mitigations must trace back to an attack ****
      5: evaluate your system. How complicated is it? Could the things you are protecting be individually protected or is everything protected at once? Do your mitigations actually mitigate the attacks they are mapped to? Have you missed any attacks and can you accept those vulnerabilities? Go back to how complicated your system is. If you can't explain it, then no single person can take ownership of the security and you will have attacks with no mitigations.
      • The real bugs are in people completely missing what the attack is and having no mitigations at all against the attack.

        ...

        4: come up with mitigations to all the attacks. ***All mitigations must trace back to an attack ****

        In that case, what are all of your mitigations against unchecked bounds, use after free, double free, dereferencing invalid pointers, and their related cousins, dirty reads, and dirty writes?

        • by Anonymous Coward

          Those aren't attacks, retard.

          Go away.

        • by gillbates ( 106458 ) on Monday October 21, 2024 @10:22AM (#64881245) Homepage Journal

          ...what are all of your mitigations against unchecked bounds, use after free, double free, dereferencing invalid pointers, and their related cousins, dirty reads, and dirty writes?

          The STL. And good design practices.

          Seriously. Whenever I hear about C++ and memory bugs, I think back to 1998 when that was seriously an issue. Of the following types of memory failures you mentioned:

          1. use after free
          2. double free
          3. dereferencing invalid pointers
          4. dirty reads and writes.

          I have found none in the code my colleagues or I have written in the past decade, if not longer. Yes, it has been more than ten years since I've found C++ code with a memory bug, and I've worked on projects with more than 10 million lines of code. Since we've adopted the STL and some sane design principles, the only issue we occasionally get is that we catch an exception for out-of-bounds conditions in third party libraries. But at least we can catch the exception and continue.

          The sort of stack-smashing security exploitable memory overrun hasn't been a thing in C++ for the past decade, for anyone who's been keeping up with the changes in C++. If you think the average programmer is going to go back to malloc() and free() and keeping track of memory after using the STL, you've got another think coming. No one who uses the STL - even for a trivial project - thinks to themselves, "Gee, I wish I had to keep track of memory again". Likewise for those using shared pointers - once you have that convenience, you don't go back to doing things the old way.

      • by Bongo ( 13261 )

        That's a real risk assessment (often formalised into various methods) and essentially I think it is right.

        It then becomes a huge pain getting people to do it. So I think there's some psychological or mental state thing which gets in the way.

        It may just be that when writing code, people are using a mental state that's focussed on discrete things to achieve a specific target, whereas risk is all about uncertainty, and having to handle multiple uncertainties and multiple novelties. It just makes people's brain

      • Memory issues can be found by noobs running scans on executables.

        No, they can't. Valgrind, etc. can find many issues, but not all. Valgrind + fuzzing can find a lot more, but will never flush them all out.

        The real bugs are in people completely missing what the attack is and having no mitigations at all against the attack.

        Sure, memory safety is orthogonal to proper threat modeling and secure design. You need both. All of the effort in the world applied to threat modeling won't protect you from memory safety bugs, nor will using the best memory safety tools protect you from insecure design.

    • Xss is language agnostic.
      I dont see how the two are comparable in the context of compilers and languages

      • by lsllll ( 830002 ) on Sunday October 20, 2024 @08:44PM (#64880107)

        I'm aware of that. What I was alluding to was that perhaps fixing buffer overrun and such issues via changes to languages is an effort to make programming more fool-proof and that it may result in possible lower wages for better programmers by giving sub-par programmers the tools to compete on a more level playing field.
         

        • ... it may result in possible lower wages for better programmers by giving sub-par programmers the tools to compete on a more level playing field.

          So your argument is that making programming easier is bad because it increases competition?

          By that logic, we should code everything in assembly and COBOL. That will raise salaries through the roof.

          • It would also significantly reduce the average quality of programmers in the field. If every job takes 5x the effort, assuming you still want to do the job, you'd have to hire 5x the people. The top of the talent pool is already employed. But, hey, if they can spell COBOL maybe they can be useful.
    • by Samantha Wright ( 1324923 ) on Sunday October 20, 2024 @10:26PM (#64880187) Homepage Journal

      Cross-site scripting attacks do not generally involve issues that the C++ designers can address. They are, at best, logic errors on the part of browser programmers who didn't implement their APIs according to their own specs.

      Now, disregarding XSS, the total number of overflow and memory corruption bugs exceeds all the others combined: 37695 vs 33290 in the years 2014 to 2024—those two categories add up to 38% of all CVEs in the time period. That's a lot of wasted labor brought on by a reckless corner-cutting decision made 50 years ago by Ken Thompson and Dennis Ritchie, who thought PL/I's length-tagged strings were too much work for their cruddy little hand-me-down PDP-7 to handle.

      • Most overflow and memory corruption defects no longer lead to CVEs. Address space layout randomization, Control Flow Guard, et cetera make memory issues non-exploitable. Instead the program just crashes. That could be part of a DoS but often just a normal user trying to use the buggy program. If the program you had written to help your business crashes, it's not much comfort that the bug isn't exploitable. It's still a failure that costs money.
    • Because it's an itch we can scratch. OK, everyone wants you to scratch differently and sometimes it just makes the itch worse, but it's still easier than dealing with any of the other, more significant, problems.
    • Applications need to be both *secure* and *correct*. Modern compilers have made memory overflow no longer an exploitable defect. However, overflows will still cause incorrect behavior and crashes.

      Languages are trying to evolve toward cheaper development which is not quite the same as cheaper programmers. If you look at metrics like lines of code per day, they are largely unchanged over time. Good programmers go at a certain rate. Maybe bad ones make more LoC per day or maybe they make less, I don't

    • It seems to me from CVE breakdown by type that memory issues result in a somewhat small subset of total CVEs.

      Memory corruption CVEs tend to dominate the most critical vulnerabilities, though. They're the primary vector for arbitrary code execution exploits.

  • by Pseudonymous Powers ( 4097097 ) on Sunday October 20, 2024 @07:51PM (#64880051)
    I think I remember a similar proposal from ten years ago. Didn't somebody advocate around then for a bunch of functions whose names were suffixed with "_safe"?
    • by youn ( 1516637 )

      let's call this _safe_safe_for_realzies_this_time_i_swear :p

      this seems more involved and I am glad some are getting the message, potentially can be a good thing

  • by LindleyF ( 9395567 ) on Sunday October 20, 2024 @08:09PM (#64880071)
    Is a legitimately good idea. Anything that moves errors from runtime to compile time is beneficial.
    • by caseih ( 160668 )

      Definitely. That and other compile-time checks including checking that all enums are handled properly. Circle C++ does all of this. Getting the concepts developed in Circle into the core C++ standard will be highly beneficial. C++ is still complex and crufty, but you can not use the old, complicated stuff in favor of the new safe constructs and syntax. No one should be passing raw pointers around. std:: has contained some powerful reference-counting smart pointers for years now that were a step in the r

      • Shared_ptr is very useful when you need it, but you usually don't need it. Unique_ptr is essential, though. But I disagree that raw ptrs should never be used. They do have a place. But *owning* raw ptrs should never happen. If you see a raw ptr, you should be able to assume it is unowned.
        • This. If the committee would figure out optional references we would have a lot fewer use cases for raw pointers as well.

        • In what circumstance would a unique or shared pointer not be adequate and force you to use a raw pointer? I know you cannot use a unique pointer in Qt alot but shared pointers work fine.
          • Well, first, there's legacy codebases you might have to interact with. Second, reference counting isn't free. You don't want to use it everywhere, due to the atomic increment cost, the way it lets you be lazy about lifetime design, and the corresponding inability to reason about when destructors will run. Lifetimes guaranteed by scope are much easier to reason about. Now, you can use a const unique_ptr& as a "non-owning" parameter, but T* is usually just as good in that context, and it puts fewer limits
            • Ok well can't say I have ever done that kind of programming that it matters that much what a shared pointer costs. But if you are doing low level system programming that needs that speed than I should hope you understand memory allocations inside and out.
          • when you pass it to an external library
      • by ArmoredDragon ( 3450605 ) on Sunday October 20, 2024 @11:21PM (#64880245)

        It feels like they're trying to reinvent rust and just slap the C++ moniker on it so they can say they didn't have to learn a new language.

        Besides, the biggest gripe most of them have against rust to begin with IS the borrow checker, and this is despite the fact that they like to pat themselves on the back about how good at RAII they are, and then violate its principles anyways.

        Circle C++ does all of this.

        One thing I haven't seen any interest in from C++ developers is using optional types and result types. Instead they seem to have a preference for throwing exceptions and then using try/catch blocks, which not only carries a higher runtime penalty but also ends up with more bugs when they either assume a try/catch isn't needed or they don't realize that the library they're hooking into can even throw exceptions. That or they do really horrible things like assume that dereferencing a null pointer because they can't be bothered to check for one will simply seg fault instead of doing potentially much worse things.

        In Rust, if you don't explicitly handle every last error condition (even if handling it means telling the compiler to panic there) then your code won't even compile.

        • Just to clarify: I am aware of Circle's 'Choice' type.

        • I'm not a fan of exceptions in C++. They basically are invisible control flow and that's hard to reason about. absl::StatusOr is a nice pattern that you might consider "choice."
          • Neither am I except I like all the alternatives even worse.

            They're not really invisible in that you need to assume any function other than noexcept might exit via a throw.

            I'm not really that thrilled with the return type being Any. Clearly neither were the designers of Java, but that didn't really work out great either in that it became very boilerplaty. Also, one could argue (and Stroustrup has) that the design of the std::exception class hierarchy was not ideal in practice. I'm coming round on the idea th

            • Spamming checks all over the place, as you put it, is one of C++'s many subgenres. There are ways to do it that aren't too bad. For instance, having every function take an error parameter and do nothing if it's already bad. Or using macros to compact the return-if-error stuff. You do kind of have to commit wholeheartedly to whichever pattern you choose, though.
          • We will eventually realize that we need 3 mechanisms:

            optional return values
            an exception system for exceptional errors
            a global error object that formalizes the tracking of swallowed exceptions (maybe the caller wants to know that the called swallowed a file not found error/etc)
        • It feels like Rust is taking what used to be the domain of a test framework, shoving it into the compiler, and then slapping the "memory safety" moniker on it, and trying to define every other language as "memory unsafe".

          look up the definition of a compiler:
          https://en.wikipedia.org/wiki/Compiler
          "In computing, a compiler is a computer program that translates computer code written in one programming language (the source language) into another language (the target language)."

          look up the definition of a softwar

          • by Uecker ( 1842596 )

            Indeed. Still, I would say it is a good think to move many of these things into the language / compiler.

            But the "memory-safe Rust" vs "memory-unsafe C/C++" marketing is annoyingly misleading.

          • "Software testing is the act of checking whether software satisfies expectations."

            Test-driven development puts testing into development.

        • One thing I haven't seen any interest in from C++ developers is using optional types and result types.

          Std::optional exists just fine.

          Instead they seem to have a preference for throwing exceptions and then using try/catch blocks,

          It's nice, it avoids spamming if(err) return errr; everywhere.

          which not only carries a higher runtime penalty

          LOWER runtime penalty. If you don't throw an exception it incurs no cost at all unlike error codes.

          but also ends up with more bugs when they either assume a try/catch isn't n

          • You cannot assume anything about what happens if you dereference a null pointer. It will usually SIGSEG, but that isn't guaranteed. It's undefined behavior.
          • which not only carries a higher runtime penalty

            LOWER runtime penalty. If you don't throw an exception it incurs no cost at all unlike error codes.

            This is simply incorrect.

            Compiling C++ with exceptions enabled adds a lot of boilerplate to every compiled function, specifically to deal with the potential need to properly unwind the stack at any point. In the compiled code the run-time cost of having exceptions enabled isn't appreciably different from having "if (err)" scattered throughout the code, though the explicit error handling code often makes the code much less readable. Rust addresses this with a bit of syntactic sugar which boils the whole

            • This is simply incorrect.

              Simply put, you are mistaken.

              Compiling C++ with exceptions enabled adds a lot of boilerplate to every compiled function,

              It does not.

              Look, Rust has EXACTLY the same exception mechanism as C++ in LLVM. You can panic in rust and catch the resulting exception in C++. It's the same code. So go fire up your Rust compiler and look at the assembler. What you will see is a lack of anything at all in the main function body about exceptions, certainly no boilerplate.

              The exception handling code

              • This is simply incorrect.

                Simply put, you are mistaken.

                It appears that I am, on modern architectures. What I said used to be true, but exception implementation has evolved to move the code out of the main functions and into separate code blocks and tables. Mostly. There's still code in the main functions to update the tables in many cases.

                Also, it's definitely not the case that exceptions are free or even cheap in terms of code at the points where they're thrown or caught. They might be a little cheaper than "if err" if there's a long chain of function cal

                • It appears that I am, on modern architectures

                  It's more compiler tech/platform ABI than architecture. Microsoft uses SEH, not the Itanium ABI and it has a different set of tradeoffs. There's nothing inherently impossible about the compiler internally returning an optional (the carry flag has been suggested) and every function call checks that to check whether to return. The disadvantage is it would be basically as slow as error codes/optionals, but it would be fully determinstic. It's been proposed recently.

                  • Score one for arrogant post from obnoxious rustacean. There's more out there than C++ you know, and frankly it's not that hard to do in C++ if one cared

                    LOL. Dude, I've been writing C++ for 35 years, Rust for one.

                    • Then what's with the "you wouldn't understand if you don't use rust" bullshit about a feature that's not really rust specific in any meaningful way? Surely you can see that's a pretty obnoxious position to take.

                    • Then what's with the "you wouldn't understand if you don't use rust" bullshit about a feature that's not really rust specific in any meaningful way?

                      Honestly, my criticism is less about C++ and more about exceptions, both conceptually and in C++'s implementation of the concept -- thought I have yet to see a language implement exceptions in a way I thought was really nice, and I've seen quite a few. More than anything, the need to categorize errors into common and uncommon buckets, and to handle the different sorts differently is artificial. Also, the exception throw and catch structures always feel bolted on and are inevitably syntactically bulky and u

                    • But Rust takes the Result concept to its logical, elegant conclusion: You don't have different buckets of errors, they're all the same, all of them have to be checked,

                      But Rust also has Panic for, well, let's say exceptional errors.

                      I really wanted to like C++ exceptions when I finally got to use them. Recall that they didn't work well in early C++ compilers, not for a long time. And when they finally arrived it turned out they were a minefield, very hard to use safely.

                      That's pretty overblown as a claim, hone

                    • There's entire book written on how to make your code conductive to exceptions(Exceptional C++ by Herb Sutter). But I'd say learning this stuff is worthwhile because mandatory dealing with result codes just results in a load of error-prone boilerplate everywhere.
                    • mandatory dealing with result codes just results in a load of error-prone boilerplate everywhere.

                      Rust demonstrates that a tiny bit of syntactic sugar eliminates that boilerplate, at least in the source code, and having the compiler diagnose ignored results eliminates the potential for error.

                      The compiler still has to generate all of the "if (err) return err" code in the binary, but the question of whether that is cheaper or more costly than exceptions is complicated and case-dependent, and the increasing core count in modern hardware is making exceptions increasingly expensive [open-std.org]. In addition, there's th

                    • If you hide error checking with implicit "if(err) return err" then it's equivalent to exceptions in all regards including performance. More complex manual error handling will be always needed but exception vs other error handling strategies is merely question of code organization. Exceptions just let you shunt error handling code into separate place than main non-exceptional case which in many cases can increase clarity and maintainability.
                    • Exceptions just let you shunt error handling code into separate place than main non-exceptional case which in many cases can increase clarity and maintainability.

                      Exceptions as implemented by C++ reduce clarity and maintainability, because they create a lot of implicit, non-obvious action which is often wrong -- writing exception-safe code is hard to do correctly. IMO, Rust strikes exactly the right balance. Error handling is always explicit, with little to no implicit magic, but without cluttering the codebase or obscuring the main flow.

          • Std::optional exists just fine.

            You know what the biggest argument for dragging C++ around is? Compatibility with older shit code. You know where std::optional doesn't exist at all?

            It's nice, it avoids spamming if(err) return errr; everywhere.

            Rust isn't golang. You know what the rust pattern is? Literally, a fucking question mark. One character. That's it. And it doesn't even involve the overhead of exception handling, it's literally a pattern match. No try/catch, no if errs, none of that shit.

            And even then, there are a ton of concise ways of handling errors inline that don't involve passing them to

        • C++ has "zero overhead" exceptions since minimum 30 years.
          And yes, we prefer exceptions over "double type" return results where we have to write an if after every function/method call.

          In C++ dereferencing a null pointer, can be converted into throwing an exception instead. I guess everyone is doing that, no idea though.

        • One thing I haven't seen any interest in from C++ developers is using optional types and result types.

          They're extremely common in the C++ code I see. std::optional is used everywhere, and result types are common in code that doesn't use exceptions.

  • by Zolmarchus ( 2646979 ) on Sunday October 20, 2024 @08:29PM (#64880099)

    The one thing that will make C++ easier to learn and understand, more welcoming, more straightforward, and will eliminate fragmentation and baggage, is just one more extension.

  • by engineer37 ( 6205042 ) on Sunday October 20, 2024 @10:30PM (#64880191)
    I'm not saying this is the end all and be all solution to memory safety. However, this is still a good step in an interesting direction. Why not try to retrofit memory safety into C++? This kinda makes sense conceptually. If there are developers who insist on C++, then it makes sense to attempt to develop a memory safe version.

    Even Rust has unsafe blocks where you can use unsafe features, so it's actually not as much of a stretch to imagine a memory safe version of C++ as you'd think. We already have examples of memory safe languages that are C++-like or C++-inspired (Java, C#), so I think it's actually reasonable to try to adopt the features of memory safe languages. C++ is known for having everything and the kitchen sink, so why not adopt both Rust-like memory safety options as well as garbage collection, and let users choose?

    These are just ideas I'm throwing out here, my main message is that this is that I like this line of thinking, and I think it could be a step in the right direction. Sure, it has a lot of issues that still need to be addressed (like how do you enforce safety for users who want to enforce it?), but I just feel like there's some good core thinking behind this.
    • C++ already has memory safety. All you have to do is always use smart pointers and other standard library classes for lists, etc and your are 99% of the way there. Make a compiler reject any kind of raw pointer use and that's most of it solved.
      • C++ already has memory safety. All you have to do is always use smart pointers and other standard library classes for lists, etc and your are 99% of the way there. Make a compiler reject any kind of raw pointer use and that's most of it solved.

        Adding borrow checking also helps, as the Safe C++ proposal suggests. For one example (and the first one mentioned in the Safe C++ doc), using smart pointers doesn't help if you do something to invalidate iterators, for example... and many iterators are not smart enough to simply stop working if invalidated. And even those that are force you to diagnose the problem at runtime, whereas a borrow checker can do it at compile time.

    • Microsoft already did this a long time ago, have a look at Managed C++ [wikipedia.org]. It's basically nothing new.
      • Managed C++ is a subset of C++.
        That is why no one is using it.

      • Microsoft already did this a long time ago, have a look at Managed C++ [wikipedia.org]. It's basically nothing new.

        Not really. Managed C++ is basically C++ for .NET, which means it's garbage-collected and depends on the .NET runtime. You couldn't use Managed C++, for example, to write Linux kernel modules. The proposed Safe C++ does not have those sorts of dependencies and would be usable for low-level systems code, where C, normal C++ or Rust would be usable.

    • You can just link a garage collector library to your C++ program.
      Boehm, comes to mind.

      But that does not solve Array overruns and other things.

  • Linus has been very vocal [cat-v.org] about his dislike for C++.

    But it would be a lot easier for the kernel to adopt safe C++ than rust, and they added support for rust for its safety features.

    • But it would be a lot easier for the kernel to adopt safe C++ than Rust

      Would it? Why do you think that? I think it's basically the same problem.

  • Dr. Dobbs wrote on this years ago. On a wrapper around unsafe memory functions that provides memory safety.
  • It does not have the required native libraries.

Never test for an error condition you don't know how to handle. -- Steinbach

Working...