Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Continuation of #3054: enable spurious reads in TB #3067

Merged
merged 1 commit into from
Oct 6, 2023

Conversation

Vanille-N
Copy link
Contributor

@Vanille-N Vanille-N commented Sep 20, 2023

The last additions to the test suite of TB left some unresolved #[should_panic] that these new modifications solve.

Problem

Recall that the issues were arising from the interleavings that follow.

A. Reserved -> Frozen has visible effects after function exit

The transition Reserved -> Frozen irreversibly blocks write accesses to the tag, so in the interleaving below y initially Reserved becomes Frozen only in the target where a spurious read through x is inserted. This makes the later write through y UB only in the target and not in the source.

1: retag x (&, protect)
2: retag y (&mut, protect)
1: spurious read x
1: ret x
2: ret y
2: write y

B. Protectors only announce their presence on retag

There is a read-on-reborrow for protected locations, but if the retag of x occurs before that of y and there is no explicit access through x, then y is unaware of the existence of x. This is problematic because a spurious read inserted through x between the retag of y and the return of the function protecting x is a noalias violation in the target without UB in the source.

1: retag x (&, protect)
2: retag y (&mut, protect)
1: spurious read x
1: ret x
2: write y
2: ret y

Step 1: Finer behavior for Reserved

Since one problem is that Reserved -> Frozen has consequences beyond function exit, we decide to remove this transition entirely. To replace it we introduce a new subtype of Reserved with the extra boolean aliased set.
Reserved { aliased: true } forbids child accesses, but only temporarily: it has no effect on activation once the tag is no longer protected.
This makes the semantics of Tree Borrows slightly weaker in favor of being more similar to noalias.

This solves interleaving A., but B. is still a problem and the exhaustive tests do not pass yet.

Step 2: Read on function exit

Protected tags issue a "reminder" that they are protected until this instant inclusive, in the form of an implicit read (symmetrically to the implicit read on retag). This ensures that if the periods on which two tags x and y are protected overlap then no matter the interleaving of retags and returns, there is either a protector currently active or a read that has been emitted, both of which temporarily block activation.

This makes the exhaustive test designed previously pass, but it has an effect on the ability to return an activated pointer that I had not foreseen before implementing it.

Step 2': Do not propagate to children

A naive implementation of Step 2 makes the following code UB:

fn reborrow(x: &mut u8) -> &mut u8 {
    let y = &mut *x;
    *y = *y;
    y // callee returns `y: Active`...
}

let x = &mut 0u8;
let y = reborrow(x); // ... and caller receives `y: Frozen`
*y = 1; // UB

This is unacceptable, and a simple fix is to make this implicit read visible only to foreign tags.

We still lack hindsight on the ramifications of this decision, and the fact that the problematic pattern was only discovered because it occured in one completely unrelated test (with a cryptic error message) is worrying. We should be vigilant as to how this interacts with the rest of the model.

TODO

As of commit #281c30, the data race model has not been fully updated.
We have removed the reborrow of mutable references counting as a write access, but we still need the implicit read of function exit to count as a read.

src/borrow_tracker/mod.rs Outdated Show resolved Hide resolved
src/borrow_tracker/tree_borrows/diagnostics.rs Outdated Show resolved Hide resolved
src/machine.rs Outdated Show resolved Hide resolved
src/machine.rs Outdated Show resolved Hide resolved
src/borrow_tracker/tree_borrows/mod.rs Outdated Show resolved Hide resolved
tests/fail/tree_borrows/spurious_read.rs Outdated Show resolved Hide resolved
tests/fail/tree_borrows/spurious_read.rs Show resolved Hide resolved
tests/fail/tree_borrows/spurious_read.stderr Outdated Show resolved Hide resolved
tests/pass/tree_borrows/spurious_read.rs Show resolved Hide resolved
tests/pass/tree_borrows/tree-borrows.rs Outdated Show resolved Hide resolved
@RalfJung
Copy link
Member

@rustbot author

@rustbot rustbot added the S-waiting-on-author Status: Waiting for the PR author to address review comments label Sep 25, 2023
@Vanille-N
Copy link
Contributor Author

@rustbot ready

