1 mod crosspointer_transmute; 2 mod transmute_float_to_int; 3 mod transmute_int_to_bool; 4 mod transmute_int_to_char; 5 mod transmute_int_to_float; 6 mod transmute_num_to_bytes; 7 mod transmute_ptr_to_ptr; 8 mod transmute_ptr_to_ref; 9 mod transmute_ref_to_ref; 10 mod transmutes_expressible_as_ptr_casts; 11 mod unsound_collection_transmute; 12 mod useless_transmute; 13 mod utils; 14 mod wrong_transmute; 15 16 use clippy_utils::in_constant; 17 use if_chain::if_chain; 18 use rustc_hir::{Expr, ExprKind}; 19 use rustc_lint::{LateContext, LateLintPass}; 20 use rustc_session::{declare_lint_pass, declare_tool_lint}; 21 use rustc_span::symbol::sym; 22 23 declare_clippy_lint! { 24 /// ### What it does 25 /// Checks for transmutes that can't ever be correct on any 26 /// architecture. 27 /// 28 /// ### Why is this bad? 29 /// It's basically guaranteed to be undefined behaviour. 30 /// 31 /// ### Known problems 32 /// When accessing C, users might want to store pointer 33 /// sized objects in `extradata` arguments to save an allocation. 34 /// 35 /// ### Example 36 /// ```ignore 37 /// let ptr: *const T = core::intrinsics::transmute('x') 38 /// ``` 39 pub WRONG_TRANSMUTE, 40 correctness, 41 "transmutes that are confusing at best, undefined behaviour at worst and always useless" 42 } 43 44 // FIXME: Move this to `complexity` again, after #5343 is fixed 45 declare_clippy_lint! { 46 /// ### What it does 47 /// Checks for transmutes to the original type of the object 48 /// and transmutes that could be a cast. 49 /// 50 /// ### Why is this bad? 51 /// Readability. The code tricks people into thinking that 52 /// something complex is going on. 53 /// 54 /// ### Example 55 /// ```rust,ignore 56 /// core::intrinsics::transmute(t); // where the result type is the same as `t`'s 57 /// ``` 58 pub USELESS_TRANSMUTE, 59 nursery, 60 "transmutes that have the same to and from types or could be a cast/coercion" 61 } 62 63 // FIXME: Merge this lint with USELESS_TRANSMUTE once that is out of the nursery. 64 declare_clippy_lint! { 65 /// ### What it does 66 ///Checks for transmutes that could be a pointer cast. 67 /// 68 /// ### Why is this bad? 69 /// Readability. The code tricks people into thinking that 70 /// something complex is going on. 71 /// 72 /// ### Example 73 /// 74 /// ```rust 75 /// # let p: *const [i32] = &[]; 76 /// unsafe { std::mem::transmute::<*const [i32], *const [u16]>(p) }; 77 /// ``` 78 /// Use instead: 79 /// ```rust 80 /// # let p: *const [i32] = &[]; 81 /// p as *const [u16]; 82 /// ``` 83 pub TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS, 84 complexity, 85 "transmutes that could be a pointer cast" 86 } 87 88 declare_clippy_lint! { 89 /// ### What it does 90 /// Checks for transmutes between a type `T` and `*T`. 91 /// 92 /// ### Why is this bad? 93 /// It's easy to mistakenly transmute between a type and a 94 /// pointer to that type. 95 /// 96 /// ### Example 97 /// ```rust,ignore 98 /// core::intrinsics::transmute(t) // where the result type is the same as 99 /// // `*t` or `&t`'s 100 /// ``` 101 pub CROSSPOINTER_TRANSMUTE, 102 complexity, 103 "transmutes that have to or from types that are a pointer to the other" 104 } 105 106 declare_clippy_lint! { 107 /// ### What it does 108 /// Checks for transmutes from a pointer to a reference. 109 /// 110 /// ### Why is this bad? 111 /// This can always be rewritten with `&` and `*`. 112 /// 113 /// ### Known problems 114 /// - `mem::transmute` in statics and constants is stable from Rust 1.46.0, 115 /// while dereferencing raw pointer is not stable yet. 116 /// If you need to do this in those places, 117 /// you would have to use `transmute` instead. 118 /// 119 /// ### Example 120 /// ```rust,ignore 121 /// unsafe { 122 /// let _: &T = std::mem::transmute(p); // where p: *const T 123 /// } 124 /// 125 /// // can be written: 126 /// let _: &T = &*p; 127 /// ``` 128 pub TRANSMUTE_PTR_TO_REF, 129 complexity, 130 "transmutes from a pointer to a reference type" 131 } 132 133 declare_clippy_lint! { 134 /// ### What it does 135 /// Checks for transmutes from an integer to a `char`. 136 /// 137 /// ### Why is this bad? 138 /// Not every integer is a Unicode scalar value. 139 /// 140 /// ### Known problems 141 /// - [`from_u32`] which this lint suggests using is slower than `transmute` 142 /// as it needs to validate the input. 143 /// If you are certain that the input is always a valid Unicode scalar value, 144 /// use [`from_u32_unchecked`] which is as fast as `transmute` 145 /// but has a semantically meaningful name. 146 /// - You might want to handle `None` returned from [`from_u32`] instead of calling `unwrap`. 147 /// 148 /// [`from_u32`]: https://doc.rust-lang.org/std/char/fn.from_u32.html 149 /// [`from_u32_unchecked`]: https://doc.rust-lang.org/std/char/fn.from_u32_unchecked.html 150 /// 151 /// ### Example 152 /// ```rust 153 /// let x = 1_u32; 154 /// unsafe { 155 /// let _: char = std::mem::transmute(x); // where x: u32 156 /// } 157 /// 158 /// // should be: 159 /// let _ = std::char::from_u32(x).unwrap(); 160 /// ``` 161 pub TRANSMUTE_INT_TO_CHAR, 162 complexity, 163 "transmutes from an integer to a `char`" 164 } 165 166 declare_clippy_lint! { 167 /// ### What it does 168 /// Checks for transmutes from a `&[u8]` to a `&str`. 169 /// 170 /// ### Why is this bad? 171 /// Not every byte slice is a valid UTF-8 string. 172 /// 173 /// ### Known problems 174 /// - [`from_utf8`] which this lint suggests using is slower than `transmute` 175 /// as it needs to validate the input. 176 /// If you are certain that the input is always a valid UTF-8, 177 /// use [`from_utf8_unchecked`] which is as fast as `transmute` 178 /// but has a semantically meaningful name. 179 /// - You might want to handle errors returned from [`from_utf8`] instead of calling `unwrap`. 180 /// 181 /// [`from_utf8`]: https://doc.rust-lang.org/std/str/fn.from_utf8.html 182 /// [`from_utf8_unchecked`]: https://doc.rust-lang.org/std/str/fn.from_utf8_unchecked.html 183 /// 184 /// ### Example 185 /// ```rust 186 /// let b: &[u8] = &[1_u8, 2_u8]; 187 /// unsafe { 188 /// let _: &str = std::mem::transmute(b); // where b: &[u8] 189 /// } 190 /// 191 /// // should be: 192 /// let _ = std::str::from_utf8(b).unwrap(); 193 /// ``` 194 pub TRANSMUTE_BYTES_TO_STR, 195 complexity, 196 "transmutes from a `&[u8]` to a `&str`" 197 } 198 199 declare_clippy_lint! { 200 /// ### What it does 201 /// Checks for transmutes from an integer to a `bool`. 202 /// 203 /// ### Why is this bad? 204 /// This might result in an invalid in-memory representation of a `bool`. 205 /// 206 /// ### Example 207 /// ```rust 208 /// let x = 1_u8; 209 /// unsafe { 210 /// let _: bool = std::mem::transmute(x); // where x: u8 211 /// } 212 /// 213 /// // should be: 214 /// let _: bool = x != 0; 215 /// ``` 216 pub TRANSMUTE_INT_TO_BOOL, 217 complexity, 218 "transmutes from an integer to a `bool`" 219 } 220 221 declare_clippy_lint! { 222 /// ### What it does 223 /// Checks for transmutes from an integer to a float. 224 /// 225 /// ### Why is this bad? 226 /// Transmutes are dangerous and error-prone, whereas `from_bits` is intuitive 227 /// and safe. 228 /// 229 /// ### Example 230 /// ```rust 231 /// unsafe { 232 /// let _: f32 = std::mem::transmute(1_u32); // where x: u32 233 /// } 234 /// 235 /// // should be: 236 /// let _: f32 = f32::from_bits(1_u32); 237 /// ``` 238 pub TRANSMUTE_INT_TO_FLOAT, 239 complexity, 240 "transmutes from an integer to a float" 241 } 242 243 declare_clippy_lint! { 244 /// ### What it does 245 /// Checks for transmutes from a float to an integer. 246 /// 247 /// ### Why is this bad? 248 /// Transmutes are dangerous and error-prone, whereas `to_bits` is intuitive 249 /// and safe. 250 /// 251 /// ### Example 252 /// ```rust 253 /// unsafe { 254 /// let _: u32 = std::mem::transmute(1f32); 255 /// } 256 /// 257 /// // should be: 258 /// let _: u32 = 1f32.to_bits(); 259 /// ``` 260 pub TRANSMUTE_FLOAT_TO_INT, 261 complexity, 262 "transmutes from a float to an integer" 263 } 264 265 declare_clippy_lint! { 266 /// ### What it does 267 /// Checks for transmutes from a number to an array of `u8` 268 /// 269 /// ### Why this is bad? 270 /// Transmutes are dangerous and error-prone, whereas `to_ne_bytes` 271 /// is intuitive and safe. 272 /// 273 /// ### Example 274 /// ```rust 275 /// unsafe { 276 /// let x: [u8; 8] = std::mem::transmute(1i64); 277 /// } 278 /// 279 /// // should be 280 /// let x: [u8; 8] = 0i64.to_ne_bytes(); 281 /// ``` 282 pub TRANSMUTE_NUM_TO_BYTES, 283 complexity, 284 "transmutes from a number to an array of `u8`" 285 } 286 287 declare_clippy_lint! { 288 /// ### What it does 289 /// Checks for transmutes from a pointer to a pointer, or 290 /// from a reference to a reference. 291 /// 292 /// ### Why is this bad? 293 /// Transmutes are dangerous, and these can instead be 294 /// written as casts. 295 /// 296 /// ### Example 297 /// ```rust 298 /// let ptr = &1u32 as *const u32; 299 /// unsafe { 300 /// // pointer-to-pointer transmute 301 /// let _: *const f32 = std::mem::transmute(ptr); 302 /// // ref-ref transmute 303 /// let _: &f32 = std::mem::transmute(&1u32); 304 /// } 305 /// // These can be respectively written: 306 /// let _ = ptr as *const f32; 307 /// let _ = unsafe{ &*(&1u32 as *const u32 as *const f32) }; 308 /// ``` 309 pub TRANSMUTE_PTR_TO_PTR, 310 pedantic, 311 "transmutes from a pointer to a pointer / a reference to a reference" 312 } 313 314 declare_clippy_lint! { 315 /// ### What it does 316 /// Checks for transmutes between collections whose 317 /// types have different ABI, size or alignment. 318 /// 319 /// ### Why is this bad? 320 /// This is undefined behavior. 321 /// 322 /// ### Known problems 323 /// Currently, we cannot know whether a type is a 324 /// collection, so we just lint the ones that come with `std`. 325 /// 326 /// ### Example 327 /// ```rust 328 /// // different size, therefore likely out-of-bounds memory access 329 /// // You absolutely do not want this in your code! 330 /// unsafe { 331 /// std::mem::transmute::<_, Vec<u32>>(vec![2_u16]) 332 /// }; 333 /// ``` 334 /// 335 /// You must always iterate, map and collect the values: 336 /// 337 /// ```rust 338 /// vec![2_u16].into_iter().map(u32::from).collect::<Vec<_>>(); 339 /// ``` 340 pub UNSOUND_COLLECTION_TRANSMUTE, 341 correctness, 342 "transmute between collections of layout-incompatible types" 343 } 344 345 declare_lint_pass!(Transmute => [ 346 CROSSPOINTER_TRANSMUTE, 347 TRANSMUTE_PTR_TO_REF, 348 TRANSMUTE_PTR_TO_PTR, 349 USELESS_TRANSMUTE, 350 WRONG_TRANSMUTE, 351 TRANSMUTE_INT_TO_CHAR, 352 TRANSMUTE_BYTES_TO_STR, 353 TRANSMUTE_INT_TO_BOOL, 354 TRANSMUTE_INT_TO_FLOAT, 355 TRANSMUTE_FLOAT_TO_INT, 356 TRANSMUTE_NUM_TO_BYTES, 357 UNSOUND_COLLECTION_TRANSMUTE, 358 TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS, 359 ]); 360 361 impl<'tcx> LateLintPass<'tcx> for Transmute { 362 #[allow(clippy::similar_names, clippy::too_many_lines)] check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>)363 fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { 364 if_chain! { 365 if let ExprKind::Call(path_expr, args) = e.kind; 366 if let ExprKind::Path(ref qpath) = path_expr.kind; 367 if let Some(def_id) = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id(); 368 if cx.tcx.is_diagnostic_item(sym::transmute, def_id); 369 then { 370 // Avoid suggesting from/to bits and dereferencing raw pointers in const contexts. 371 // See https://github.com/rust-lang/rust/issues/73736 for progress on making them `const fn`. 372 // And see https://github.com/rust-lang/rust/issues/51911 for dereferencing raw pointers. 373 let const_context = in_constant(cx, e.hir_id); 374 375 let from_ty = cx.typeck_results().expr_ty(&args[0]); 376 let to_ty = cx.typeck_results().expr_ty(e); 377 378 // If useless_transmute is triggered, the other lints can be skipped. 379 if useless_transmute::check(cx, e, from_ty, to_ty, args) { 380 return; 381 } 382 383 let mut linted = wrong_transmute::check(cx, e, from_ty, to_ty); 384 linted |= crosspointer_transmute::check(cx, e, from_ty, to_ty); 385 linted |= transmute_ptr_to_ref::check(cx, e, from_ty, to_ty, args, qpath); 386 linted |= transmute_int_to_char::check(cx, e, from_ty, to_ty, args); 387 linted |= transmute_ref_to_ref::check(cx, e, from_ty, to_ty, args, const_context); 388 linted |= transmute_ptr_to_ptr::check(cx, e, from_ty, to_ty, args); 389 linted |= transmute_int_to_bool::check(cx, e, from_ty, to_ty, args); 390 linted |= transmute_int_to_float::check(cx, e, from_ty, to_ty, args, const_context); 391 linted |= transmute_float_to_int::check(cx, e, from_ty, to_ty, args, const_context); 392 linted |= transmute_num_to_bytes::check(cx, e, from_ty, to_ty, args, const_context); 393 linted |= unsound_collection_transmute::check(cx, e, from_ty, to_ty); 394 395 if !linted { 396 transmutes_expressible_as_ptr_casts::check(cx, e, from_ty, to_ty, args); 397 } 398 } 399 } 400 } 401 } 402