Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

> You're not fully understanding the issue with memory safety. When you write C or C++, you're promising that you won't violate memory safety at all.

The post you reply to does not indicate a misunderstanding of memory safety at all. .



The comment I'm responding to implicitly assumes memory safety violations are like other bugs where that it's meaningful to speak of programs being more or less correct depending on the number of issues. What I'm emphasizing is that code with safety violations, strictly speaking, isn't C/C++ at all. It's more like parsing paint splatters as perl [0]. You might get something resembling what you want if you're lucky, but you also might not depending on how the compiler feels that day.

Let's use an example: https://godbolt.org/z/TP6n4481j

The code shows main immediately calling a nullptr. What the compiler generates is a program that calls unreachable() instead. These are two different programs. If memory safety is "just" a bug, this would be a miscompilation. It's not a miscompilation though, because what I've given the compiler is something that resembles C++, but is actually some similar language where null dereferences are meaningful. The compiler only knows about C++ though and C++ doesn't have nullptr dereferences, so it assumes I haven't done that. Instead it generates a program corresponding to an execution trace that is valid C++, even if it can't see the call to NeverUsed(). If you use -O0, you get the segfault as expected.

A single instance of memory unsafety (or other UB) can take your program arbitrarily far from "correct". All other things being equal, a program with 1 violation might be just as incorrect as a program with 100. I could add a hundred more lines of safety violations after Do() without changing the compiled behavior. You don't even need to execute the unsafety to have "spooky action at a distance" cause that change.

[0] https://web.archive.org/web/20190406194101/http://colinm.org...


Finally someone who actually gets it.

Many Rust proponents are experienced C and C++ developers who have dealt with this situation for decades. Given the language, it's understandable that compilers make the choices that they do. It's also understandable that programmers find it unreasonably difficult to reason about code written in such a language.


> What I'm emphasizing is that code with safety violations, strictly speaking, isn't C/C++ at all.

This isn't really correct and many programming language standards (including that of C and C++) don't support this view. Many language standards define a notion of conformance. Strictly conforming programs aren't allowed to invoke behaviors that which are undefined[1].

Conforming programs do not have this requirement and basically any non-trivial C and C++ programs are written to this rather than the notion of "strictly conforming".

Most non-trivial programs are not strictly conforming (including some C compilers themselves), generally because restricting the set of targets to something smaller than "any possible C implementation" is useful.

It is perfectly legal (and very desirable in cases where the standards fall short of usefulness) for a C compiler to define undefined behavior. What you compiled is still a C program, just one that isn't portable across the entire potential set of implementations.

[1]: Or unspecified or implementation-defined, for that matter, but this part tends to get left out of discussions.


The C++ ISO document describes conforming implementations of their language, ie compilers and similar tools - that conformance isn't a property of your program at all.

So far as I can tell there is no mention of the program conformance you're describing.


There's a line in the standards that basically says a conforming program is anything acceptable by a conforming implementation. In theory you could have an implementation that gives semantics to UB like Fil-C or CCured do. No mainstream implementation does that for memory unsafety due to the performance overhead, and conforming implementations are required to document those extensions. I don't think there's a sane argument for an implementation to intentionally choose the behavior in the example I provided and Clang certainly doesn't, so it's non-conformant regardless.


> No mainstream implementation does that for memory unsafety due to the performance overhead

It depends on what is considered memory safety here (especially when some of them are arguably unforced errors in the standards), but many implementations do in fact have options for this ("no delete null pointer checks" for example is an example of one such option, for example, which is used extensively by the Linux kernel for example).

The performance impact tends to be much more negligible outside of, sometimes contrived, benchmarks, especially when compared to algorithmic efficiencies or the like.


> There's a line in the standards that basically says a conforming program is anything acceptable by a conforming implementation.

Perhaps it "basically" says that, but it certainly doesn't appear to literally say any such thing, so you're going to need to specify where you believe you saw this so that I can have any idea what it actually says.


C standard N3096, Section 4:

    A conforming program is one that is acceptable to a conforming implementation.
That definition goes all the way back to C89. The C++ standard drops it for the term "well-formed program", but adds enough clarifications in 1.4 to mean essentially the same thing.


Ah, no. Most C++ programs that compile are not well-formed programs. This functions as an escape hatch for Rice's Theorem. You see, C++ even more so than C has semantic requirements - but Rice says all non-trivial semantic requiremnts are Undecidable. So, if you want what C++ says it wants it appears that compilers would be entirely impossible and that's awkward. To "fix" that C++ says it's fine if the compiler will compile your program even though it is not well-formed, the program doesn't have any meaning of course, only well-formed programs have meaning, but it did compile, so as a programmer you're happy...

C++ has a recurring phrase in its standard document "Ill-formed No Diagnostic Required" or IFNDR which carries this intent. The compiler can't tell you made a mistake, but you didn't actually write a valid C++ program so -shrug-

Because there's no way to tell for sure without exhaustive human examination we don't know for sure how many C++ programs aren't actually well-formed but experts who've thought about it tend to think the answer for large C++ software projects is all or most of them.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: