-
Notifications
You must be signed in to change notification settings - Fork 13.1k
/
Copy pathcheck_packed_ref.rs
72 lines (65 loc) · 2.83 KB
/
check_packed_ref.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
use rustc_errors::struct_span_err;
use rustc_middle::mir::visit::{PlaceContext, Visitor};
use rustc_middle::mir::*;
use rustc_middle::ty::{self, TyCtxt};
use crate::util;
use crate::MirLint;
pub struct CheckPackedRef;
impl<'tcx> MirLint<'tcx> for CheckPackedRef {
fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
let param_env = tcx.param_env(body.source.def_id());
let source_info = SourceInfo::outermost(body.span);
let mut checker = PackedRefChecker { body, tcx, param_env, source_info };
checker.visit_body(&body);
}
}
struct PackedRefChecker<'a, 'tcx> {
body: &'a Body<'tcx>,
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
source_info: SourceInfo,
}
impl<'tcx> Visitor<'tcx> for PackedRefChecker<'_, 'tcx> {
fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
// Make sure we know where in the MIR we are.
self.source_info = terminator.source_info;
self.super_terminator(terminator, location);
}
fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
// Make sure we know where in the MIR we are.
self.source_info = statement.source_info;
self.super_statement(statement, location);
}
fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location: Location) {
if context.is_borrow() {
if util::is_disaligned(self.tcx, self.body, self.param_env, *place) {
let def_id = self.body.source.instance.def_id();
if let Some(impl_def_id) = self.tcx.impl_of_method(def_id)
&& self.tcx.is_builtin_derive(impl_def_id)
{
// If we ever reach here it means that the generated derive
// code is somehow doing an unaligned reference, which it
// shouldn't do.
unreachable!();
} else {
struct_span_err!(
self.tcx.sess,
self.source_info.span,
E0793,
"reference to packed field is unaligned"
)
.note(
"fields of packed structs are not properly aligned, and creating \
a misaligned reference is undefined behavior (even if that \
reference is never dereferenced)",
).help(
"copy the field contents to a local variable, or replace the \
reference with a raw pointer and use `read_unaligned`/`write_unaligned` \
(loads and stores via `*p` must be properly aligned even when using raw pointers)"
)
.emit();
}
}
}
}
}