Live data from Hacker News

Why Safety Profiles Failed

circle-lang.org

171–180 of 233 posts

Re: Why Safety Profiles Failed

#171

The assumption here seems to be that the compiler/analyzer is only able to look at one function at a time. This makes no sense. Safety is a whole-program concern and you should analyze the whole program to check it. If anything as simple as the following needs lifetime annotations then your proposed solution will not be used by anyone: const int& f4(std::map & map, const int& key) { return map[key]; }

Whole-program analysis is not tractable (i.e., not scalable), and Rust has already proven that function signatures are enough, and does actually scale. The analysis can be performed locally at each call site, and doesn't have to recurse into callees. Your function would look like this in Rust: fn f4 (map: &'a Map , key: &i32) -> &'a i32 { ... } You don't need much more than a superficial understanding of Rust's lifet…

Something I would like to know is how much lifetime annotation you can infer (recursively) from the function implementation itself. Compiler driven, IDE integrated, automatic annotation would be a good tool to have.

Some amount of non-local inference might also be possible for templated C++ code that already lack a proper separate compilation story.

Re: Why Safety Profiles Failed

#172

Earlier quoted context omitted.

The idea is to keep it in C++ and do new development in an hypothetical Safe C++. That would ideally be significantly simpler than interface with rust or rewrite. There is of course the "small" matter that Safe C++ doesn't exist yet, but Google analysis showing that requiring only new code to be safe is good enough, is a strong reason for developing a Safe C++.

Safe C++ does exist today: it’s implemented in Circle. You can try it out on godbolt right now.

Thanks! I have been putting off playing with rust lifetimes. I guess now I have no excuses.

Re: Why Safety Profiles Failed

#173

Why is `f3` safe? My thought (which is apparently wrong) is that the `const int& x` refers to memory that might be freed during `vector::push_back`. Then, when we go to construct the new element that is a copy of `x`, it might be invalid to read `x`. No? Is this related to how a reference-to-const on the stack can extend the lifetime of a temporary to which it's bound? I didn't think that function parameters had this…

[deleted]

Re: Why Safety Profiles Failed

#174

Why is `f3` safe? My thought (which is apparently wrong) is that the `const int& x` refers to memory that might be freed during `vector::push_back`. Then, when we go to construct the new element that is a copy of `x`, it might be invalid to read `x`. No? Is this related to how a reference-to-const on the stack can extend the lifetime of a temporary to which it's bound? I didn't think that function parameters had this…

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.

Re: Why Safety Profiles Failed

#175
post #168

Earlier quoted context omitted.

There’s some truth to both. What’s good for computers is often good for humans, but there’s a balance to be had. The elision rules are an acknowledgment that being 100% explicit in surface syntax is going a bit too far, even if it’s important info for the computer to have.

Fair enough! The part that always stuck out to me is that there were other potential designs that could have been made around how (and which) lifetime information would be specified. I think sometimes people might not realize that the we didn't get stuck with the requirements we have for lifetime annotation today due to validation requiring exactly that set of information or an indifference to the burden it might pla…

For sure. And I do find https://cfallin.org/blog/2024/06/12/rust-path-generics , for example, interesting. It’s certainly not like what Rust does today is the only way things could ever be. Heck, I’m sad we never got elision on structs in 2018 like we were talking about.

Re: Why Safety Profiles Failed

#176

Earlier quoted context omitted.

Whole-program analysis is not tractable (i.e., not scalable), and Rust has already proven that function signatures are enough, and does actually scale. The analysis can be performed locally at each call site, and doesn't have to recurse into callees. Your function would look like this in Rust: fn f4 (map: &'a Map , key: &i32) -> &'a i32 { ... } You don't need much more than a superficial understanding of Rust's lifet…

Something I would like to know is how much lifetime annotation you can infer (recursively) from the function implementation itself. Compiler driven, IDE integrated, automatic annotation would be a good tool to have. Some amount of non-local inference might also be possible for templated C++ code that already lack a proper separate compilation story.

At the limit, the answer is “between zero and completely.” Zero because you may only have access to the prototype and not the body, say if the body is in another translation unit, or completely if a full solution could be found, which is certainly possible for trivial cases.

The reason to not do this isn’t due to impossibility, but for other factors: it’s computationally expensive, I’d you think compile times are already bad, get ready for them to get way worse. Also, changing the body can break code in competently different parts of your program, as changing the body changes the signature and can now invalidate callers.

Re: Why Safety Profiles Failed

#177
post #125

Earlier quoted context omitted.

Microsoft eventually learned that keeping full POSIX support would have been a better outcome in today's server room if they had done it properly instead. Likewise, pushing half solutions like profiles that are still pretty much a paper idea, other than what already exists in static analysers, might decrease C++'s relevance in some domains, and eventually those pushing for them might find themselves in the position t…

We can dream of what it would be like with full POSIX support on Windows, but it was a pipe dream to begin with. There are some major differences between Windows and POSIX semantics for things like processes and files. The differences are severe enough that Windows and POSIX processes can’t coexist. The big issue with files is that on POSIX, you can conceptually think of a file as an inode, with zero or more paths po…

This wasn't the case with the subsystems approach, which is also validated by all micro-computers from IBM and Unisys still in use, being further developed, with incompatible differences between their mainframe heritage and UNIX compatability workloads.

Re: Why Safety Profiles Failed

#178
post #125

Earlier quoted context omitted.

Microsoft eventually learned that keeping full POSIX support would have been a better outcome in today's server room if they had done it properly instead. Likewise, pushing half solutions like profiles that are still pretty much a paper idea, other than what already exists in static analysers, might decrease C++'s relevance in some domains, and eventually those pushing for them might find themselves in the position t…

Adopting what static analyzers do is a no-go, as they rely on non-local reasoning, even across translation units for lifetime and aliasing analysis. Their output highly depend on what they can see, and they generally can't see the source code for the whole program. I also doubt that they promise any kind of stability in their output across versions. This is a not a jab against static analyzers, by all means use them,…

Yeah, yet that is exactly the approach being pushed by those on the profiles camp.

Further, the clang tidy and VC++ analysis based on some of the previous work, e.g. lifetime analysis paper from 2015, barely work, full of false positives.

I was looking forward to it in VC++, and to this day in VC++ latest, it still leaves too much on the table.

Re: Why Safety Profiles Failed

#179

Why is `f3` safe? My thought (which is apparently wrong) is that the `const int& x` refers to memory that might be freed during `vector::push_back`. Then, when we go to construct the new element that is a copy of `x`, it might be invalid to read `x`. No? Is this related to how a reference-to-const on the stack can extend the lifetime of a temporary to which it's bound? I didn't think that function parameters had this…

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 "reserve(size() + 1), copy element into the new place", and it would have different aliasing requirements...

(For me this is a good example of how subtle such things are)

Re: Why Safety Profiles Failed

#180
post #87

> A C++ compiler can infer nothing about aliasing from a function declaration. True. but you don't solely rely on the declaration, do you? lots of power comes from static analysis.

You do solely rely on the declaration.

From P3465: "why this is a scalable compile-time solution, because it requires only function-local analysis"

Profiles uses local analysis, as does borrow checking. Whole program analysis is something you don't want to mess with.

Post reply on HN