Skip to content

Commit 9ef1e35

Browse files
committed
reject projecting to fields whose offset we cannot compute
1 parent b1613eb commit 9ef1e35

7 files changed

Lines changed: 85 additions & 75 deletions

File tree

‎compiler/rustc_codegen_ssa/src/mir/place.rs‎

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,8 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
9999
let offset = self.layout.fields.offset(ix);
100100
let effective_field_align = self.align.restrict_for_offset(offset);
101101

102+
// `simple` is called when we don't need to adjust the offset to
103+
// the dynamic alignment of the field.
102104
letmut simple = || {
103105
let llval = matchself.layout.abi{
104106
_ if offset.bytes() == 0 => {
@@ -141,28 +143,21 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
141143
};
142144

143145
// Simple cases, which don't need DST adjustment:
144-
// * no metadata available - just log the case
145-
// * known alignment - sized types, `[T]`, `str` or a foreign type
146+
// * known alignment - sized types, `[T]`, `str`
147+
// * offset 0 -- rounding up to alignment cannot change the offset
146148
// Note that looking at `field.align` is incorrect since that is not necessarily equal
147149
// to the dynamic alignment of the type.
148150
match field.ty.kind(){
149-
_ ifself.llextra.is_none() => {
150-
debug!(
151-
"unsized field `{}`, of `{:?}` has no metadata for adjustment",
152-
ix,self.llval
153-
);
154-
returnsimple();
155-
}
156151
_ if field.is_sized() => returnsimple(),
157-
ty::Slice(..) | ty::Str | ty::Foreign(..) => returnsimple(),
152+
ty::Slice(..) | ty::Str => returnsimple(),
153+
_ if offset.bytes() == 0 => returnsimple(),
158154
_ => {}
159155
}
160156

161157
// We need to get the pointer manually now.
162158
// We do this by casting to a `*i8`, then offsetting it by the appropriate amount.
163159
// We do this instead of, say, simply adjusting the pointer from the result of a GEP
164-
// because the field may have an arbitrary alignment in the LLVM representation
165-
// anyway.
160+
// because the field may have an arbitrary alignment in the LLVM representation.
166161
//
167162
// To demonstrate:
168163
//

‎compiler/rustc_const_eval/src/interpret/projection.rs‎

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -174,12 +174,15 @@ where
174174
};
175175
(base_meta, offset.align_to(align))
176176
}
177-
None => {
178-
// For unsized types with an extern type tail we perform no adjustments.
179-
// NOTE: keep this in sync with `PlaceRef::project_field` in the codegen backend.
180-
assert!(matches!(base_meta,MemPlaceMeta::None));
177+
Noneif offset == Size::ZERO => {
178+
// If the offset is 0, then rounding it up to alignment wouldn't change anything,
179+
// so we can do this even for types where we cannot determine the alignment.
181180
(base_meta, offset)
182181
}
182+
None => {
183+
// We don't know the alignment of this field, so we cannot adjust.
184+
throw_unsup_format!("`extern type` does not have a known offset")
185+
}
183186
}
184187
}else{
185188
// base_meta could be present; we might be accessing a sized field of an unsized
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Test that we can handle unsized types with an extern type tail part.
2+
// Regression test for issue #91827.
3+
4+
#![feature(extern_types)]
5+
6+
use std::ptr::addr_of;
7+
8+
extern"C"{
9+
typeOpaque;
10+
}
11+
12+
structNewtype(Opaque);
13+
14+
structS{
15+
i:i32,
16+
a:Opaque,
17+
}
18+
19+
constNEWTYPE:() = unsafe{
20+
// Projecting to the newtype works, because it is always at offset 0.
21+
let x:&Newtype = unsafe{&*(1usizeas*constNewtype)};
22+
let field = &x.0;
23+
};
24+
25+
constOFFSET:() = unsafe{
26+
// This needs to compute the field offset, but we don't know the type's alignment, so this fail.
27+
let x:&S = unsafe{&*(1usizeas*constS)};
28+
let field = &x.a;//~ERROR: evaluation of constant value failed
29+
//~| does not have a known offset
30+
};
31+
32+
fnmain(){}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
error[E0080]: evaluation of constant value failed
2+
--> $DIR/issue-91827-extern-types-field-offset.rs:28:17
3+
|
4+
LL | let field = &x.a;
5+
| ^^^^ `extern type` does not have a known offset
6+
7+
error: aborting due to 1 previous error
8+
9+
For more information about this error, try `rustc --explain E0080`.

‎tests/ui/consts/const-eval/issue-91827-extern-types.rs‎

Lines changed: 0 additions & 59 deletions
This file was deleted.
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// run-fail
2+
// check-run-results
3+
// normalize-stderr-test "panicking\.rs:\d+:\d+:" -> "panicking.rs:"
4+
#![feature(extern_types)]
5+
6+
extern"C"{
7+
typeOpaque;
8+
}
9+
10+
structNewtype(Opaque);
11+
12+
structS{
13+
i:i32,
14+
a:Opaque,
15+
}
16+
17+
fnmain(){
18+
// Projecting to the newtype works, because it is always at offset 0.
19+
let x:&Newtype = unsafe{&*(1usizeas*constNewtype)};
20+
let field = &x.0;
21+
22+
// This needs to compute the field offset, but we don't know the type's alignment,
23+
// so this panics.
24+
let x:&S = unsafe{&*(1usizeas*constS)};
25+
let field = &x.a;
26+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
thread 'main' panicked at library/core/src/panicking.rs:
2+
attempted to compute the size or alignment of extern type `Opaque`
3+
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
4+
thread caused non-unwinding panic. aborting.

0 commit comments

Comments
 (0)