|
| 1 | +use super::TRANSMUTE_SLICE_TO_LARGER_ELEMENT_TYPE; |
| 2 | +use clippy_utils::diagnostics::span_lint_and_then; |
| 3 | +use clippy_utils::source::reindent_multiline; |
| 4 | +use clippy_utils::sugg; |
| 5 | +use clippy_utils::ty::approx_ty_size; |
| 6 | +use rustc_errors::Applicability; |
| 7 | +use rustc_hir::Expr; |
| 8 | +use rustc_lint::LateContext; |
| 9 | +use rustc_middle::ty::{self, Ty}; |
| 10 | +use std::borrow::Cow; |
| 11 | + |
| 12 | +// TODO: Adjust the parameters as necessary |
| 13 | +pub(super) fn check<'tcx>( |
| 14 | + cx: &LateContext<'tcx>, |
| 15 | + call_to_transmute: &'tcx Expr<'_>, |
| 16 | + from_ty: Ty<'tcx>, |
| 17 | + to_ty: Ty<'tcx>, |
| 18 | + transmute_arg: &'tcx Expr<'_>, |
| 19 | +) -> bool { |
| 20 | + if let (ty::Ref(_, ty_from, _), ty::Ref(_, ty_to, _)) = (&from_ty.kind(), &to_ty.kind()) { |
| 21 | + if let (&ty::Slice(ty_elem_from), &ty::Slice(ty_elem_to)) = (&ty_from.kind(), &ty_to.kind()) { |
| 22 | + let ty_eleme_from_size = approx_ty_size(cx, *ty_elem_from); |
| 23 | + let ty_elem_to_size = approx_ty_size(cx, *ty_elem_to); |
| 24 | + if ty_eleme_from_size < ty_elem_to_size { |
| 25 | + // this is UB!! |
| 26 | + span_lint_and_then( |
| 27 | + cx, |
| 28 | + TRANSMUTE_SLICE_TO_LARGER_ELEMENT_TYPE, |
| 29 | + call_to_transmute.span, |
| 30 | + &format!("transmute from `&[{ty_elem_from}]` to `&[{ty_elem_to}]` results in undefined behavior"), |
| 31 | + |diag| { |
| 32 | + let transmute_arg = sugg::Sugg::hir(cx, transmute_arg, ".."); |
| 33 | + // TODO: In this case, outer unsafe block is not needed anymore. It should be removed in |
| 34 | + // suggestion. |
| 35 | + let sugg_reallocate = format!( |
| 36 | + "{transmute_arg}\ |
| 37 | + .iter()\ |
| 38 | + .map(|item| unsafe {{ std::mem::transmute(item) }})\ |
| 39 | + .collect::<Vec<_>>()\ |
| 40 | + .to_slice()" |
| 41 | + ); |
| 42 | + let sugg_reallocate = Cow::from(sugg_reallocate); |
| 43 | + let sugg_align_to = format!("std::slice::align_to::<{ty_elem_to}>({transmute_arg}).1"); |
| 44 | + let sugg_align_to = Cow::from(sugg_align_to); |
| 45 | + diag.note("this transmute leads out-of-bounds read"); |
| 46 | + diag.span_suggestions( |
| 47 | + call_to_transmute.span, |
| 48 | + "try", |
| 49 | + [ |
| 50 | + reindent_multiline(sugg_reallocate, true, None).to_string(), |
| 51 | + // TODO: this suggestion does not check if there's prefix and postfix. |
| 52 | + // NOTE: this is not what user want to do if ty_elem_to is ZST; however, |
| 53 | + // this lint will not fire in such case anyway (ZSTs cannot be larger than any type). |
| 54 | + reindent_multiline(sugg_align_to, true, None).to_string(), |
| 55 | + ], |
| 56 | + Applicability::Unspecified, |
| 57 | + ); |
| 58 | + }, |
| 59 | + ); |
| 60 | + |
| 61 | + true |
| 62 | + } else { |
| 63 | + false |
| 64 | + } |
| 65 | + } else { |
| 66 | + false |
| 67 | + } |
| 68 | + } else { |
| 69 | + false |
| 70 | + } |
| 71 | +} |
0 commit comments