HNHacker News
TopNewBestAskShowJobs

duneroadrunner

157 karma · joined September 26, 2016

submissionscomments
duneroadrunner··on C++ Lifetime profile v1.0 posted
> It's not clear to me how this is possible without breaking backwards compatibility.

What do you mean? Presumably most existing sizable codebases will not satisfy the requirements of the (eventual completed) lifetime checker, even if the code is actually safe.

> > You don't need to completely eliminate the aliasing issue to achieve (efficient) memory safety, you just need to address it "enough"

> Safe Rust isn't "enough" safe, it is 100% (proofs pending, of course) safe. A "safe enough" system is not equivalent.

I'm asserting (perhaps mistakenly) that you don't need to address the aliasing issue as completely as (Safe) Rust does in order to achieve the same memory safety that (Safe) Rust does. Or maybe "completely" is not exactly the right word. I'm saying that the universal imposition of the "mutable references are exclusive" restriction is not a necessary prerequisite to (fully) achieving the same type of ("zero overhead") memory safety that (Safe) Rust does.

I'm not that familiar with Rust, but for example, if you have a reference to an element in a dynamic container, like a vector, (Safe) Rust ensures that that element is not prematurely deallocated by ensuring that there is no simultaneously existing mutable reference to the container. I.e. the container is immutable while an (immutable) reference to one of its elements exists. Right? (I mean, assuming you didn't "split" it first.) And if the reference to the element is a mutable reference, then the container cannot be referenced at all, right?

From a memory safety perspective, this is overkill. The container does not have to be immutable (or inaccessible) while a reference to an element exists, only its structure needs to be immutable. The C++ lifetime checker imposes this lesser restriction.

And for simple objects that do not have dynamic structure (or any indirect references), then the "mutable references are exclusive" restriction provides no memory safety benefit at all, right?

As I said, even this lesser restriction will presumably break most existing C++ codebases, and you could (I think legitimately) argue that that makes this new "Safe" C++ a substantially different language than traditional C++. But the fact that the restrictions are much less severe than Rust's means that a lot fewer code modifications will be required than if a Rust-style universal "mutable references are exclusive" restriction had been adopted.

Am I making sense here? Maybe I'm mistaken and these "lesser" restrictions are somehow inadequate, but I don't see it.

duneroadrunner··on C++ Lifetime profile v1.0 posted
> This proposal and Rust's guarantees are different.

A little different, but only in the sense of being, for the moment, less ambitious (than Rust) about the completeness of the checker's implementation. But I think it substantially demonstrates a straightforward path to achieving the same level of memory safety in C++ as Rust.

> For example: > > We do not attempt to address all aliasing cases

It seems to me that a main principle behind the design of the Rust language was to eliminate the aliasing issue, by imposing the "mutable references are exclusive" restriction, as a prerequisite to addressing the memory safety issue. And there was an implication (and sometimes more than that) that as long as C++ can't address the aliasing issue it can't address the memory safety issue (like Rust can).

I think the key thing that the lifetime checker demonstrates is that this premise is not (quite) right. You don't need to completely eliminate the aliasing issue to achieve (efficient) memory safety, you just need to address it "enough". And that can be done for C++.

Now, whether the complete elimination of the aliasing issue is, apart from the memory safety implications, a virtue that's worth the (flexibility) cost of the "mutable references are exclusive" restriction, is as far as I'm aware, still a matter of opinion. (Given the existence of the RefCell wrapper in Rust, and the ease (if not elegance) of implementing an "anti-RefCell" wrapper in C++, I'm guessing it's mostly a wash.)

> > or make concurrency safety guarantees. Programmers are still responsible for eliminating race conditions.

Data races are a separate issue, but relative to the (single-threaded) memory safety issue, I think there'd be less controversy that it can be addressed in C++ in vaguely similar fashion to Rust. [1]

