Live data from Hacker News

Why Safety Profiles Failed

circle-lang.org

181–190 of 233 posts

Re: Why Safety Profiles Failed

#181
post #165

Earlier quoted context omitted.

> It seems to me like we already have a lower-overhead approach ... Rust Rewriting all the existing C++ code in Rust is extremely high-cost. Practically speaking, that means it won't happen in many, many cases. I think we want to find a more efficient way to achieve memory safety in C++. Not to mention, Rust's safety model isn't that great. It does memory safety, which is good, but it's overly restrictive, disallowin…

Folks who want to propose alternatives should do so! Right now, you’ve only got the two: profiles and Safe C++. There are also two that aren’t proposals. It have a semblance of a plan: “graft Hylo semantics instead of Rust semantics” and “scpptool.” Realistically, unless something else concrete and not “could be” is found at the eleventh hour, this is the reality of the possible choices.

Don't forget the comment above proposes another alternative, "rewrite it in Rust".

The problem with such a proposal is that the cost is impossibly high for many, many cases. Effectively, across the entire existing C++ code base, you get "X% rewrite it in Rust plus (1-X)% do nothing at all", where X is probably a lot closer to 0 than 1.

If your goal is to address as many vulnerabilities as possible, you might want to look for a better plan.

I don't have a ready plan, but the general approach of incrementally improving the safety of existing C++ seems likely to be more effective than rewrites to me -- it could let the X in my formula move a lot closer to 1. Possibly one of the existing mechanisms for this is already better than "RIIR".

Edit, I meant to add:

For many, many things it's not the eleventh hour. For a lot of existing C++ code, no one has reached a final decision point. Many haven't really started at all and are at the 0th hour.

Re: Why Safety Profiles Failed

#182

Earlier quoted context omitted.

There are reasonably good c++11 conventions for lifetimes - if it is a unique_ptr you own it, otherwise you don't and shouldn't save a copy. Almost nobody follows them, but they are good conventions and you should, and write up a bug if someone else isn't. Similar, for threads, keep your data confined to one thread, but explicit where you move/copy it to a different thread (note I said move or copy - the first thread…

> There are reasonably good c++11 conventions for lifetimes [...] Almost nobody follows them [...] I swear I'm not trying to be snarky or rude here, but is it actually a "convention" if almost nobody follows it? This seems like one example of my general issue with C++, in that it could be great if everyone agreed to a restricted subset, but of course nobody can coordinate such agreement and it doesn't exist outside c…

Honestly, I blame MSVC for a lot of lost momentum when adopting new standards, given it takes them more than 4 years implementing those features. Ofc, this isn't the case for C++11 today, but a lot of projects were started prior to 2015.

And don't get me started on C itself. Jesus Christ.

Re: Why Safety Profiles Failed

#183

Earlier quoted context omitted.

Smart pointers, containers... There are plenty of best practices that would give memory safety but nobody uses them (and not for cases where in rust you would have to use unsafe and thus there is good reason). Which is why safety profiles are so interesting, they are something I should be able to turn on/off on a file by file basis and thus easily force the issue. Of course profiles don't exist yet (and what is propo…

Safe C++ is also something you turn on file by file.

What matters is tool support. Anything in the standard I expect to get tool support for (eventually), while everything else - lets just say I've been burned a lot by tools that are really nice for a few years but then they stop maintaining it and now I have to rewrite otherwise perfectly good code just so I can upgrade something else. Standard C++ isn't going anyplace soon and I feel confident that if something makes it into the standard tools will exist for a few decades at least (long enough for me to retire). Will Rust or Safe C++ still be around in 10 years, or just be another fad like so many other languages that got a lot of press for a few years and now are not used much (you probably cannot answer this other than a guess)

Re: Why Safety Profiles Failed

#184

Earlier quoted context omitted.

What's with the "this model detects all possible errors" quote at the beginning of the post, then?

That’s a claim about dangling pointers and ownership. Profiles do not solve aliasing or concurrency, as two examples of things that Safe C++ does that are important for memory safety.

Concurrency, sure, I can see thinking of that as a separate thing (as some people from Google have advocated for). But aliasing isn't a memory safety violation, it's a cause of memory safety violations (and other kinds of bugs besides). The first example from the linked post is straightforwardly a dangling pointer dereference, and I don't understand how the people behind safety profiles can claim that it's out of scope just because it involves aliasing. Did they say something like "this assumes your code follows these non-machine-checkable aliasing rules, if it doesn't then all bets are off"?

Re: Why Safety Profiles Failed

#185
post #179

Earlier quoted context omitted.

If the vector has to be resized in push_back, the implementation copy-constructs a new object from x. It resizes the buffer. Then it move-constructs the copy into the buffer. The cost is only a move construct per resize... So it's on the order of log2(capacity). Very efficient. But don't get used to it, because there are plenty of other C++ libraries that will break under aliasing.

I think the implementation in C++ does not do realloc on push_back, but allocates new memory, creates the new element and only then deallocates it. I believe the reason f3 is safe is that the standard says that the iterators/references are invalidated after push_back – so push_back needs to be carefully written to accept aliasing pointers. I am pretty sure if I were writing my own push_back it would do something like…

> allocates new memory, creates the new element and only then deallocates it.

Ah, I'll have to check the standard. Thanks.

Re: Why Safety Profiles Failed

#186

Earlier quoted context omitted.

There are reasonably good c++11 conventions for lifetimes - if it is a unique_ptr you own it, otherwise you don't and shouldn't save a copy. Almost nobody follows them, but they are good conventions and you should, and write up a bug if someone else isn't. Similar, for threads, keep your data confined to one thread, but explicit where you move/copy it to a different thread (note I said move or copy - the first thread…

