Skip to content

Commit c4e41dc

Browse files
committed
Updated P3390R0
1 parent 64f7a2a commit c4e41dc

File tree

4 files changed

+18
-12
lines changed

4 files changed

+18
-12
lines changed

docs/P3444R0.html

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -571,13 +571,13 @@ <h2 data-number="1.1" id="exclusivity"><span class="header-section-number">1.1</
571571
feature). There are other assumptions C++ programmers already make about
572572
the validity of inputs: for instance, references never hold null
573573
addresses. Non-valid inputs are implicated in undefined behavior.</p>
574-
<p>By the parsimony principal you may suggest “rather than adding a new
574+
<p>With a desire to simplify, you may suggest “rather than adding a new
575575
safe reference type, just enforce exclusivity on lvalue- and
576576
rvalue-references when compiled under the <code class="sourceCode cpp"><span class="op">[</span>safety<span class="op">]</span></code>
577577
feature.” But that makes the soundness problem worse. New code will
578578
<em>assume</em> legacy references don’t mutably alias, but existing code
579-
doesn’t uphold that invariant because it was written without even
580-
knowing about it.</p>
579+
doesn’t uphold that invariant because it was written without considering
580+
exclusivity.</p>
581581
<p>If safe code calls legacy code that returns a struct with a pair of
582582
references, do those references alias? Of course they may alias, but the
583583
parsimonious treatment claims that mutable references don’t alias under
@@ -1007,6 +1007,11 @@ <h1 data-number="4" id="achieving-first-class-references"><span class="header-se
10071007
mutex. This is a challenge for safe references, because safe reference
10081008
data members aren’t supported. Normally those would require lifetime
10091009
parameters on the containing class.</p>
1010+
<p>Robust support for user-defined types with reference data members
1011+
isn’t just a convenience in a safe C++ system. It’s a necessary part of
1012+
<em>interior mutability</em>, the core design pattern for implementing
1013+
shared ownership of mutable state (think safe versions of
1014+
<code class="sourceCode cpp">shared_ptr</code>).</p>
10101015
<p>What are some options for RAII reference semantics?</p>
10111016
<ul>
10121017
<li>Coroutines. This is the Hylo strategy. The ramp function locks a
@@ -1268,7 +1273,6 @@ <h1 data-number="5" id="lifetime-parameters"><span class="header-section-number"
12681273
interfacing the two languages. The easier it is to interoperate with
12691274
Rust, the more options and freedom companies have to fulfill with their
12701275
security mandate.<span class="citation" data-cites="rust-interop">[<a href="https://security.googleblog.com/2024/02/improving-interoperability-between-rust-and-c.html" role="doc-biblioref">rust-interop</a>]</span></p>
1271-
<p>An up-to-date draft of this document is maintained at <a href="https://www.safe-cpp.org/draft-lifetimes.html">safe-cpp.org/draft-lifetimes.html</a>.</p>
12721276
<h1 data-number="6" id="bibliography"><span class="header-section-number">6</span> References<a href="#bibliography" class="self-link"></a></h1>
12731277
<div id="refs" class="references csl-bib-body hanging-indent" data-entry-spacing="1" role="doc-bibliography">
12741278
<div id="ref-android" class="csl-entry" role="doc-biblioentry">
@@ -1301,7 +1305,7 @@ <h1 data-number="6" id="bibliography"><span class="header-section-number">6</spa
13011305
Design. <a href="https://blog.google/technology/safety-security/tackling-cybersecurity-vulnerabilities-through-secure-by-design/"><div class="csl-block">https://blog.google/technology/safety-security/tackling-cybersecurity-vulnerabilities-through-secure-by-design/</div></a>
13021306
</div>
13031307
<div id="ref-safecpp" class="csl-entry" role="doc-biblioentry">
1304-
[safecpp] Safe C++. <a href="https://safecpp.org/draft.html"><div class="csl-block">https://safecpp.org/draft.html</div></a>
1308+
[safecpp] P3390 – Safe C++. <a href="https://safecpp.org/draft.html"><div class="csl-block">https://safecpp.org/draft.html</div></a>
13051309
</div>
13061310
<div id="ref-second-class" class="csl-entry" role="doc-biblioentry">
13071311
[second-class] Second-Class References. <a href="https://borretti.me/article/second-class-references"><div class="csl-block">https://borretti.me/article/second-class-references</div></a>