But both in the case of Rust and the C++ lifetime checker, I don't think that the cost of the imposed (compile-time) restrictions in terms of code/algorithmic flexibility is being adequately acknowledged. For example, say you have a list (or whatever container) of references to (pre-)existing objects. In both cases, the restrictions require that all the objects must (be known to) outlive the list container even if there is a reference to them in the list for only a short time [2]. Imo this is an impractical restriction. In C++, you could use run-time checked pointers[3][4] to alleviate the restriction without sacrificing memory safety [5]. It's not immediately obvious to me that Rust couldn't have such a run-time checked reference as well. But others would be more qualified to make that assessment.

[1] shameless plug: https://github.com/duneroadrunner/SaferCPlusPlus#multithread...

[2] https://github.com/duneroadrunner/misc/blob/master/201/8/Jul...

[3] https://github.com/duneroadrunner/SaferCPlusPlus#registered-...

[4] https://github.com/duneroadrunner/SaferCPlusPlus#norad-point...

[5] https://github.com/duneroadrunner/misc/blob/master/201/8/Jul...

duneroadrunner··on C2rust vs. Corrode
Not sure if it's what you're thinking of, but there is the "C to SaferCPlusPlus" auto-translation helper tool[1]. The idea is that the output can be compiled as straight C, with the safety mechanisms disabled, or with the (compile-time and run-time) safety mechanisms enabled, which requires compilation as C++. The tool is currently being neglected, and at the moment it mostly just translates native arrays, and pointers that are being used as array iterators.

I say "just", but actually it addresses what I believe to be (by far) the most difficult issue, which, as other commenters have mentioned, is determining in the general case whether a pointer is actually being used as an array iterator. And it also determines whether that array is a fixed-size array or a (potentially) resizable array.

For example, in this code snippet:

    void foo1(int *p, int n) {
        foo2(p, n);
    }
does p point into an array, or just at an int? You have to deduce it from context. And there's no theoretical limit to the amount of deduction you might need to do.

The tool doesn't automatically translate regular "non-array" pointers yet, but that can be a straightforward task as the SaferCPlusPlus library has a safe, general drop-in replacement for pointers. Translating to "performance optimal" safe pointers is another story. There you have challenges similar to translating to safe Rust I think.

[1] shameless plug: https://github.com/duneroadrunner/SaferCPlusPlus-AutoTransla...

duneroadrunner··on Handles are the better pointers
Pretense not intended, thanks for clarifying. :) Rather than algorithmic novelty, the point is more that ivector has an API and implementation that is memory safe (memory safety seemed to be an emphasis of the blog post).

As for those next steps, I'm under the vague impression that they aren't as popular these days because larger cpu caches have greatly reduced the cost of moving contiguous data in most real-world scenarios. So that more often than not the cache coherency benefits of simple contiguous data outweigh the avoidance of shifting some of that (contiguous) data.[1]

[1] simple microbenchmark of contiguous vs non-contiguous containers near the end of the article: https://www.codeproject.com/articles/1087021/stable-iterator...

duneroadrunner··on Handles are the better pointers
> Most of the following blog post is written from a game developer’s perspective, but should also apply to other areas ...

Video games are a special case where allocations and deallocations are often well scheduled and predictable. For the more general case, using a data type like ivector[1] for the object arrays would provide the desired memory safety. It gives you the flexibility of safely accessing an object via index, iterator or (zero-overhead smart) pointer. Even though it's a vector (like std::vector) its iterators behave like list iterators. That is, after an insertion or removal operation, unlike indexes, they continue to point to the same item (not necessarily the same position) and they only become invalid when the item they point to is removed. In particular, they don't become invalid after a resize/reallocation operation.

So using ivector's iterators instead of index handles would allow you to safely perform insertion/removal operations if necessary.

Also, for performance reasons you may sometimes want to temporarily obtain a direct pointer to the item. ivector allows you to obtain a zero-overhead smart pointer to the item that is guaranteed not to become invalid. [2] It does this by disabling "resize" operations on the vector while it exists.

[1] shameless plug: https://github.com/duneroadrunner/SaferCPlusPlus#vectors

[2] https://github.com/duneroadrunner/SaferCPlusPlus#make_xscope...

