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

Make accesses to fields of packed structs unsafe #44884

Merged
merged 10 commits into from
Nov 27, 2017
Merged

Conversation

arielb1
Copy link
Contributor

@arielb1 arielb1 commented Sep 27, 2017

To handle packed structs with destructors (which you'll think are a rare
case, but the #[repr(packed)] struct Packed<T>(T); pattern is
ever-popular, which requires handling packed structs with destructors to
avoid monomorphization-time errors), drops of subfields of packed
structs should drop a local move of the field instead of the original
one.

That's it, I think I'll use a strategy suggested by @Zoxc, where this mir

drop(packed_struct.field)

is replaced by

tmp0 = packed_struct.field;
drop tmp0

cc #27060 - this should deal with that issue after codegen of drop glue
is updated.

The new errors need to be changed to future-compatibility warnings, but
I'll rather do a crater run first with them as errors to assess the
impact.

cc @eddyb

Things which still need to be done for this:

  • - handle repr(packed) structs in derive the same way I did in Span, and use derive there again
  • - implement the "fix packed drops" pass and call it in both the MIR shim and validated MIR pipelines
  • - do a crater run
  • - convert the errors to compatibility warnings

@rust-highfive
Copy link
Collaborator

r? @pnkfelix

(rust_highfive has picked a reviewer for you, use r? to override)

@arielb1
Copy link
Contributor Author

arielb1 commented Sep 27, 2017

r? @eddyb

@rust-highfive rust-highfive assigned eddyb and unassigned pnkfelix Sep 27, 2017
@eddyb
Copy link
Member

eddyb commented Sep 27, 2017

LGTM. cc @rust-lang/compiler

@kennytm
Copy link
Member

kennytm commented Sep 27, 2017

CI failure is due to tendril.

The relevant #[repr(packed)] has been removed in servo/tendril@f9c672f. The latest version of tendril is 0.4.0, but we are currently using 0.3.1. #44785 does not include this update. We need to get kuchiki to update its dependencies.

Dependency tree:

  • tendril 0.3.1 (current: 0.4.0)
    • markup5ever 0.3.2 (current: 0.5.0)
      • html5ever 0.18.0 (current: 0.20.0)
        • kuchiki 0.5.1 (already latest current: 0.6.0)
          • html-diff 0.0.4 (already latest current: 0.0.5)
            • rustdoc 0.0.0
