158. WG21 January mailing, safety, contracts
With Bjarne Stroustrup, Gianluca Delfino, Vladimír Arnošt and other colleagues.
Media
Video
Podcast
Powered by RedCircle
Feedback
Paul Floyd writes:
In your latest podcast you talked about values that get used to fill memory like 0x8BADF00D.
You also mentioned 0xAA. This gets used a lot in memory tests since it is 1010 in binary. So by writing 0xAA then 0x55 (0101) you can try to test if there are any problems with neighbouring bits toggling.
CppCast news
The CppCast podcast has new hosts: Timur Doumler and Phil Nash. Best of luck to them with CppCast!
The intro episode is here, with the former hosts Rob Irving and Jason Turner as guests.
Interesting tidbits:
- Jason said that the proposed safety features (like zero-initialisation of locals) make sense only for those who don’t use any tools, since the current compiler and static analysis tools let you know when you use uninitialised variables.
- Timur mentioned something called erroneous behaviour, which is not undefined behaviour but is still an error, and which could possibly be discussed in the committee. It would allow the tools to detect it but would also prevent exploits. The problem is that such behaviour can’t be expressed in the C++ abstract machine.
WG21 January mailing
What’s the status on reflection? ↑
Is the committee still… reflecting… on it?
Active discussion re: default zero-initialisation of variables.
A call to action: Think seriously about “safety”; then do something sensible about it
P2739R0 by Bjarne Stroustrup.
Discussions: HackerNews, Reddit.
Regarding the NSA memo:
That specifically and explicitly excludes C and C++ as unsafe. As is far too common, it lumps C and C++ into the single category C/C++, ignoring 30+ years of progress. Unfortunately, much C++ use is also stuck in the distant past, ignoring improvements, including ways of dramatically improving safety.
BTW there is another language safety memo, this time by Consumer Reports (PDF). It also talks about memory safety, and also mentions C and C++, but it’s either “C” or “C/C++” – I couldn’t see any mentions of C++ as a separate language (Rust mentions are aplenty). It’s more than a little annoying. I also couldn’t see any C++ experts in the list of contributors.
See also:
Static analysis:
- Visual Studio Core Guidelines analysis profile
- Clang-tidy
What might “something sensible to do” be? I suggest making a list of issues that could be considered safety issues (including UB) and finding ways of preventing them within the framework of P2687R0. That’s what I plan to do.
DG opinion on safety for ISO C++
P2759R0 by H. Hinnant, R. Orr, B. Stroustrup, D. Vandevoorde, M. Wong.
This looks like a “meta-paper”, proposing a process and a framework for further security work.
C++ appears, at least in public image, less competitive than other languages in regards to safety. This seems true especially when compared to languages that advertise themselves more heavily/actively/brazenly/competently than C++. In some ways, they appear especially to satisfy an executive-suite definition of safety, which makes it attractive for executives to ask for a switch from C++.
Yet what has been lost in the noise is that C++ has made great strides in recent years in matters of dangling, resource and memory safety. <…>
Newer languages have less vulnerabilities because they have not been through the test of time. Today, even RUST (sic!) has had vulnerabilities discovered recently <…> and time will expose more vulnerabilities and weaknesses for general use.
Haha, take that, RUST! (this dig at Rust, while likely fair, doesn’t look good, tbh.)
The paper proposes “profiles”:
To support more than one notion of “safety”, we need to be able to name them. We call a collection of restrictions and requirements that defines a property to be enforced, a “profile.” A typical profile will not be a simple subset of C++ language features.
Initial work on the idea of profiles can be found in the [C++ Core Guidelines] and in Section 7 in a recent paper by Stroustrup and Dos Reis P2687. Profiles package up several features to make it visible for a code region. Profiles do not limit code in such a way that it reduces the language expressivity like subsets do.
We like to think Profiles do not fragment the ecosystem but increase diversity.
For example we might even have safety profiles for safe-embedded, safe-automotive, safe-medical, performance-games, performance-HPC, and EU-government-regulation.
Profiles impose restrictions on use where they are activated. They do not change the semantics of a valid program. In particular, a piece of code means the same in every profile (or no profiles). This property is the crucial difference between dialects and our approach.
This sounds eerily similar to what Jarrad Waterloo proposed in his paper P2657: C++ is the next C++.
Some feedback.
Contracts for C++: Prioritizing Safety
The paper now has an inset with the main idea at the top:
This document suggests a design of contract predicates that emphasizes safety by default, by reducing opportunities for undefined behaviors in contracts and their propagation across abstraction boundaries. An accommodation, in the form of relaxed contract predicates, is provided for scenarios where “safety by default” is not a primary concern.
The goal:
Consequently, a viable contract system for C++ (however minimal) must ensure that the evaluation of a contract predicate cannot itself be exploitable source of undefined behavior (by compiler optimizers).
Some notable quotes:
It is also an answer to the call to action for improving safety in C++ programs (Stroustrup, A call to action: Think seriously about “safety”; then do something sensible about it, 2022).
In practice, contracts are summaries of the expectations and guarantees of a successful function call. As such, not every single action taken (or statement written) in the body of a function implementation needs to be reflected in the expression of the contracts of a function.
The ideal that the contract predicates design presented in this paper aims for is: the evaluation of contract predicates shall be free of undefined behavior, and they shall not modify parameters they reference. Contracts provide basic mitigation framework, they should not themselves be sources of vulnerabilities. <…> We should aim to reduce undefined behavior from contract as much as possible.
This proposal modifies the current “MVP” as follows: categorize contracts into two groups: (1) non-relaxed contracts; (2) relaxed contracts; introduction of the notion of conveyor functions.
There is a whole section on UB in contracts. The proposed solution is:
Tighten the specification of the [C++] abstract machine so that contract predicate evaluation never invokes undefined behavior (even if other parts might), and appropriately restrict the contract predicate language.
Regarding side effects in contract expressions, Gaby says:
I suggest that we make each of a pre-condition and a post-condition, a self-contained expression (their free variables being function parameters and constants), and side-effect free when seen from the outside of each of their cone of evaluation.
A new concept of conveyor function is introduced:
A conveyor function is conceptually a function that, when called with an argument list, performs no side effects outside of its function body or argument list. Furthermore, such a function does not perform any operation the behavior of which might invoke undefined behavior. A conveyor function is declared with the attribute
[[conveyor]]
, and its body is subject to syntactic restrictions as defined below.
Is it what they call a “pure” (“referentially transparent”) function, with extra security features and restrictions to prevent UB?
The Appendix contains answers to the questions raised after presenting the initial version of the paper and collated in D2700R1. Unfortunately, the questions are not copied, so you need to have both papers open to see the questions together with the answers.
There is a quote by Chuck D. at the end of the paper:
It is not a matter of skills
But a battle of wills
I can’t help thinking it’s about the Committee.
Contract predicates that are not predicates
P2570R2 by Andrzej Krzemieński is about side effects in contract expressions.
Proposal of Simple Contract Side Effect Semantics
P2756R0 by Andrew Tomazos:
We propose and motivate a set of simple, intuitive and time-honored semantics for side effects in MVP contracts. In essence, we propose that contract expressions have the same side effect semantics and evaluation semantics as any other C++ expression.
This paper seems to be based on the notion that contracts are either not evaluated or evaluated with program termination on failure, which is unacceptable for a large number of applications. Also, I think that P2680R1 by Gabriel Dos Reis proposes a better solution for dealing with side effects.
Proposal of Condition-centric Contracts Syntax
P2737R0 by Andrew Tomazos introduces another (3rd!) style of contract expressions.
We propose coining a new term called an “incondition”. If a precondition is a condition that must be true at the entry of a function and a postcondition is a condition that must be true at the exit of a function, an incondition is a condition that must be true at a point within (or inside) a function.
But it’s not assertion, because assertion doesn’t rhyme. No, really.
Much the same as postcondition, incondition is not an English word and does not appear in the dictionary.
And to my medically-educated mind it sounds like a symptom. Well, since we’re inventing new words now, I propose midcondition instead, because why not.
There’s more. The author proposes to truncate these non-words to precond
, incond
, and postcond
, because we don’t have enough of awkward keywords in C++. His motivation is rock-solid too:
The spelling “cond” is a very common shortening of the word “condition” used by programmers.
Evaluation of Checked Contract-Checking Annotations
P2751R0 by Joshua Berne:
We propose a series of rules to govern the evaluation of predicates and thus to determine when a contract violation has occurred.
This also deals with two modes only, No_Eval
and Eval_and_abort
.
When the predicate of a checked contract-checking annotation would have undefined behavior (UB), a defect occurs; platforms are encouraged to treat any such UB as a contract violation occurring.
How would that work? Compilers would have to detect UB, which is not always possible. To which the author pretty much says, “whatever, just make it work, like maybe have a little UB sanitiser limited to contract expressions”.
The paper specifically deals with number of expression evaluations being zero, one or more, depending on contract mode.
Reconsidering concepts in-place syntax
P2677R2 by Mike Spertus (Amazon). If only we had a proposal to simplify concepts syntax, which was rejected. No, can’t remember.
1[](auto:T && x) { return f(std::forward<T>(x)); }
Sender/Receiver Interface For Networking
P2762R0 by Dietmar Kühl (Bloomberg) is a noble endeavour to use Senders/Receivers to define a Networking architecture. It raises hopes of a standard networking solution based on the standard asynchrony patterns. I’m sure it’ll do just fine in the Committee.
Adding the new SI prefixes
P2734R0 by Marc Mutz adds new prefixes:
We propose to add the missing SI prefixes quecto (10^-30), ronto (10^−27), as well as ronna (10^27) and quetta (10^30) to the
<ratio>
header.
C xor C++ Programming
P2735R0 by Aaron Ballman (Intel):
It is not uncommon to hear about C/C++ programming as a shorthand for “C and C++” programming. This implies that C and C++ are similar, but distinct, programming languages with the obvious interpretation being that C++ is a proper superset of C. However, this does not accurately describe the situation.
This document enumerates instances where the same source code has different meaning when compiled with C and C++ implementations.
A very interesting paper that presents many differences between C and C++ that I didn’t know about, together with the appropriate Godbolt links.
Related: Modern C for C++ Peeps, HN.
Quote
Brian Kernighan:
Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.