duneroadrunner··on XNU kernel heap overflow due to bad bounds checking in MPTCP
Don't forget about SaferCPlusPlus[1]. Much safer than conventional modern C++. Also (optionally) uses scope lifetimes to prevent use-after-free. (Not yet fully compiler enforced like Rust, but hopefully that'll be coming at some point.) There is a translation helper tool[2] that, at this point, can automatically replace native C array and pointer iterator declarations with macros that make them memory safe (bounds and use-after-free) when compiled in C++ mode.

[1] shameless plug: https://github.com/duneroadrunner/SaferCPlusPlus/blob/master...

[2] https://github.com/duneroadrunner/SaferCPlusPlus-AutoTransla...

duneroadrunner··on A meta-analysis of C++ projects
For those that "love C++" (or their existing C++ code base), there's SaferCPlusPlus[1].

[1] shameless plug: https://github.com/duneroadrunner/SaferCPlusPlus

duneroadrunner··on C for All
SaferCPlusPlus[1], for example, is a safe subset of C++ that has compatible safe substitutes for C++'s (and therefore C's) unsafe elements. So migrating existing C/C++ code generally just requires replacing variable declarations, not restructuring the code.

For C programs, one strategy is to provide a set of macros to be used as replacements for unsafe types in variable declarations. These macros will allow you, with a compile-time directive, to switch between using the original unsafe C elements, or the compatible safe substitutes (which are C++ and require a C++ compiler).

The replacement of unsafe C types with the compatible substitute macros can be largely automated, and there is actually a nascent auto-translator[2] in the works. (Well, it's being a bit neglected at the moment :)

Custom conventions using macros to improve code quality are not that uncommon in organized C projects. Right? But this one can (optionally, theoretically) deliver complete memory safety. So you might imagine, for example, a linux distribution providing two build versions, where one is a little slower but memory safe.

[1] shameless plug: https://github.com/duneroadrunner/SaferCPlusPlus

[2] https://github.com/duneroadrunner/SaferCPlusPlus-AutoTransla...

duneroadrunner··on A Usable C++ Dialect That Is Safe Against Memory Corruption
Yes, documentation and class names are not SaferCPlusPlus' strong points at the moment. Perhaps the easy way to get started is just to use the elements in the "mse::mstd" namespace, like vector, array, string, string_view, etc. which are just safe, compatible implementations of their namesakes in the "std" namespace.

As for the pointers, there's a slightly out-of-date article[1] that tries to explain them with examples. But a simple option is to just replace all your raw pointers with "registered" pointers. It's not performance optimal, but it's safe and simple.

But yes, better introductory documentation and examples are needed. There is not yet a forum for those picking up SaferCPlusPlus, but for now you can post any questions or suggestions in the issues section[2].

[1] https://www.codeproject.com/Articles/1093894/How-To-Safely-P...

[2] https://github.com/duneroadrunner/SaferCPlusPlus/issues

duneroadrunner··on A Usable C++ Dialect That Is Safe Against Memory Corruption
> "guaranteed to be safe" (which will most likely require tooling) rather than merely "safer" - and I will be the first one to promote it myself :-)

Well I hope so, as SaferCPlusPlus could use a little promotion :) At this point, despite the name, I think the dialect itself is "safe", not just "safer". Potentially unsafe features are relegated to the "mse::us" namespace and are generally only needed for interop with legacy code.

Of course there's no way to enforce that a programmer stick to the "dialect"/subset without some tooling. But I think the "rule" for adhering to the SaferCPlusPlus subset is pretty simple and generally intuitive. That is, "any potentially unsafe element of C++ should be avoided". And I think most of us have a pretty good sense of which C++ elements are potentially unsafe. The (few) unintuitive ones might include things like the implicit "this" pointer (which is a native pointer, so it should be avoided). A tool to enforce adherence would be fairly straightforward to write. When there is sufficient demand it will be provided. At the moment an "auto-translation"[1] tool has higher priority.

> quite simple: there are only 3 concepts, with 2 of them ('naked' and 'owning'=unique_ptr<>) being already very familiar

It's the same with SaferCPlusPlus, but the 3 "concepts" (pointer types) are "reference counting" pointer (=std::shared_ptr<>), "registered pointer" (= safe, unrestricted naked pointer), and "scope" pointer (basically a naked pointer that is restricted to stack allocation (i.e. a "local variable") and can only point to objects guaranteed to outlive it). The Core Guidelines also has three "concepts"/pointer types (shared, unique, and naked). I suspect that some experience will reveal that SaferCPlusPlus has the better set of pointer types.

