]>
Commit | Line | Data |
---|---|---|
9c376795 | 1 | use crate::lints::CStringPtr; |
29967ef6 XL |
2 | use crate::LateContext; |
3 | use crate::LateLintPass; | |
4 | use crate::LintContext; | |
353b0b11 | 5 | use rustc_hir::{Expr, ExprKind}; |
29967ef6 | 6 | use rustc_middle::ty; |
353b0b11 | 7 | use rustc_span::{symbol::sym, Span}; |
29967ef6 XL |
8 | |
9 | declare_lint! { | |
10 | /// The `temporary_cstring_as_ptr` lint detects getting the inner pointer of | |
11 | /// a temporary `CString`. | |
12 | /// | |
13 | /// ### Example | |
14 | /// | |
15 | /// ```rust | |
16 | /// # #![allow(unused)] | |
17 | /// # use std::ffi::CString; | |
18 | /// let c_str = CString::new("foo").unwrap().as_ptr(); | |
19 | /// ``` | |
20 | /// | |
21 | /// {{produces}} | |
22 | /// | |
23 | /// ### Explanation | |
24 | /// | |
25 | /// The inner pointer of a `CString` lives only as long as the `CString` it | |
26 | /// points to. Getting the inner pointer of a *temporary* `CString` allows the `CString` | |
27 | /// to be dropped at the end of the statement, as it is not being referenced as far as the typesystem | |
28 | /// is concerned. This means outside of the statement the pointer will point to freed memory, which | |
29 | /// causes undefined behavior if the pointer is later dereferenced. | |
30 | pub TEMPORARY_CSTRING_AS_PTR, | |
31 | Warn, | |
32 | "detects getting the inner pointer of a temporary `CString`" | |
33 | } | |
34 | ||
35 | declare_lint_pass!(TemporaryCStringAsPtr => [TEMPORARY_CSTRING_AS_PTR]); | |
36 | ||
29967ef6 XL |
37 | impl<'tcx> LateLintPass<'tcx> for TemporaryCStringAsPtr { |
38 | fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { | |
353b0b11 FG |
39 | if let ExprKind::MethodCall(as_ptr_path, as_ptr_receiver, ..) = expr.kind |
40 | && as_ptr_path.ident.name == sym::as_ptr | |
41 | && let ExprKind::MethodCall(unwrap_path, unwrap_receiver, ..) = as_ptr_receiver.kind | |
42 | && (unwrap_path.ident.name == sym::unwrap || unwrap_path.ident.name == sym::expect) | |
43 | { | |
44 | lint_cstring_as_ptr(cx, as_ptr_path.ident.span, unwrap_receiver, as_ptr_receiver); | |
29967ef6 XL |
45 | } |
46 | } | |
47 | } | |
48 | ||
49 | fn lint_cstring_as_ptr( | |
50 | cx: &LateContext<'_>, | |
51 | as_ptr_span: Span, | |
52 | source: &rustc_hir::Expr<'_>, | |
53 | unwrap: &rustc_hir::Expr<'_>, | |
54 | ) { | |
55 | let source_type = cx.typeck_results().expr_ty(source); | |
56 | if let ty::Adt(def, substs) = source_type.kind() { | |
5e7ed085 | 57 | if cx.tcx.is_diagnostic_item(sym::Result, def.did()) { |
29967ef6 | 58 | if let ty::Adt(adt, _) = substs.type_at(0).kind() { |
5e7ed085 | 59 | if cx.tcx.is_diagnostic_item(sym::cstring_type, adt.did()) { |
9c376795 | 60 | cx.emit_spanned_lint( |
2b03887a FG |
61 | TEMPORARY_CSTRING_AS_PTR, |
62 | as_ptr_span, | |
9c376795 | 63 | CStringPtr { as_ptr: as_ptr_span, unwrap: unwrap.span }, |
2b03887a | 64 | ); |
29967ef6 XL |
65 | } |
66 | } | |
67 | } | |
68 | } | |
69 | } |