docs/draft-lifetimes.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1300,7 +1300,7 @@ <h1 data-number="6" id="bibliography"><span class="header-section-number">6</spa
13001300
Design. <a href="https://blog.google/technology/safety-security/tackling-cybersecurity-vulnerabilities-through-secure-by-design/"><div class="csl-block">https://blog.google/technology/safety-security/tackling-cybersecurity-vulnerabilities-through-secure-by-design/</div></a>
13011301
</div>
13021302
<div id="ref-safecpp" class="csl-entry" role="doc-biblioentry">
1303-
[safecpp] Safe C++. <a href="https://safecpp.org/draft.html"><div class="csl-block">https://safecpp.org/draft.html</div></a>
1303+
[safecpp] P3390 – Safe C++. <a href="https://safecpp.org/draft.html"><div class="csl-block">https://safecpp.org/draft.html</div></a>
13041304
</div>
13051305
<div id="ref-second-class" class="csl-entry" role="doc-biblioentry">
13061306
[second-class] Second-Class References. <a href="https://borretti.me/article/second-class-references"><div class="csl-block">https://borretti.me/article/second-class-references</div></a>

lifetimes/P3444R0.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ Exclusivity is a program-wide invariant. It doesn't hinge on the safeness of a f
7676

7777
"Valid" borrow and safe reference inputs don't mutably alias. This is something a function can just _assume_; it doesn't need to check and there's no way to check. Borrow checking upholds exclusivity even for unsafe functions (when compiled under the `[safety]` feature). There are other assumptions C++ programmers already make about the validity of inputs: for instance, references never hold null addresses. Non-valid inputs are implicated in undefined behavior.
7878

79-
By the parsimony principal you may suggest "rather than adding a new safe reference type, just enforce exclusivity on lvalue- and rvalue-references when compiled under the `[safety]` feature." But that makes the soundness problem worse. New code will _assume_ legacy references don't mutably alias, but existing code doesn't uphold that invariant because it was written without even knowing about it.
79+
With a desire to simplify, you may suggest "rather than adding a new safe reference type, just enforce exclusivity on lvalue- and rvalue-references when compiled under the `[safety]` feature." But that makes the soundness problem worse. New code will _assume_ legacy references don't mutably alias, but existing code doesn't uphold that invariant because it was written without considering exclusivity.
8080

8181
If safe code calls legacy code that returns a struct with a pair of references, do those references alias? Of course they may alias, but the parsimonious treatment claims that mutable references don't alias under the `[safety]` feature. We've already stumbled on a soundness bug.
8282

@@ -388,6 +388,8 @@ The presented design is as far as I could go to address the goal of "memory safe
388388
389389
Let's consider RAII types with reference semantics. An example is `std::lock_guard`, which keeps a reference to a mutex. When the `lock_guard` goes out of scope its destructor calls `unlock` on the mutex. This is a challenge for safe references, because safe reference data members aren't supported. Normally those would require lifetime parameters on the containing class.
390390
391+
Robust support for user-defined types with reference data members isn't just a convenience in a safe C++ system. It's a necessary part of _interior mutability_, the core design pattern for implementing shared ownership of mutable state (think safe versions of `shared_ptr`).
392+
391393
What are some options for RAII reference semantics?
392394
393395
* Coroutines. This is the Hylo strategy. The ramp function locks a mutex and returns a safe reference to the data within. The continuation unlocks the mutex. The reference to the mutex is kept in the coroutine frame. But this still reduces to supporting structs with reference data members. In this case it's not a user-defined type, but a compiler-defined coroutine frame. I feel that the coroutine solution is an unidiomatic fit for C++ for several reasons: static allocation of the coroutine frame requires exposing the definition of the coroutine to the caller, which breaks C++'s approach to modularity; the continuation is called immediately after the last use of the yielded reference, which runs counter to expectation that cleanup runs at the end of the enclosing scope; and since the continuation is called implicitly, there's nothing textual on the caller side to indicate an unlock.
@@ -497,13 +499,11 @@ The US government and major players in tech including Google[@secure-by-design]
497499

