Skip to content

Commit e6717e8

Browse files
committed
Add repr_c_implicit_padding lint (off by default)
The `repr_c_implicit_padding` lint checks structures marked a u8 followed by a u64, which would require 7 bytes of padding to get the u64 aligned correctly. The reason for this is that in the BSD socket code, there is some shifty casting between structs which results in data being stored in padding bytes. Since the LLVM Load instruction does not copy padding, this can result in data loss. (This is also a problem in C, but since structs are rarely copied by value, instead using pointers and memcpy(), it is not as serious a problem.) We therefore need explicit padding for the socket structures, and this lint will make sure we get it. This is necessary because the recent pull rust-lang#16081 which is a fix for rust-lang#15763, changes the return value semantics to involve a Load. Without padding fixes, this breaks the Tcp code.
1 parent 51ff6c0 commit e6717e8

File tree

5 files changed

+49
-2
lines changed

5 files changed

+49
-2
lines changed

src/libnative/io/addrinfo.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ impl GetAddrInfoRequest {
4040
ai_addrlen: 0,
4141
ai_canonname: mut_null(),
4242
ai_addr: mut_null(),
43-
ai_next: mut_null()
43+
ai_next: mut_null(),
44+
__padding: [0, ..4]
4445
}
4546
});
4647

src/librustc/lint/builtin.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1536,6 +1536,9 @@ declare_lint!(pub UNKNOWN_CRATE_TYPE, Deny,
15361536
declare_lint!(pub VARIANT_SIZE_DIFFERENCE, Allow,
15371537
"detects enums with widely varying variant sizes")
15381538

1539+
declare_lint!(pub REPR_C_IMPLICIT_PADDING, Allow,
1540+
"detects implicit padding, which cannot be memset reliably, in C structures")
1541+
15391542
/// Does nothing as a lint pass, but registers some `Lint`s
15401543
/// which are used by other parts of the compiler.
15411544
pub struct HardwiredLints;
@@ -1554,7 +1557,8 @@ impl LintPass for HardwiredLints {
15541557
WARNINGS,
15551558
UNKNOWN_FEATURES,
15561559
UNKNOWN_CRATE_TYPE,
1557-
VARIANT_SIZE_DIFFERENCE
1560+
VARIANT_SIZE_DIFFERENCE,
1561+
REPR_C_IMPLICIT_PADDING
15581562
)
15591563
}
15601564
}

src/librustc/lint/context.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -638,6 +638,16 @@ impl LintPass for GatherNodeLevels {
638638
_ => { }
639639
}
640640
},
641+
ast::ItemStruct(..) => {
642+
let lint_id = LintId::of(builtin::REPR_C_IMPLICIT_PADDING);
643+
match cx.lints.get_level_source(lint_id) {
644+
lvlsrc @ (lvl, _) if lvl != Allow => {
645+
cx.node_levels.borrow_mut()
646+
.insert((it.id, lint_id), lvlsrc);
647+
},
648+
_ => { }
649+
}
650+
}
641651
_ => { }
642652
}
643653
}

src/librustc/middle/trans/base.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1908,6 +1908,29 @@ fn enum_variant_size_lint(ccx: &CrateContext, enum_def: &ast::EnumDef, sp: Span,
19081908
}
19091909
}
19101910

1911+
fn struct_repr_padding_lint(ccx: &CrateContext, struct_def: &ast::StructDef, id: ast::NodeId) {
1912+
let levels = ccx.tcx.node_lint_levels.borrow();
1913+
let lint_id = lint::LintId::of(lint::builtin::REPR_C_IMPLICIT_PADDING);
1914+
let lvlsrc = match levels.find(&(id, lint_id)) {
1915+
None | Some(&(lint::Allow, _)) => return,
1916+
Some(&lvlsrc) => lvlsrc,
1917+
};
1918+
1919+
let mut total_size = 0;
1920+
for field in struct_def.fields.iter() {
1921+
let align = llalign_of_min(ccx, sizing_type_of(ccx,
1922+
ty::node_id_to_type(&ccx.tcx, field.node.id)));
1923+
if total_size % align != 0 {
1924+
lint::raw_emit_lint(&ccx.tcx().sess, lint::builtin::REPR_C_IMPLICIT_PADDING,
1925+
lvlsrc, Some(field.span),
1926+
format!("field expects alignment of {} bytes, but is being \
1927+
inserted after {}", align, total_size).as_slice());
1928+
}
1929+
total_size += llsize_of_real(ccx, sizing_type_of(ccx,
1930+
ty::node_id_to_type(&ccx.tcx, field.node.id)));
1931+
}
1932+
}
1933+
19111934
pub struct TransItemVisitor<'a> {
19121935
pub ccx: &'a CrateContext,
19131936
}
@@ -1977,6 +2000,14 @@ pub fn trans_item(ccx: &CrateContext, item: &ast::Item) {
19772000
ast::ItemForeignMod(ref foreign_mod) => {
19782001
foreign::trans_foreign_mod(ccx, foreign_mod);
19792002
}
2003+
ast::ItemStruct(ref struct_definition, _) => {
2004+
// Only run the struct padding lint if we have #[repr(C)]
2005+
if item.attrs.iter().fold(attr::ReprAny, |acc, attr| {
2006+
attr::find_repr_attr(ccx.tcx.sess.diagnostic(), attr, acc)
2007+
}) == attr::ReprExtern {
2008+
struct_repr_padding_lint(ccx, &**struct_definition, item.id);
2009+
}
2010+
}
19802011
ast::ItemTrait(..) => {
19812012
// Inside of this trait definition, we won't be actually translating any
19822013
// functions, but the trait still needs to be walked. Otherwise default

src/librustuv/addrinfo.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ impl GetAddrInfoRequest {
6565
ai_canonname: mut_null(),
6666
ai_addr: mut_null(),
6767
ai_next: mut_null(),
68+
__padding: [0, ..4]
6869
}
6970
});
7071
let hint_ptr = hint.as_ref().map_or(null(), |x| {

0 commit comments

Comments
 (0)