@rustbot rustbot added S-waiting-on-review Status: Waiting for a review to complete and removed S-waiting-on-author Status: Waiting for the PR author to address review comments labels Sep 26, 2023
src/borrow_tracker/tree_borrows/perms.rs Outdated Show resolved Hide resolved
src/borrow_tracker/tree_borrows/perms.rs Outdated Show resolved Hide resolved
src/borrow_tracker/tree_borrows/perms.rs Outdated Show resolved Hide resolved
tests/pass/tree_borrows/spurious_read.rs Outdated Show resolved Hide resolved
src/borrow_tracker/tree_borrows/perms.rs Outdated Show resolved Hide resolved
tests/fail/tree_borrows/spurious_read.rs Outdated Show resolved Hide resolved
src/borrow_tracker/tree_borrows/tree.rs Outdated Show resolved Hide resolved
src/borrow_tracker/tree_borrows/tree.rs Outdated Show resolved Hide resolved
@RalfJung
Copy link
Member

@rustbot author

@rustbot rustbot added S-waiting-on-author Status: Waiting for the PR author to address review comments and removed S-waiting-on-review Status: Waiting for a review to complete labels Sep 26, 2023
@Vanille-N
Copy link
Contributor Author

The fail test in the last commit is technically redundant since it's a subpattern of our spurious read test.
I added it because I think it's helpfull to diff it with the pass test to see the difference, but it shouldn't be required.

@Vanille-N
Copy link
Contributor Author

@rustbot ready

@rustbot rustbot added S-waiting-on-review Status: Waiting for a review to complete and removed S-waiting-on-author Status: Waiting for the PR author to address review comments labels Sep 30, 2023
@RalfJung
Copy link
Member

RalfJung commented Oct 5, 2023

@rustbot author

@rustbot rustbot added S-waiting-on-author Status: Waiting for the PR author to address review comments and removed S-waiting-on-review Status: Waiting for a review to complete labels Oct 5, 2023
Comment on lines 47 to 51
// which asserts that
// retag x
// read y
// write x
// is UB.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here it's not clear which operation happens in which thread.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In fact the comments in this file are not coherent... first it says

// read x     || retag y (&mut, protect)
//        -- sync --
//            || write y

but later it says

//      read y
//      retag x
//      write x

Is this mixing up x and y? Something doesn't check out.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops, I was planning to make the names consistent across read_retag_no_race and spurious_read
(x in thread 1, y in thread 2, x gets read, y gets written), but it looks like I started in and didn't finish the process.

@RalfJung
Copy link
Member

RalfJung commented Oct 6, 2023

Great, thanks. :)
Please rebase, fix the build, and squash.

Reserved loses permissions too quickly.
Adding more fine-grained behavior of Reserved lets it lose
write permissions only temporarily.
Protected tags receive a read access on initialized locations.
@Vanille-N Vanille-N force-pushed the spurious-incremental branch from 62feb30 to f95bcbb Compare October 6, 2023 12:46
@RalfJung
Copy link
Member

RalfJung commented Oct 6, 2023

Looking great!
@bors r+

@bors
Copy link
Contributor

bors commented Oct 6, 2023

📌 Commit f95bcbb has been approved by RalfJung

It is now in the queue for this repository.

@bors
Copy link
Contributor

bors commented Oct 6, 2023

⌛ Testing commit f95bcbb with merge 4e4426b...

@bors
Copy link
Contributor

bors commented Oct 6, 2023

☀️ Test successful - checks-actions
Approved by: RalfJung
Pushing 4e4426b to master...

@bors bors merged commit 4e4426b into rust-lang:master Oct 6, 2023
7 checks passed
bors added a commit that referenced this pull request Jul 4, 2024
…, r=RalfJung

TB: Refine protector end semantics

Tree Borrows has protector end tag semantics, namely that protectors ending cause a [special implicit read](https://perso.crans.org/vanille/treebor/diff.0.html) on all locations protected by that protector that have actually been accessed. See also #3067.

While this is enough for ensuring protectors allow adding/reordering reads, it does not prove that one can reorder writes. For this, we need to make this stronger, by making this implicit read be a write in cases when there was a write to the location protected by that protector, i.e. if the permission is `Active`.

There is a test that shows why this behavior is necessary, see `tests/fail/tree_borrows/protector-write-lazy.rs`.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-author Status: Waiting for the PR author to address review comments
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants