Live data from Hacker News

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

ithare.com

81–90 of 103 posts

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

#81

This technique is mostly a garbage collector, as I see it. Postponing memory destruction until the stack is empty is a special case of deferred reference counting [1], where sweep can only happen with an empty stack. If the "soft pointers" are implemented with reference counting, that's also a type of GC. On the other hand, the tagged pointer implementation strategy for "soft pointers" isn't really garbage collection…

> Pointer reads must check the tag ID and throw, which is like a read barrier

Usually, "read barrier" is understood as a multithreaded stuff - and OP has nothing to do with MT. In other words, no "read fence" is necessary (simply because it lives in a perfect single-threaded world). And from this POV, it is extremely difficult to beat this schema with any popular-multithreaded-GC. As a side note, proposed schema DOES allow 'naked' pointers, so relatively-expensive (costing ~4CPU cycles, which is not much to start with) conversion from 'soft' into 'naked' has to be done only _very_ occasionally, and after the conversion, we're working with good old plain pointers, which just happen to be safe due to the way they're used.

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

#82
post #49

Earlier quoted context omitted.

Would it be possible to write the check so that the null test overlaps with the rest of the instructions? If the test is anyways assumed to pass, you should only get a 1-instruction overhead, right? (That'll only work for null.)

1 instruction != 1 clock cycle. In particular that would utterly kill the usage of unique_ptr on things like small embedded processors or microcontrollers that either lack speculative execution entirely or do not have the level of branch predictor & speculative execution capabilities of a high-end x86 or ARMv8 CPU.

FWIW: in general, simpler controllers (especially those in-order ones) tend to be much more friendly to branching (exactly because they're not out-of-order). NB: I am not arguing whether unique_ptr should check or not: if I want checked version, I will write my own wrapper, it is not a rocket science.

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

#83
post #27

Earlier quoted context omitted.

If you're not being facetious, then really, not much. You really can't go wrong with smart pointers unless you explicitly try to access the memory it handles rather than going through its normal interface (e.g., not using get()). Shared pointers are basically reference counted just like many other language handle memory management.

> > as long as we’re following these rules/ guidelines If that's an assumption, it's not worth much. A safe language is one that enforces the rules, not one that hopes the program authors self-enforce.

By that measure Rust would be unsafe since it hopes that the authors don't just put everything in unsafe blocks.

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

#84

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.

There is a compiler option for that, just run javac alias instead of g++

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

#85
post #77
post #76

Earlier quoted context omitted.

Yes, NVidia specially designs their new GPGPUs for C++ execution. "Volta and Cuda C++" - http://cppcast.com/2017/09/olivier-giroux/ CppCon 2017: Olivier Giroux "Designing (New) C++ Hardware” https://www.youtube.com/watch?v=86seb-iZCnI

Yep, this one. On CPPCON17, Olivier Giroux has said: "[when designing Volta,] we were literally quoting C++ standard to each other".

Neat. Thanks to both of you!

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

#86
post #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,…

> use the type system to have the compiler statically check the pointers are live

It doesn't explain how it would statically ensure that a moved-from unique_ptr (or equivalent) can not be used. In fact the only mentions of moves are that owning pointers can only be moved and soft pointers can be moved or copied, but C++'s move does not remove any access, it just moves the content leaving the moved-from object in a "valid but unspecified state".

Note that valid != safe. Dereferencing a moved-from unique_ptr is unsafe for instance.

Rust's affine types solve this issue, a moved-from type (Box included) simply can't be used, its scope ends when it's moved.

> Looking online, I see that people implement all the same primitives in rust, with exactly the same safety caveats.

Rust's (safe) pointers and references don't throw exceptions on explicit use after free because such code doesn't compile at all, and its equivalent to dynamic_cast has to be very specifically opted in: https://doc.rust-lang.org/1.19.0/std/any/trait.Any.html#meth...

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

#87
post #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 de…

> 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 article's "soft" pointer does not own its contents and depends on an owning pointer, so the semantics are much closer to Rust's references. In fact, the article draws an analogy between soft pointers and weak_ptr. And of course dereferencing "soft" pointers can fault.

> 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! ).

Async does jack shit for concurrent safety. You can have either shared-memory concurrency or isolated concurrency.

And explicit asynchronous API (à la JS or C#) are dreadful.

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

#88
post #10

Earlier quoted context omitted.

Perhaps someone better versed in those compilers can add to/correct me here, but I'm pretty sure that can only happen if you're invoking UB somewhere along the line.

Once you've entered the realm of undefined behavior, the compiler can really do whatever it likes. Before then all it can do is assume you're not doing anything undefined.

> Once you've entered the realm of undefined behavior, the compiler can really do whatever it likes. Before then all it can do is assume you're not doing anything undefined.

In practice there is very little difference and you're effectively entering the realm of UB as soon as the program starts, because through inlining and propagation a possible UB may be leveraged before the UB is sequentially hit.

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

#89

Earlier quoted context omitted.

> a fundamental misunderstanding of the problem No kidding! There is one right here: > Yes, in some cases the compiler can prove UB, and uses it to write optimiation Compilers do not prove UB , on the contrary they postulate no-UB and then use this axiom to prove other properties of the code.

I suppose that's true, yes. My point was more that your compiler is not hitting a line of code and saying "I know this is or is not UB" because it can not do that in the general case - it is definitely incorrect to say it is 'proving' this. Would you consider that an accurate representation?

> My point was more that your compiler is not hitting a line of code and saying "I know this is or is not UB" because it can not do that in the general case

I think it's still a (cause of) misunderstanding. For the compiler, UBs are situations which axiomatically can not occur. "This is UB" is not a concept, because the compiler assumes at all point that UBs can not occur.

The compiler doesn't go "oh you're dereferencing a pointer which may be null, fuck you", it goes "you're dereferencing a pointer so it can't be null, and thus I can remove anything assuming possible nullability".

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

#90
post #67

Earlier quoted context omitted.

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,…

> use the type system to have the compiler statically check the pointers are live It doesn't explain how it would statically ensure that a moved-from unique_ptr (or equivalent) can not be used. In fact the only mentions of moves are that owning pointers can only be moved and soft pointers can be moved or copied, but C++'s move does not remove any access, it just moves the content leaving the moved-from object in a "v…

> Rust's (safe) pointers and references don't throw exceptions on explicit use

Which essentially goes at the cost of having Java-style semantic memory leaks (very generally, _any_ kind of keeping-an-object-as-long-as-at-least-one-reference-exists suffers from it) => we still have to pick our poison (personally, I _strongly_ prefer to avoid refcounting, and it does work like a charm in a few very serious million-LoC/billions-transactions projects, but I do agree that opinions may differ).

Post reply on HN