498500
Finally, adoption of this feature brings a major benefit even if you personally want to get off C++: It's critical for **improving C++/Rust interop**. Your C++ project is generating revenue and there's scant economic incentive to rewrite it. But there is an incentive to pivot to a memory-safe language for new development, because new code is how vulnerabilities get introduced.[@android] Bringing C++ closer to Rust with the inclusion of _safe-specifier_, relocation, choice types, and, importantly, lifetime parameters, reduces the friction of interfacing the two languages. The easier it is to interoperate with Rust, the more options and freedom companies have to fulfill with their security mandate.[@rust-interop]
499501

500-
An up-to-date draft of this document is maintained at [safe-cpp.org/draft-lifetimes.html](https://www.safe-cpp.org/draft-lifetimes.html).
501-
502502
---
503503
references:
504504
- id: safecpp
505505
citation-label: safecpp
506-
title: Safe C++
506+
title: P3390 -- Safe C++
507507
URL: https://safecpp.org/draft.html
508508

509509
- id: second-class

lifetimes/draft-lifetimes.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ Exclusivity is a program-wide invariant. It doesn't hinge on the safeness of a f
7676

7777
"Valid" borrow and safe reference inputs don't mutably alias. This is something a function can just _assume_; it doesn't need to check and there's no way to check. Borrow checking upholds exclusivity even for unsafe functions (when compiled under the `[safety]` feature). There are other assumptions C++ programmers already make about the validity of inputs: for instance, references never hold null addresses. Non-valid inputs are implicated in undefined behavior.
7878

79-
By the parsimony principal you may suggest "rather than adding a new safe reference type, just enforce exclusivity on lvalue- and rvalue-references when compiled under the `[safety]` feature." But that makes the soundness problem worse. New code will _assume_ legacy references don't mutably alias, but existing code doesn't uphold that invariant because it was written without even knowing about it.
79+
With a desire to simplify, you may suggest "rather than adding a new safe reference type, just enforce exclusivity on lvalue- and rvalue-references when compiled under the `[safety]` feature." But that makes the soundness problem worse. New code will _assume_ legacy references don't mutably alias, but existing code doesn't uphold that invariant because it was written without considering exclusivity.
8080

8181
If safe code calls legacy code that returns a struct with a pair of references, do those references alias? Of course they may alias, but the parsimonious treatment claims that mutable references don't alias under the `[safety]` feature. We've already stumbled on a soundness bug.
8282

@@ -388,6 +388,8 @@ The presented design is as far as I could go to address the goal of "memory safe
388388
389389
Let's consider RAII types with reference semantics. An example is `std::lock_guard`, which keeps a reference to a mutex. When the `lock_guard` goes out of scope its destructor calls `unlock` on the mutex. This is a challenge for safe references, because safe reference data members aren't supported. Normally those would require lifetime parameters on the containing class.
390390
391+
Robust support for user-defined types with reference data members isn't just a convenience in a safe C++ system. It's a necessary part of _interior mutability_, the core design pattern for implementing shared ownership of mutable state (think safe versions of `shared_ptr`).
392+
391393
What are some options for RAII reference semantics?
392394
393395
* Coroutines. This is the Hylo strategy. The ramp function locks a mutex and returns a safe reference to the data within. The continuation unlocks the mutex. The reference to the mutex is kept in the coroutine frame. But this still reduces to supporting structs with reference data members. In this case it's not a user-defined type, but a compiler-defined coroutine frame. I feel that the coroutine solution is an unidiomatic fit for C++ for several reasons: static allocation of the coroutine frame requires exposing the definition of the coroutine to the caller, which breaks C++'s approach to modularity; the continuation is called immediately after the last use of the yielded reference, which runs counter to expectation that cleanup runs at the end of the enclosing scope; and since the continuation is called implicitly, there's nothing textual on the caller side to indicate an unlock.
@@ -501,7 +503,7 @@ Finally, adoption of this feature brings a major benefit even if you personally
501503
references:
502504
- id: safecpp
503505
citation-label: safecpp
504-
title: Safe C++
506+
title: P3390 -- Safe C++
505507
URL: https://safecpp.org/draft.html
506508

507509
- id: second-class

0 commit comments

Comments
 (0)