Live data from Hacker News

A Usable C++ Dialect That Is Safe Against Memory Corruption

ithare.com

61–70 of 103 posts

Re: A Usable C++ Dialect That Is Safe Against Memory Corruption

#61

Earlier quoted context omitted.

> As far as I'm aware, if you stay within the confines of smart pointers (and don't drop down to the raw pointer it owns) you will never encounter undefined behavior. Deref'ing an empty (e.g. moved-from) unique_ptr is still UB.

Yeah, there's that. It would be nice if C++ did a emptiness check for you, but I guess that this wasn't in the cards…

While we're on "nice to haves," it would be great if there was a way to explicitly terminate the scope of objects. Then you could have an atomic move-from-and-remove-from-scope operation. Which removes any possibility of accessing the moved-from object again.

Re: A Usable C++ Dialect That Is Safe Against Memory Corruption

#62
post #41
post #4

I have a question about this. Articles like http://blog.llvm.org/2011/05/what-every-c-programmer-should-... have convinced me that even if C or C++ reads logically like it is safe, there is a possibility that the compiler can rewrite your code in an acceptable way according to the standards such that the checks that are clearly visible in your code disappear, opening up the very problems that you thought you were pro…

The best thing I've ever encountered that encapsulated this was a Cap'N'Proto vulnerability, and the discussion here about it was enlightening as well.[1] The highly condensed version is that the compiler optimized away an if block that was responsible for throwing an error as impossible to reach in correctly functioning code, when the whole purpose of that if block was to check that condition and error so that the p…

-fwrapv should fix it (no warranties of any kind, batteries not included).

Re: A Usable C++ Dialect That Is Safe Against Memory Corruption

#63
post #14

Earlier quoted context omitted.

As far as I'm aware, if you stay within the confines of smart pointers (and don't drop down to the raw pointer it owns) you will never encounter undefined behavior. You may have crashes if you try to double free something, but these are defined to crash rather than letting the compiler optimize out checks.

Wouldn't you have a problem with reference cycles in C++ smart pointers? Not sure if they do anything special to prevent this.

std::unique_ptr won't allow you to have 'owning' reference cycles; neither 'owning' reference cycles are really necessary in real-world programs.

Re: A Usable C++ Dialect That Is Safe Against Memory Corruption

#64
post #8

TL;DR; use smart pointers, RAII semantic and STL containers/iterators. Though, I'd have a few criticism... > Rules to ensure memory safety These "rules" only protect you against object's lifetime issues, not overflow / underflows, and other kind of memory issues. > ‘owning’ pointers are obtained only from operator new no, you shall be using std::make_{unique,shared}(...) which will protect you against leaking memory…

Mostly agree, but: > Don't use C API. The STL should provide you with enough API to use the proper C++ types, either std::string or std::string_view in C++17 if possible. Sometimes you're working with C API that gives you back a char * that they've already allocated. AFAIK there isn't a way to create an std::string out of that without a copy. > you can't static_cast a pointer You can static_cast a void * into other k…

> You can static_cast a void * into other kinds of pointers.

Moreover, you can use static_cast for downcasts (from the parent class to child class) - without runtime costs of dynamic_cast. static_cast is not safe (it doesn't perform runtime checks), but reinterpret_cast is even worse (it doesn't perform even compile-time checks).

Re: A Usable C++ Dialect That Is Safe Against Memory Corruption

#65
post #62
post #41

Earlier quoted context omitted.

The best thing I've ever encountered that encapsulated this was a Cap'N'Proto vulnerability, and the discussion here about it was enlightening as well.[1] The highly condensed version is that the compiler optimized away an if block that was responsible for throwing an error as impossible to reach in correctly functioning code, when the whole purpose of that if block was to check that condition and error so that the p…

-fwrapv should fix it (no warranties of any kind, batteries not included).

IIRC this particular case was only seen on a specific version of one compiler for MacOS that was provided with extra patches, so it's at first glance less of a problem than it originally looks. That said, I don't think it was doing anything illegal according to the standard (no an expert on this), and as compiled software and a library, the reach of that case may be larger than we might otherwise assume.

There are undoubtedly ways to tell the compiler to be careful, but that isn't always in control of the person writing the code, and even if some level of control exists, compilers change.

Re: A Usable C++ Dialect That Is Safe Against Memory Corruption

#66
post #8

TL;DR; use smart pointers, RAII semantic and STL containers/iterators. Though, I'd have a few criticism... > Rules to ensure memory safety These "rules" only protect you against object's lifetime issues, not overflow / underflows, and other kind of memory issues. > ‘owning’ pointers are obtained only from operator new no, you shall be using std::make_{unique,shared}(...) which will protect you against leaking memory…

