Live data from Hacker News

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

ithare.com

41–50 of 103 posts

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

#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 program did not continue in an invalid state.

Specifically:

  word* target = segmentStart + farPointer.offset;
  if (target = segmentEnd) {
    throwBoundsError();
  }
  doSomething(*target);
(a simplified version of the actual code) was used to detect if target had overflowed (and thus target However, as it turns out, pointer arithmetic that overflows is undefined behavior under the C standard. As a result, the compiler is allowed to assume that the addition on the first line never overflows. Since farPointer.offset is an unsigned number, the compiler is able to conclude that target

The post that's from (the sumbmitted article to the HN discussion I linked) is fairly accessible in my view. I highly recommend reading it.

Another discussion that probably has good info is this one.[2]

1: https://news.ycombinator.com/item?id=14163111

2: https://news.ycombinator.com/item?id=14785867

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

#42
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...

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

#43
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…

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.

UAF is still possible. Iterator invalidation, and such.

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

#44
post #26
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.

That's exactly the problem. C/C++ has undefined behavior as part of the language spec, so it can never be safe unless you use a compiler that promises to reject programs that invoke undefined behavior.

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 thing you'd expect it to do and transform it into a simple memory read.

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

#46
post #30
post #27

Earlier quoted context omitted.

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

I don't think anyone claimed the _language_ was safe.

Title: "A Usable C++ Dialect That Is Safe Against Memory Corruption".

Any questions?

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

#47
Interesting article. I hope the author has a chance to take a look at the Pony language, which he's described the core of. Now all it needs is a capability system to statically ensure that the data in sent messages is safe without copying. (And to move those runtime checks into the type system.)

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

#48
post #26

Earlier quoted context omitted.

That's exactly the problem. C/C++ has undefined behavior as part of the language spec, so it can never be safe unless you use a compiler that promises to reject programs that invoke undefined behavior.

It's more complicated than this. C++ compilers can't just "reject" UB code - they don't have enough information at all times to prove that code invokes UB, the languages is not powerful enough to represent this in all cases. When people say "just fix this in compilers, don't compile when they run into UB" it's a fundamental misunderstanding of the problem. Yes, in some cases the compiler can prove UB, and uses it to…

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

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

#49
post #40

Earlier quoted context omitted.

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…

Then you have a check on every deref, which means you incur a relatively large performance penalty for using a smart pointer. If you want stuff like this there are other languages out there.

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

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

#50
post #46
post #30

Earlier quoted context omitted.

I don't think anyone claimed the _language_ was safe.

Title: "A Usable C++ Dialect That Is Safe Against Memory Corruption". Any questions?

The author claims that the rules described, "extending" the standard C++, are enforcing memory corruption, and it is this author described subset that is still unsafe, not C++ in general. Think about english vs. americanized english, largely the same, but two distinct entities.

In C++, you are free to shoot yourself in the foot. In Rust, you have a Government inspector ensure that you always point the gun not just in a "safe" direction, but only toward a crosshair target at a designated gun range.

Post reply on HN