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

check_expr_struct_fields: taint context with errors if struct definition is malformed #125947

Closed
wants to merge 5 commits into from

Conversation

olafes
Copy link
Contributor

@olafes olafes commented Jun 4, 2024

Make sure we don't create instances of structs with ambiguous layout in const/static context, as this can lead to ICE's. Fragment below is a reduced version of both #125842 and #124464. With this change, the body of static initializer is tainted and we don't evaluate it at compile-time.

struct Struct { 
    field: Option<u8>,
    field: u8,
}

static STATIC: Struct = Struct { 
    field: 1,
};

pub fn main() {}

fixes #125842, fixes #124464, fixes #124552

@rustbot
Copy link
Collaborator

rustbot commented Jun 4, 2024

Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @davidtwco (or someone else) some time within the next two weeks.

Please see the contribution instructions for more information. Namely, in order to ensure the minimum review times lag, PR authors and assigned reviewers should ensure that the review label (S-waiting-on-review and S-waiting-on-author) stays updated, invoking these commands when appropriate:

  • @rustbot author: the review is finished, PR author should check the comments and take action accordingly
  • @rustbot review: the author is ready for a review, this PR will be queued again in the reviewer's queue

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Jun 4, 2024
@rust-log-analyzer

This comment has been minimized.

let mut error_happened = if variant.fields.len() > remaining_fields.len() {
// Some field is defined more than once. Make sure we don't try to
// instantiate this struct in static/const context.
let guar = self.dcx().span_delayed_bug(expr.span, "struct fields have non-unique names");
Copy link
Member

Choose a reason for hiding this comment

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

No need to delay a bug here. Please taint the infcx below when we emit FieldMultiplySpecifiedInInitializer or report_unknown_field.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Here? I'm not sure this else branch is executed.

} else {
error_happened = true;
let guar = if let Some(prev_span) = seen_fields.get(&ident) {
tcx.dcx().emit_err(FieldMultiplySpecifiedInInitializer {
span: field.ident.span,
prev_span: *prev_span,
ident,
})
} else {
self.report_unknown_field(
adt_ty,
variant,
expr,
field,
hir_fields,
adt.variant_descr(),
)
};
Ty::new_error(tcx, guar)
};

Should I move my checking and tainting code to this line after the for loop?
}
// Make sure the programmer specified correct number of fields.

Copy link
Member

Choose a reason for hiding this comment

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

Actually, I guess I misread the issue. You probably want to do this instead on line 1874 where we call report_missing_fields?

Copy link
Contributor Author

@olafes olafes Jun 4, 2024

Choose a reason for hiding this comment

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