[00:34:19] error[E0133]: borrow of packed field requires unsafe function or block
[00:34:19]    --> /cargo/registry/src/github.com-1ecc6299db9ec823/tendril-0.3.1/src/tendril.rs:486:26
[00:34:19]     |
[00:34:19] 486 |         let kind = match self.ptr.get().get() {
[00:34:19]     |                          ^^^^^^^^ borrow of packed field
[00:34:19] 
[00:34:19] error[E0133]: borrow of packed field requires unsafe function or block
[00:34:19]    --> /cargo/registry/src/github.com-1ecc6299db9ec823/tendril-0.3.1/src/tendril.rs:562:15
[00:34:19]     |
[00:34:19] 562 |         match self.ptr.get().get() {
[00:34:19]     |               ^^^^^^^^ borrow of packed field
[00:34:19] 
[00:34:19] error[E0133]: borrow of packed field requires unsafe function or block
[00:34:19]    --> /cargo/registry/src/github.com-1ecc6299db9ec823/tendril-0.3.1/src/tendril.rs:572:17
[00:34:19]     |
[00:34:19] 572 |         let n = self.ptr.get().get();
[00:34:19]     |                 ^^^^^^^^ borrow of packed field
[00:34:19] 
[00:34:19] error[E0133]: borrow of packed field requires unsafe function or block
[00:34:19]    --> /cargo/registry/src/github.com-1ecc6299db9ec823/tendril-0.3.1/src/tendril.rs:580:17
[00:34:19]     |
[00:34:19] 580 |         let n = self.ptr.get().get();
[00:34:19]     |                 ^^^^^^^^ borrow of packed field
[00:34:19] 
[00:34:19] error[E0133]: borrow of packed field requires unsafe function or block
[00:34:19]    --> /cargo/registry/src/github.com-1ecc6299db9ec823/tendril-0.3.1/src/tendril.rs:582:39
[00:34:19]     |
[00:34:19] 582 |         (n > MAX_INLINE_TAG) && (n == other.ptr.get().get())
[00:34:19]     |                                       ^^^^^^^^^ borrow of packed field
[00:34:19] 
[00:34:19] error[E0133]: borrow of packed field requires unsafe function or block
[00:34:19]    --> /cargo/registry/src/github.com-1ecc6299db9ec823/tendril-0.3.1/src/tendril.rs:588:12
[00:34:19]     |
[00:34:19] 588 |         if self.ptr.get().get() <= MAX_INLINE_TAG {
[00:34:19]     |            ^^^^^^^^ borrow of packed field
[00:34:19] 
[00:34:19] error[E0133]: borrow of packed field requires unsafe function or block
[00:34:19]    --> /cargo/registry/src/github.com-1ecc6299db9ec823/tendril-0.3.1/src/tendril.rs:589:13
[00:34:19]     |
[00:34:19] 589 |             self.ptr.set(unsafe { NonZeroUsize::new(EMPTY_TAG) });
[00:34:19]     |             ^^^^^^^^ borrow of packed field
[00:34:19] 
[00:34:19] error: aborting due to 7 previous errors

@arielb1
Copy link
Contributor Author

arielb1 commented Sep 27, 2017

The error is correct - calling Cell::get on an unaligned Cell is absolutely UB.

@aidanhs aidanhs added the S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. label Sep 28, 2017
@pnkfelix
Copy link
Member

pnkfelix commented Oct 2, 2017

@arielb1 do you know if the now merged update to kuchiki mean we should re-do a travis run on this?

@arielb1 arielb1 force-pushed the pack-safe branch 2 times, most recently from 51e8c00 to 4ec62e4 Compare October 2, 2017 14:00
@arielb1 arielb1 added S-waiting-on-crater Status: Waiting on a crater run to be completed. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Oct 2, 2017
@arielb1
Copy link
Contributor Author

arielb1 commented Oct 2, 2017

Code is green. Can we have a crater run to see whether we break the world before I go make this a future-compat warning?

@arielb1
Copy link
Contributor Author

arielb1 commented Oct 2, 2017

@bors try

@bors
Copy link
Contributor

bors commented Oct 2, 2017

⌛ Trying commit 4ec62e4 with merge 618297e...

bors added a commit that referenced this pull request Oct 2, 2017
[WIP] make accesses to fields of packed structs unsafe

To handle packed structs with destructors (which you'll think are a rare
case, but the `#[repr(packed)] struct Packed<T>(T);` pattern is
ever-popular, which requires handling packed structs with destructors to
avoid monomorphization-time errors), drops of subfields of packed
structs should drop a local move of the field instead of the original
one.

That's it, I think I'll use a strategy suggested by @Zoxc, where this mir
```
drop(packed_struct.field)
```

is replaced by
```
tmp0 = packed_struct.field;
drop tmp0
```

cc #27060 - this should deal with that issue after codegen of drop glue
is updated.

The new errors need to be changed to future-compatibility warnings, but
I'll rather do a crater run first with them as errors to assess the
impact.

cc @eddyb

Things which still need to be done for this:
 - [ ] - handle `repr(packed)` structs in `derive` the same way I did in `Span`, and use derive there again
 - [ ] - implement the "fix packed drops" pass and call it in both the MIR shim and validated MIR pipelines
 - [ ] - do a crater run
 - [ ] - convert the errors to compatibility warnings
@bors
Copy link
Contributor

bors commented Oct 2, 2017

☀️ Test successful - status-travis
State: approved= try=True

@Mark-Simulacrum
Copy link
Member

Cargobomb run started.

@carols10cents
Copy link
Member

@Mark-Simulacrum has the cargobomb run completed on this?

@Mark-Simulacrum
Copy link
Member

@arielb1
Copy link
Contributor Author

arielb1 commented Oct 12, 2017

This appears to be quite a problem, we have 31 root regressions.

Summary:
basic_dsp_vector 0.5.2 - derive
cgmath 0.15.0 - derive
simd 0.2.0 - derive
tendril 0.2.4 - borrow, fixed
btrfs 1.2.2 - borrow, not on github
gjio 0.1.3 - borrow, deprecated
carp 0.1.0 - derive, no dependent crates, dead?
rust-extra 0.0.17 - borrow, badly unsound
elfloader 0.0.4 - borrow, needs {}
vek 0.1.0 - derive, needs copy
libpijul 0.8.2 - derive, need copy?
lm4f120 0.2.0 - borrow, needs to not be packed?
multiboot 0.3.0 - derive, needs more Copy?
multiboot2 0.3.2 - derive, no repo, needs more Copy?
orbclient 0.3.12 - borrow, needs {}
p0f_api 0.1.1 - borrow, needs {}
pe 0.1.1 - borrow, needs {} I think
pelite 0.4.0 - borrow, needs {}
persistent_hashmap 0.3.0 - derive, not sure how to fix
btrfs2 1.2.2 - borrow, not on github
rpcap 0.3.0 - borrow, needs to switch to Packed fields?
rux 0.1.0 - borrow, needs {}
sgx-isa 0.1.2 - borrow, needs to use by-value
simd-alt 0.2.0 - derive, like simd
tantivy 0.4.3 - borrow, needs extra packed annotations on datastructs
td_revent - borrow, needs {}
vec-2-10-10-10 - borrow, unsound public API
x86_64 0.1.2 - EntryOptions also needs to be packed because the compiler is stupid
zfs 0.1.0 - borrow, needs {}
lout (https://github.com/rrichardson/lout) - borrow, needs {}

@arielb1
Copy link
Contributor Author

arielb1 commented Oct 12, 2017

There are a few common types of regressions:

One easily-fixed case is println!("{}", packed.field);, which needs to be changed to println!("{}", {packed.field}); to avoid creating a direct reference to a packed field.

The other annoying one is derive on a non-Copy packed struct. The worst one is this from https://github.com/JoNil/persistent_hashmap/blob/master/src/lib.rs:

#[derive(Clone, Copy, Default)]
#[repr(C, packed)]
struct HashmapEntry<V> {
    // 1 bit occupied and 63 bit hash
    state: u64,
    value: V,
}

The Debug & Clone impls are currently UB, and I don't see a good way of fixing them except for either removing the packed or adding a V: Copy bound.

@arielb1
Copy link
Contributor Author

arielb1 commented Oct 12, 2017

I think the derive wrapper needs to be changed to add an attribute that warns if there's a non-Copy field, to avoid breaking half the world.

@bors
Copy link
Contributor

bors commented Oct 13, 2017

☔ The latest upstream changes (presumably #45013) made this pull request unmergeable. Please resolve the merge conflicts.

@kennytm kennytm added the S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. label Oct 13, 2017
@arielb1
Copy link
Contributor Author

arielb1 commented Nov 26, 2017

r? @eddyb - the last commit is new and non-trivial

@rust-highfive rust-highfive assigned eddyb and unassigned nikomatsakis Nov 26, 2017
@nrc nrc mentioned this pull request Nov 26, 2017
@nrc
Copy link
Member

nrc commented Nov 26, 2017

Rustfmt is fixed by #46144, I was waiting for this to land, but it looks like it is taking longer than expected. Since 46144 is ready to go and fixes the RLS which is currently broken, I want to land it sooner rather than later. Assuming it lands first (which it should) could you remove the 'mark rustfmt as broken' commit here since it shouldn't be needed.

@eddyb
Copy link
Member

eddyb commented Nov 27, 2017

@bors r=nikomatsakis,eddyb

@bors
Copy link
Contributor

bors commented Nov 27, 2017

📌 Commit f3b2d7f has been approved by nikomatsakis,eddyb

bors added a commit that referenced this pull request Nov 27, 2017
Make accesses to fields of packed structs unsafe

To handle packed structs with destructors (which you'll think are a rare
case, but the `#[repr(packed)] struct Packed<T>(T);` pattern is
ever-popular, which requires handling packed structs with destructors to
avoid monomorphization-time errors), drops of subfields of packed
structs should drop a local move of the field instead of the original
one.

That's it, I think I'll use a strategy suggested by @Zoxc, where this mir
```
drop(packed_struct.field)
```

is replaced by
```
tmp0 = packed_struct.field;
drop tmp0
```

cc #27060 - this should deal with that issue after codegen of drop glue
is updated.

The new errors need to be changed to future-compatibility warnings, but
I'll rather do a crater run first with them as errors to assess the
impact.

cc @eddyb

Things which still need to be done for this:
 - [ ] - handle `repr(packed)` structs in `derive` the same way I did in `Span`, and use derive there again
 - [ ] - implement the "fix packed drops" pass and call it in both the MIR shim and validated MIR pipelines
 - [ ] - do a crater run
 - [ ] - convert the errors to compatibility warnings
@bors
Copy link
Contributor

bors commented Nov 27, 2017

⌛ Testing commit f3b2d7f with merge 58e1234...

@bors
Copy link
Contributor

bors commented Nov 27, 2017

☀️ Test successful - status-appveyor, status-travis
Approved by: nikomatsakis,eddyb
Pushing 58e1234 to master...

@bors bors merged commit f3b2d7f into rust-lang:master Nov 27, 2017
@bluss bluss added the relnotes Marks issues that should be documented in the release notes of the next release. label Nov 27, 2017
arielb1 added a commit to arielb1/rust that referenced this pull request Nov 28, 2017
That commit had accidentally snuck in into rust-lang#44884. Revert it.

This reverts commit c48650e.
bors added a commit that referenced this pull request Nov 28, 2017
Revert "fix treatment of local types in "remote coherence" mode"

That commit had accidentally snuck in into #44884 and it causes regressions. Revert it.

This reverts commit c48650e.

@bors p=10 - fixes breakage in nightly
r? @eddyb
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
relnotes Marks issues that should be documented in the release notes of the next release. S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion.
Projects
None yet
Development

Successfully merging this pull request may close these issues.