...

Oh wait, you're the author of the article? In which case, I think it would be worth your time to get more familiar with SaferCPlusPlus. Even if just as research for your own dialect. But with some experience, I think ultimately you might be convinced by the SaferCPlusPlus solution. In fact, there's no reason why your (Re)Actors couldn't be implemented on top of SaferCPlusPlus, which would automatically provide the safe "collections" that you need.

Don't hesitate to post any questions in the "issues" section[2].

[1] https://github.com/duneroadrunner/SaferCPlusPlus-AutoTransla...

[2] https://github.com/duneroadrunner/SaferCPlusPlus/issues

duneroadrunner··on A Usable C++ Dialect That Is Safe Against Memory Corruption
If anyone is really interested in this sort of thing, I suggest you take a look at SaferCPlusPlus[1]. It is "A Usable C++ Dialect That Is Safe Against Memory Corruption" (including data races). And it already exists.

And I think it's better than this proposed dialect in that most of the (safety) restrictions are enforced without requiring extra tooling, and it's much less restrictive. Most existing C++ code can be converted directly. And the run-time overhead is kept to a minimum. Btw these advantages apply versus the Core Guidelines[2] as well.

[1] shameless plug: https://github.com/duneroadrunner/SaferCPlusPlus

[2] https://github.com/duneroadrunner/SaferCPlusPlus#safercplusp...

duneroadrunner··on Checked C: extension to C that adds static and dynamic checking
> It's technically possible, but retrofitting old code rarely happens.

Yeah. A more realistic solution might be auto-translation of existing code. Here[1] is an example that replaces declarations of arrays, and pointers used as array iterators, with macros that enable the code to be compiled as either unsafe C code or "safe" C++ code (bounds checked and iterator use-after-free safe).

Determining in general whether or not a pointer is being used as an array iterator, or a pointer to an array is not trivial. It sometimes has to be deduced from context. Which may be why it doesn't seem to have been done already?

[1] shameless plug: https://github.com/duneroadrunner/SaferCPlusPlus-AutoTransla...

duneroadrunner··on C++ Core Guidelines
I'm going to dissent on this. While the Core Guidelines "raise the floor" for code safety, I think the may be lowering/hardening the ceiling[1] as well. One problem is that, they impose an (inflexible) standard for function interfaces that is still intrinsically unsafe. For example, they direct you to standardize on std::shared_ptr for objects shared between threads. But this prevents you from using (even) safer smart pointers that, for example, do automatic mutex locking[2].

Presumably the alternatives to a standardized, intrinsically unsafe interface are either a standardized, safe interface, which would require introducing safe alternatives for unsafe elements like std::shared_ptr and raw pointers. Or a more felixible interface standard. For example, making your public functions function templates when necessary.

[1] shameless plug: https://github.com/duneroadrunner/SaferCPlusPlus#safercplusp...

[2] https://github.com/duneroadrunner/SaferCPlusPlus#the-problem...

duneroadrunner··on Unsafe Zig Is Safer Than Unsafe Rust
> unless you just don't use pointers or references at all (and refrain from using any library that is not safe which includes large parts of the standard library like all the containers)

It may seem far fetched, but it might be more practical than you'd think. The SaferCPlusPlus[1] library provides memory-safe implementations of the most commonly used standard library containers, and pointer types that reflect the lifetimes of their target objects. That is to say, there is a practical subset of C++ that is more closely comparable to safe Rust than is conventional C++.

[1] shameless plug: https://github.com/duneroadrunner/SaferCPlusPlus

duneroadrunner··on Building a Website with C++
Two main components of Rust's approach to memory management are i) the imposing/exploiting of scope lifetimes on objects and references, and ii) the restriction that a mutable reference may not co-exist with any other references (to the same object).

I suggest that with C++ there is kind of the option of embracing the former, without so much of the latter, to achieve a performance-safety combination that is closer to Rust's than current "modern C++" practices. That's sort of the premise of the SaferCPlusPlus library [1]. If you're a C++ programmer, the barrier to adoption is low. Though without a "borrow checker" or something equivalent, you wouldn't be able to match Rust's performance-safety combination in all cases.

[1] shameless plug: https://github.com/duneroadrunner/SaferCPlusPlus

edit: edited the link

duneroadrunner··on Rust in 2018: easier to use
C++ does have a practical, memory-safe subset[1]. Recommended for anyone writing internet facing C++ code.

[1] shameless plug: https://github.com/duneroadrunner/SaferCPlusPlus

duneroadrunner··on Coming Soon: Machine-Checked Proofs in Everyday Development
Here's my hypothesis: The problem with these static verifiers is that they are applied at the wrong stage. The verification logic would be more useful in more cases if it were applied at the optimization stage.

Right now the benefits of static verifiers is rather binary. Either your program (or code unit) is sucessfully verified or it isn't. And every time you make a change to verified code you risk losing its verified status.

Imagine instead writing code that is made "safe" using run-time asserts everywhere. Unoptimized, this code might be slow. And unreliable in the sense that a run-time assert could fail, requiring some kind of recovery or abort action. But it would still be "safe".

The run-time asserts are effectively the "program specifications", and the discarding of those asserts at the optimization stage is basically equivalent to traditional static verification. The difference being that not quite fully optimized "safe" code is generally more valuable than not quite fully verified (and therefore not fully "safe") code.

> These heady days of being able to deny responsibility and shove out any software we want without consequence need to end.

If the static verification community is imploring the development community to, with some effort, change its practices to improve code safety, would that community be willing to, with some effort, move the application of their verification logic to the optimization stage where it would be more practical for a wider range of applications?

duneroadrunner··on Modernize C++: Sink Functions
> good coding conventions in C++ will get you 90% of the way there

For those that need it, SaferCPlusPlus conventions will get you even further.

> Basically in C++ I think an of old-style pointers/refs as Rust-like "borrowed" references.

They key safety feature of Rust references is that they have "scope lifetime" and their target is guaranteed to be alive for the duration of that scope lifetime. You can use SaferCPlusPlus' "scope pointers"[1] to achieve this in C++.

Scope pointers can be explicitly converted to raw pointers, so they can be used with existing "legacy" functions. But you get even more benefit when you change your function interfaces to support scope pointers directly[2]. For example, it would prevent the function from (inappropriately) putting a copy of the scope pointer into "long term storage" (like Rust does).

[1] shameless plug: https://github.com/duneroadrunner/SaferCPlusPlus#scope-point...

[2] https://github.com/duneroadrunner/SaferCPlusPlus#safely-pass...

duneroadrunner··on Linked List Problems (2002) [pdf]
You mean how it's implemented? Umm, well it's been a while, but basically an ipointer is a proxy for an iterator that is stored internally by the msevector. These "internally stored" iterators are updated when necessary. For example, when insert() or erase() is called.

One nice thing about it is that it roughly conforms to the principle of "only pay for what you use". That is, the run-time cost is roughly proportional to the number of ipointers you have and the frequency of operations that modify the size of the vector.

One caveat is that this mechanism is not thread safe. But whenever you need to share the vector among threads, you can swap it with a vector that is safe to share[1].

And for those that are into memory safety, there is also a memory-safe vector[2] that supports ipointers.

Is this the sort of explanation you're looking for?

[1] https://github.com/duneroadrunner/SaferCPlusPlus#nii_vector

[2] https://github.com/duneroadrunner/SaferCPlusPlus#ivector

duneroadrunner··on Carp, a compiled Lisp with type inference and a borrow checker
The problem is that, while in many ways an improvement over traditional coding practice, the subset of C++ associated with the Core Guidelines (GSL stands for "(Core) Guidelines Support Library") has turned out to be a dead-end when it comes to memory safety. In fact it formalizes the depenedency on intrinsically unsafe elements like native pointers, std::shared_ptr, etc. I mean, with "regular" C++ you're not actually obligated to use those intrinsically unsafe elements. With the Core Guidelines you are.

SaferCPlusPlus[1] is an alternative subset of C++ that doesn't have that same problem. It achieves memory safety by simply excluding the intrinsically unsafe elements and providing memory-safe alternatives.

> All compile time checks.

Not quite in reality. One small issue with the GSL, for example, is that its not_null pointer class does a run-time check on every pointer dereference[2]. SaferCPlusPlus can enforce "not null"ness at compile-time.

A bigger example, for instance, is the situation where you want to allow multiple threads to simultaneously modify different parts of an array. With SaferCPlusPlus, this is straightforward and safe [3]. With the GSL/Core Guidelines, less so.

I don't know how much these technical considerations factor into (or will factor into) popularity of adoption. I don't know how big the intersection is of the sets of developers who take code safety seriously and those who remain interested in C++.

[1] shameless plug: https://github.com/duneroadrunner/SaferCPlusPlus

[2] https://github.com/Microsoft/GSL/blob/1c95f9436eae69c9b93159...

[3] https://github.com/duneroadrunner/SaferCPlusPlus/blob/278b40...

duneroadrunner··on Linked List Problems (2002) [pdf]
The problem with trying to substitute lists with vectors is that their iterators behave differently. I.e. vector iterators point to positions rather than elements and are prone to being invalidated. So sometimes it's nice to have a vector that supports iterators that behave like list iterators[1].

[1] shameless plug: https://www.codeproject.com/Articles/1087021/Stable-Iterator...

duneroadrunner··on Fearless Concurrency in Firefox Quantum
It's arguably even a little bit nicer in SaferCPlusPlus[1]:

    template<typename TVectorPointer>
    void write_foo(TVectorPointer vec_ptr) {
        (*vec_ptr)[3] += 1;
    }
    
    template<typename TVectorPointer>
    auto read_foo(TVectorPointer vec_ptr) {
        return (*vec_ptr)[7];
    }
    
    template<typename TVectorAccessRequester>
    void use_shared_vector(TVectorAccessRequester vec_ar) {
        {
            // obtain a non-const pointer to the vector from the "access requester"
            // blocking if necessary
            auto wl_ptr = vec_ar.writelock_ptr();

            write_foo(wl_ptr);

            // the pointer owns a lock on the vector so as long as the pointer
            // exists it is safe and valid to use
        }

        // obtaining and using a const pointer to the vector
        auto res1 = read_foo(vec_ar.readlock_ptr());
        
        // without a "lock pointer" obtained from an access requester, there is no way
        // to access, or even refer to the shared vector, so you can't access it in an
        // unsafe manner
    }
[1] shameless plug: https://github.com/duneroadrunner/SaferCPlusPlus#asynchronou...
duneroadrunner··on Fearless Concurrency in Firefox Quantum
> basically a nicer C++ with the obvious foot guns removed

For those stuck with C++, you're not out of luck in terms of safe and easy sharing between threads. The SaferCPlusPlus library provides "access requesters" that provide functionality and (data race) safety similar to Arc<T>.

Unfortunately the documentation[1] is "in transition" at the moment and does not currently refer to the very latest version. But the main difference is that the latest version implements something akin to rust's "sync" trait to help prevent you from attempting to share inappropriate data types.

Again, documentation is a work in progress, but if you're interested you can check out an example that demonstrates an array being safely modified simultaneously from multiple threads[2].

[1] shameless plug: https://github.com/duneroadrunner/SaferCPlusPlus#asynchronou...

[2] https://github.com/duneroadrunner/SaferCPlusPlus/blob/7e3574...

duneroadrunner··on LibHTTP: Open Source HTTP Library in C
> (http://people.canonical.com/~ubuntu-security/cve/pkg/xmlrpc-...)

It looks like some of those CVEs are dated not that long ago. If code safety is still a concern with this project, you/someone might consider conversion to SaferCPlusPlus (essentially a memory-safe subset of C++). There is an "auto-conversion helper tool"[1] still in development, but already functional.

[1] shameless plug: https://github.com/duneroadrunner/SaferCPlusPlus-AutoTransla... (Feel free to post any questions to the github "issues" section.)

duneroadrunner··on Pointer Free Programming and the Future of Nim
First let me say that I'm not familiar with Nim. But I understand that it compiles/transpiles to C/C++. And it sounds like they're now trying to move away from dependency on the GC. In that case, might I suggest they consider switching the transpile target to SaferCPlusPlus[1]. It might make things easier as it already addresses the "efficient memory-safety via scope lifetimes without a borrow-checker" issue. And also the (data race) safe sharing of objects between threads. (Note that the documentation is currently rather out-of-date, and a major update is coming.)

[1] shameles plug: https://github.com/duneroadrunner/SaferCPlusPlus

duneroadrunner··on Building on Rock, Not Sand
> Does anyone actually want to program in "C++ with instance methods banned"?

Well, passing a "safe this" pointer as the first parameter to a (static) member function isn't that hard to get used to, is it?

But I don't disagree with your gist. If memory-safety is your only concern and you're not trying to salvage an existing codebase, then Rust might be a better choice.

But if you're trying to add memory safety to, say, an existing C implementation of SSL, the SaferCPlusPlus route would probably be less effort. Even when non-static member functions are banned.

> (which is most of them)

Personally, I consider RAII (deterministic destructors) an essential feature for safe, efficient programming at scale. That leaves only two choices, C++ and Rust, right?

And if there's a memory-safe C++ option available, there are some arguments for choosing it over Rust.

duneroadrunner··on Building on Rock, Not Sand
> For one thing, the "this" pointer problem is pretty much unsolvable in C++.

Well, you could just avoid/prohibit the explicit and implicit use of the "this" pointer. I.e. prohibit non-static member functions[1], right?

[1] https://github.com/duneroadrunner/SaferCPlusPlus#practical-l...

duneroadrunner··on Building on Rock, Not Sand
> On the other hand, it probably is less effort to rewrite PolarSSL in Rust than doing that proof.

It's probably even less effort to convert to SaferCPlusPlus[1] (essentially a memory-safe subset of C++). There's even an tool[2] (under construction, but functional) to do a lot of the conversion for you.

[1] shameless plug: https://github.com/duneroadrunner/SaferCPlusPlus

[2] https://github.com/duneroadrunner/SaferCPlusPlus-AutoTransla...

duneroadrunner··on Abseil: C++ Common Libraries
SaferCPlusPlus does not recommend relying directly on mutexes at all. For most straightforward cases, you can use the "access requesters" to safely manage asynchronous access automatically.

Recursive mutexes are analogous to having multiple pointers (or iterators), some of which are "non-const", to an object in the same thread at the same time. Some suggest that this too is a bad idea. For example, the Rust language does not allow a "mutable" (i.e. "non-const") reference to an object to co-exist with any other reference to that object, even in the same thread.

SaferCPlusPlus does not necessarily disagree with this position, but it also does not require adherence to it, like Rust does. So if SaferCPlusPlus is going to allow multiple pointers (or iterators) to a shared object in the same thread, then it's going to need to lock the mutex protecting the object multiple times from the same thread. Giving each pointer/iterator its own separate lock, as opposed to having one lock encompass the all the pointer/iterators, allows the locks to be managed automatically, which ensures against data races, and that resource locks will be released as soon as it is safe to do so.

Again, there's rarely any reason you'd need to interact with the mutex directly. It's primarily there to support "access requester" functionality.

Also, note that this is a recursive shared mutex, not just a recursive mutex, which means that, for example, it provides a kind of "upgrade mutex" functionality. So if a thread has a "read" lock, it can obtain a "write" lock (blocking if necessary), without having to give up its read lock. Then when it's done with the write lock, it can release it without fear of losing its read lock (or blocking).

duneroadrunner··on Abseil: C++ Common Libraries
Yeah, I think it might be a familiarity bias.

Anyway, the point of access requesters are that they are much safer than manually protecting resources with mutexes. That is, using access requesters eliminates the possibility of data races[1]. Which is important because data races can be particularly insidious bugs.

Just like how smart pointers can improve safety by automatically managing object lifetimes, access requesters can improve safety by automatically managing object lifetimes and asynchronous access.

[1] As long as you adhere to the rule that shared objects not have "unprotected" mutable or indirect (i.e. pointers/references) members.

← PreviousPage 2 of 6Next →