Well, the point of the OP goes further than that. Two Big Questions are (a) what to do with the non-owning back references (such as backref going up the owning tree) - for this 'soft' pointers are proposed (I _hate_ shared_ptr-like ref-counted stuff, in large projects they tend to cause much more trouble then they're worth, especially memory leaks due to shared_ptr loops are troublesome, causing both syntactic and semantic memory leaks, ouch!), and (b) how to formalize the use of those non-owning ('naked') pointers/references and how to prevent them from being dereferenced when they're pointing to already-deallocated memory locations (and saying "don't use naked pointers/refs, ever" is not really practical IMNSHO).

Re: A Usable C++ Dialect That Is Safe Against Memory Corruption

#67
post #34

This works, although the downside compared to Rust is that soft pointer validity is checked at runtime, meaning that a program that compiles can still randomly fail at runtime and that performance is worse due to the checks. The key idea and massive difference from standard C++ is that object destruction is delayed until a "quiescient state" happens in what is a reframing of RCU [ https://en.wikipedia.org/wiki/Read-c…

I don’t understand your comment about how rust pointers are safer than soft pointers. The article explains how to implement a wide variety of pointer semantics, all of which are memory safe (throw an exception on explicit use after free, use the type system to have the compiler statically check the pointers are live, use dynamic cast, etc). Looking online, I see that people implement all the same primitives in rust, with exactly the same safety caveats.

Also, the container and mutex tricks you mention sound interesting, but I don’t see why they can’t also be used in C++ (which has a turing complete type system / checker).

Re: A Usable C++ Dialect That Is Safe Against Memory Corruption

#68

Earlier quoted context omitted.

int get_value(int* pointer) { return *pointer; } How is a compiler supposed to reject this for undefined behavior? It'd be absurd to demand the compiler someone knows all possible usages for get_value to find if any of them pass a nullptr, so what is it supposed to do? And this is why the spec says things like that deref'ing a null pointer is undefined behavior, so that the compiler can take that function and do the…

The compiler shouldn't rejected UB, it should define all behavior, and reject all code constructs that can't have behavior fully defined (like accessing raw pointers as arrays, so bounds- checking is impossible). It can throw an exception on null de-reference at runtime. That's slow, but safe.

Slow but safe is not why people choose C++ for their software.

Re: A Usable C++ Dialect That Is Safe Against Memory Corruption

#69
post #54

Dialects are of limited uses, because they are dialects... New dialects are arguably of even more limited uses, because better languages now exist where the desirable characteristics are enforced not by using a dialect, but by the core languages, and safety checking is not optional. (Also, I'm somewhat curious about why the proposed dialect tells about think "similar to unique_ptr, and so over: just use the real thin…

One point of a dialect (aka “coding standards”) is that you can evolve legacy code bases toward them with a series of simple refactorings instead of by rewriting from scratch.

For me this is the big advantage of C++: it is possible to backport virtually any language feature you want to it, thanks to the combination of modern template programming and low-level C-style bit twiddling.

Re: A Usable C++ Dialect That Is Safe Against Memory Corruption

#70
post #34

This works, although the downside compared to Rust is that soft pointer validity is checked at runtime, meaning that a program that compiles can still randomly fail at runtime and that performance is worse due to the checks. The key idea and massive difference from standard C++ is that object destruction is delayed until a "quiescient state" happens in what is a reframing of RCU [ https://en.wikipedia.org/wiki/Read-c…

> that performance is worse due to the checks.

I'd argue that use cases for 'soft pointers' are about the same as that of Rust's RC, which also incurs runtime costs (very briefly - there is no magic here, neither with Rust).

> The key idea and massive difference from standard C++ is that object destruction is delayed until a "quiescient state" happens

If you're speaking about OP - clarification: it is not "object destruction" which is delayed (destructor is still called synchronously when the variable goes out of scope, so all the crazy finalize()-like problems don't occur), it is memory deallocation which is delayed (and this is generally ok as deallocation is not observable, or at least garbage-collected languages tell us so ).

> things like mutexes can only be safe

Whether C++ or Rust or whatever-else, mutexes at app-level are evil ;-) (it can lead to a very long discussion, but long story short - finally, by 2017, most of the opinion leaders started to converge to this IMO-very-obvious observation: ASYNC RULEZZ! ).

> since that allows to statically check for correctness,

The idea behind OP is to have a tool which will do the same thing (where possible, see above re. 'soft pointers' and RC). Whether such a tool materializes - is a different story, but well - first we have to agree that such a tool is a Good Thing(tm).

> have to delay freeing memory

In practice, it is never an observable problem in (Re)Actor-like contexts ((Re)Actor use cases are about highly interactive systems ranging from games to stock exchanges, where typical input is processed in milliseconds, and amount of allocated memory until the 'quiescient state' is reached, is single-digit kilos; in extreme cases, it goes up to single-digit megabytes, still nothing by modern standards).

> you are much better off using Rust

Really really depends. It is still C++, and being C++ has its own virtues (alongside with its own quirks); just two things to illustrate this point - (i) recently it was revealed that modern GPUs are designed with ISO C++ standard in mind (specifically C++, not Rust or anything else); (ii) developer availability is also a major factor for real-world projects, and so on, and so forth. In an ideal world - well, probably Rust does look as a more to-the-point language (though even with Rust I'd create an own dialect, in particular, outlawing thread sync to simplify things), but given real-world considerations - the choice is certainly not that black-and-white.

Post reply on HN