I think none of the checks in check_expr_struct_fields really catch what this ICE is about. remaining_fields is a map that has field names as keys and duplicated fields just get overwritten. If we try to compile code given as an example in this PR, at 1873 remaining_fields will be empty and this branch will not be taken as well.

} else if adt_kind != AdtKind::Union && !remaining_fields.is_empty() {
debug!(?remaining_fields);

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I could make remaining_fields distinguish between fields with the same name. I didn't feel confident in changing that much just to cover this, because error about struct definition is always there anyway.

@rust-log-analyzer

This comment has been minimized.

@olafes
Copy link
Contributor Author

olafes commented Jun 4, 2024

possibly related #123917

Copy link
Member

@compiler-errors compiler-errors left a comment

Choose a reason for hiding this comment

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

Ok, sorry, yeah, I understand what the issue here is. I do wonder if there is a better place to do this tainting -- like rustc_mir_build -- rather than tangling it up with typeck 🤔.

Please squash this into one commit and then I can approve.

Comment on lines 1675 to 1685
let mut error_happened = if variant.fields.len() > remaining_fields.len() {
// Some field is defined more than once. Make sure we don't try to
// instantiate this struct in static/const context.
let guar =
self.dcx().span_delayed_bug(expr.span, "struct fields have non-unique names");
self.set_tainted_by_errors(guar);

true
} else {
false
};
Copy link
Member

Choose a reason for hiding this comment

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

Can you split this up like so:

Suggested change
let mut error_happened = if variant.fields.len() > remaining_fields.len() {
// Some field is defined more than once. Make sure we don't try to
// instantiate this struct in static/const context.
let guar =
self.dcx().span_delayed_bug(expr.span, "struct fields have non-unique names");
self.set_tainted_by_errors(guar);
true
} else {
false
};
let mut error_happened = false;
if variant.fields.len() != remaining_fields.len() {
// Some field is defined more than once. Make sure we don't try to
// instantiate this struct in static/const context.
let guar =
self.dcx().span_delayed_bug(expr.span, "struct fields have non-unique names");
self.set_tainted_by_errors(guar);
error_happened = true;
}

@rustbot rustbot added has-merge-commits PR has merge commits, merge with caution. S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Jun 5, 2024
@rustbot
Copy link
Collaborator

rustbot commented Jun 5, 2024

There are merge commits (commits with multiple parents) in your changes. We have a no merge policy so these commits will need to be removed for this pull request to be merged.

You can start a rebase with the following commands:

$ # rebase
$ git pull --rebase https://github.com/rust-lang/rust.git master
$ git push --force-with-lease

The following commits are merge commits:

@rust-log-analyzer

This comment has been minimized.

@rustbot rustbot added A-testsuite Area: The testsuite used to check the correctness of rustc T-bootstrap Relevant to the bootstrap subteam: Rust's build system (x.py and src/bootstrap) labels Jun 5, 2024
@rustbot
Copy link
Collaborator

rustbot commented Jun 5, 2024

Some changes occurred in run-make tests.

cc @jieyouxu

The run-make-support library was changed

cc @jieyouxu

@rustbot rustbot removed has-merge-commits PR has merge commits, merge with caution. S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Jun 5, 2024
@olafes olafes closed this Jun 5, 2024
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this pull request Jun 5, 2024
check_expr_struct_fields: taint context with errors if struct definit…

Taint errors while checking `struct { field: 1 }` below if struct definition has duplicated fields so that we don't pass it to const eval.

fixes rust-lang#125842, fixes rust-lang#124464, fixes rust-lang#124552
```rust
struct Struct {
    field: Option<u8>,
    field: u8,
}

static STATIC: Struct = Struct {
    field: 1,
};

pub fn main() {}
```
(This was rust-lang#125947 but i messed something up, sorry)
r? `@compiler-errors`
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this pull request Jun 6, 2024
check_expr_struct_fields: taint context with errors if struct definit…

Taint errors while checking `struct { field: 1 }` below if struct definition has duplicated fields so that we don't pass it to const eval.

fixes rust-lang#125842, fixes rust-lang#124464, fixes rust-lang#124552
```rust
struct Struct {
    field: Option<u8>,
    field: u8,
}

static STATIC: Struct = Struct {
    field: 1,
};

pub fn main() {}
```
(This was rust-lang#125947 but i messed something up, sorry)
r? ``@compiler-errors``
rust-timer added a commit to rust-lang-ci/rust that referenced this pull request Jun 6, 2024
Rollup merge of rust-lang#126045 - olafes:master, r=compiler-errors

check_expr_struct_fields: taint context with errors if struct definit…

Taint errors while checking `struct { field: 1 }` below if struct definition has duplicated fields so that we don't pass it to const eval.

fixes rust-lang#125842, fixes rust-lang#124464, fixes rust-lang#124552
```rust
struct Struct {
    field: Option<u8>,
    field: u8,
}

static STATIC: Struct = Struct {
    field: 1,
};

pub fn main() {}
```
(This was rust-lang#125947 but i messed something up, sorry)
r? ``@compiler-errors``
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-testsuite Area: The testsuite used to check the correctness of rustc S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-bootstrap Relevant to the bootstrap subteam: Rust's build system (x.py and src/bootstrap) T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
6 participants