> There are reasonably good c++11 conventions for lifetimes [...] Almost nobody follows them [...] I swear I'm not trying to be snarky or rude here, but is it actually a "convention" if almost nobody follows it? This seems like one example of my general issue with C++, in that it could be great if everyone agreed to a restricted subset, but of course nobody can coordinate such agreement and it doesn't exist outside c…

What we have is a human problem. The convention exists in enough places (though in slightly different forms) to call it a convention, but it needs more adoption.

Every once in a while someone who writes a lot of Rust will blog about some code they discovered that was 'unsafe' and after looking close they realized it wasn't doing something that fundamentally required unsafe (and often fixing the code to be safe fixed real bugs). C++ and Rust have to leave people enough rope to hang themselves in order to solve the problems they want to solve, but that means people will find a way to do stupid things.

Re: Why Safety Profiles Failed

#187

Earlier quoted context omitted.

Safe C++ is also something you turn on file by file.

What matters is tool support. Anything in the standard I expect to get tool support for (eventually), while everything else - lets just say I've been burned a lot by tools that are really nice for a few years but then they stop maintaining it and now I have to rewrite otherwise perfectly good code just so I can upgrade something else. Standard C++ isn't going anyplace soon and I feel confident that if something makes…

I fully agree, this thread is about two possible futures for getting that support in the standard: Safe C++ and profiles.

Re: Why Safety Profiles Failed

#188

Earlier quoted context omitted.

That’s a claim about dangling pointers and ownership. Profiles do not solve aliasing or concurrency, as two examples of things that Safe C++ does that are important for memory safety.

Concurrency, sure, I can see thinking of that as a separate thing (as some people from Google have advocated for). But aliasing isn't a memory safety violation, it's a cause of memory safety violations (and other kinds of bugs besides). The first example from the linked post is straightforwardly a dangling pointer dereference, and I don't understand how the people behind safety profiles can claim that it's out of sco…

Sure, I said “aliasing” to mean “these rules do not prevent memory unsafety due to misusing aliased pointers.”

I hesitate to answer your question, but my impression is the answer is that they’re just not shooting for 100% safety, and so it’s acceptable to miss this kind of case.

Re: Why Safety Profiles Failed

#189
post #133

Additionally I still cannot understand why they didn't make iterators safe from the very beginning. In the alias examples some iterators must alias and some not. With safe iterators the checks would be trivial, as just the base pointers need to be compared. This could be done even at compile-time, when all iterators bases are known at compile-time. Their argument then was that iterators are just simple pointers, not…

The C++ committee and standard library folks are in a hard spot.

They have two goals:

1. Make primitives in the language as safe as they can.

2. Be as fast as corresponding completely unsafe C code.

These goals are obviously in opposition. Sometimes, if you're lucky, you can improve safety completely at compile time and after the safety is proven, the compiler eliminates everything with no overhead. But often you can't. And when you can't, C++ folks tend to prioritize 2 over 1.

You could definitely argue that that's the wrong choice. At the same time, that choice is arguably the soul of C++. Making a different choice there would fundamentally change the identity of the language.

But I suspect that the larger issue here is cultural. Every organization has some foundational experiences that help define the group's identity and culture. For C++, the fact that the language was able to succeed at all instead of withering away like so many other C competitors did is because it ruthlessly prioritized performance and C compatibility over all other factors.

Back in the early days of C++, C programmers wouldn't sacrifice an ounce of performance to get onto a "better" language. Their identity as close-to-the-metal programmers was based in part on being able to squeeze more out of a CPU than anyone else could. And, certainly, at the time, that really was valuable when computers were three orders of magnitude slower than they are today.

That culture still pervades C++ where everyone is afraid of a performance death of a thousand cuts.

So the language has sort of wedged itself into an untenable space where it refuses to be any slower than completely guardrail-less machine code, but where it's also trying to be safer.

I suspect that long-term, it's an evolutionary dead end. Given the state of hardware (fast) and computer security failures (catastrophically harmful), it's worth paying some amount of runtime cost for safer languages. If you need to pay an extra buck or two for a slightly faster chip, but you don't leak national security secrets and go to jail, or leak personal health information and get sued for millions... buy the damn chip.

Re: Why Safety Profiles Failed

#190
post #91

Earlier quoted context omitted.

With a safe runtime, a pointer is really something like a `struct { u32 allocation_base, allocation_offset;}`. (it may be worth doing fancy variable-bit-width math to allow many small allocations but only a few large ones; it's also likely worth it to have a dedicated "leaf" section of memory that is intended not to contain any pointers) An implementation of `sort` would start with: `assert (begin.allocation_base ==…

Tracking allocations is necessary, but not sufficient. struct S { int arr1[100]; std::string s; int arr2[100]; }; void foo(S& s) { //arr1 and arr2 are in the same complete object //so they are in the same allocation std::sort(std::begin(arr1), std::end(arr2)); } To make it sound you really need to track arrays specifically (including implicit single-element ones), not just allocations. It's surely somewhat feasible,…

(if `sizeof(char *)` != `sizeof(int)` it will be detected as an illegal memory access, since at a minimum every word is tagged whether it's a pointer or not. Otherwise ...)

That's really an aliasing problem, not specific to arrays. The tricky part about tagging memory with a full type is that a lot of code, even in standards, relies on aliasing that's supposed to be forbidden.

Still, even if the `sort` isn't detected (due to the user insisting on permissiveness rather than adding annotations), it would still detect any attempt to use `s` afterward.

As for a limited array-specific solution ... I can't think of one that would handle all variants of `sort((int *)&s[0], (int *)&s[1])`. And do we want to forbid `sort(&s.arr[0], (int *)&s.s)`?

Post reply on HN