Skip to content

Commit 0f6dae4

Browse files
committed
Auto merge of #148122 - saethlin:deny-deref-nullptr, r=petrochenkov
Make deref_nullptr deny by default instead of warn This lint was added 4 years ago in #83948 and I cannot find any discussion on that PR or its issue about whether it should be warn or deny by default. I think keeping this lint to warn was at one point in the past justifiable because of the old bindgen behavior of generating tests that do null pointer derefs. I've certainly heard that argument. I don't think it holds up now, so I think we should be more firm about code that is definitely UB. We merged #134424 which adds a runtime check for null pointer reads/writes, with very little fanfare. So now we know things like: This lint warns on 111 crates in crater, but 106 crates are encountering the runtime UB check. 65 crates hit both the lint and a runtime check. Of the 46 crates that only hit the lint, 25 look to me like machine-generated bindings, and all hits except https://github.com/Plecra/asm-w-ownership/blob/3a0eff4bd151d8a0ccc076d6b8dea0bbc051e8e8/src/main.rs#L454 are trying to compute a field offset, and should use `offset_of!`. Based on the contents of the crater runs for 1.91, I'd expect these crates to go from test-fail to build-fail as a result of this change: ``` gh/bernardjason/rust-invaders gh/Leinnan/doppler gh/Max-E/rust-gl-python-gtk gh/nslebruh/rust-opengl-glfw gh/nslebruh/rust_physics_gl_test gh/oraoto/php-stacktrace gh/playXE/jsrs gh/Plecra/asm-w-ownership gh/TateKennington/ROpenGL gh/WillFarris/voxel-game reg/ochre ``` Most of the crates where the lint fires already don't build for other reasons (note there are a lot of C bindings wrapper crates in the set).
2 parents 7934bbd + 4752322 commit 0f6dae4

File tree

7 files changed

+38
-25
lines changed

7 files changed

+38
-25
lines changed

compiler/rustc_lint/src/builtin.rs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2697,8 +2697,9 @@ declare_lint! {
26972697
///
26982698
/// ### Example
26992699
///
2700-
/// ```rust,no_run
2700+
/// ```rust,compile_fail
27012701
/// # #![allow(unused)]
2702+
/// # #![cfg_attr(bootstrap, deny(deref_nullptr))]
27022703
/// use std::ptr;
27032704
/// unsafe {
27042705
/// let x = &*ptr::null::<i32>();
@@ -2716,7 +2717,7 @@ declare_lint! {
27162717
///
27172718
/// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
27182719
pub DEREF_NULLPTR,
2719-
Warn,
2720+
Deny,
27202721
"detects when an null pointer is dereferenced"
27212722
}
27222723

@@ -2726,6 +2727,16 @@ impl<'tcx> LateLintPass<'tcx> for DerefNullPtr {
27262727
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &hir::Expr<'_>) {
27272728
/// test if expression is a null ptr
27282729
fn is_null_ptr(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
2730+
let pointer_ty = cx.typeck_results().expr_ty(expr);
2731+
let ty::RawPtr(pointee, _) = pointer_ty.kind() else {
2732+
return false;
2733+
};
2734+
if let Ok(layout) = cx.tcx.layout_of(cx.typing_env().as_query_input(*pointee)) {
2735+
if layout.layout.size() == rustc_abi::Size::ZERO {
2736+
return false;
2737+
}
2738+
}
2739+
27292740
match &expr.kind {
27302741
hir::ExprKind::Cast(expr, ty) => {
27312742
if let hir::TyKind::Ptr(_) = ty.kind {

tests/ui/lint/lint-deref-nullptr.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
// test the deref_nullptr lint
22

3-
#![deny(deref_nullptr)]
4-
53
use std::ptr;
64

75
struct Struct {
86
field: u8,
97
}
108

9+
#[derive(Clone, Copy)]
10+
struct Zst;
11+
1112
fn f() {
1213
unsafe {
1314
let a = 1;
@@ -32,6 +33,11 @@ fn f() {
3233
// ^^ OKAY
3334
let offset = ptr::addr_of!((*ptr::null::<Struct>()).field);
3435
//~^ ERROR dereferencing a null pointer
36+
37+
// Make sure the lint permits derefs of null pointers to ZSTs
38+
let ok: Zst = *ptr::null();
39+
let ok: Zst = *ptr::null_mut();
40+
let ok: Zst = *(0 as *const Zst);
3541
}
3642
}
3743

tests/ui/lint/lint-deref-nullptr.stderr

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,49 @@
11
error: dereferencing a null pointer
2-
--> $DIR/lint-deref-nullptr.rs:15:18
2+
--> $DIR/lint-deref-nullptr.rs:16:18
33
|
44
LL | let ub = *(0 as *const i32);
55
| ^^^^^^^^^^^^^^^^^^ this code causes undefined behavior when executed
66
|
7-
note: the lint level is defined here
8-
--> $DIR/lint-deref-nullptr.rs:3:9
9-
|
10-
LL | #![deny(deref_nullptr)]
11-
| ^^^^^^^^^^^^^
7+
= note: `#[deny(deref_nullptr)]` on by default
128

139
error: dereferencing a null pointer
14-
--> $DIR/lint-deref-nullptr.rs:17:18
10+
--> $DIR/lint-deref-nullptr.rs:18:18
1511
|
1612
LL | let ub = *ptr::null::<i32>();
1713
| ^^^^^^^^^^^^^^^^^^^ this code causes undefined behavior when executed
1814

1915
error: dereferencing a null pointer
20-
--> $DIR/lint-deref-nullptr.rs:19:18
16+
--> $DIR/lint-deref-nullptr.rs:20:18
2117
|
2218
LL | let ub = *ptr::null_mut::<i32>();
2319
| ^^^^^^^^^^^^^^^^^^^^^^^ this code causes undefined behavior when executed
2420

2521
error: dereferencing a null pointer
26-
--> $DIR/lint-deref-nullptr.rs:21:18
22+
--> $DIR/lint-deref-nullptr.rs:22:18
2723
|
2824
LL | let ub = *(ptr::null::<i16>() as *const i32);
2925
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this code causes undefined behavior when executed
3026

3127
error: dereferencing a null pointer
32-
--> $DIR/lint-deref-nullptr.rs:23:18
28+
--> $DIR/lint-deref-nullptr.rs:24:18
3329
|
3430
LL | let ub = *(ptr::null::<i16>() as *mut i32 as *mut usize as *const u8);
3531
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this code causes undefined behavior when executed
3632

3733
error: dereferencing a null pointer
38-
--> $DIR/lint-deref-nullptr.rs:25:19
34+
--> $DIR/lint-deref-nullptr.rs:26:19
3935
|
4036
LL | let ub = &*ptr::null::<i32>();
4137
| ^^^^^^^^^^^^^^^^^^^ this code causes undefined behavior when executed
4238

4339
error: dereferencing a null pointer
44-
--> $DIR/lint-deref-nullptr.rs:27:19
40+
--> $DIR/lint-deref-nullptr.rs:28:19
4541
|
4642
LL | let ub = &*ptr::null_mut::<i32>();
4743
| ^^^^^^^^^^^^^^^^^^^^^^^ this code causes undefined behavior when executed
4844

4945
error: dereferencing a null pointer
50-
--> $DIR/lint-deref-nullptr.rs:33:36
46+
--> $DIR/lint-deref-nullptr.rs:34:36
5147
|
5248
LL | let offset = ptr::addr_of!((*ptr::null::<Struct>()).field);
5349
| ^^^^^^^^^^^^^^^^^^^^^^^^ this code causes undefined behavior when executed

tests/ui/lint/lint-forbid-internal-unsafe.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,5 @@ macro_rules! evil {
1313

1414
fn main() {
1515
println!("{}", evil!(*(0 as *const u8)));
16-
//~^ WARNING dereferencing a null pointer
16+
//~^ ERROR dereferencing a null pointer
1717
}

tests/ui/lint/lint-forbid-internal-unsafe.stderr

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@ note: the lint level is defined here
1010
LL | #![forbid(unsafe_code)]
1111
| ^^^^^^^^^^^
1212

13-
warning: dereferencing a null pointer
13+
error: dereferencing a null pointer
1414
--> $DIR/lint-forbid-internal-unsafe.rs:15:26
1515
|
1616
LL | println!("{}", evil!(*(0 as *const u8)));
1717
| ^^^^^^^^^^^^^^^^^ this code causes undefined behavior when executed
1818
|
19-
= note: `#[warn(deref_nullptr)]` on by default
19+
= note: `#[deny(deref_nullptr)]` on by default
2020

21-
error: aborting due to 1 previous error; 1 warning emitted
21+
error: aborting due to 2 previous errors
2222

tests/ui/unreachable-code/unreachable-bool-read-7246.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use std::ptr;
55
pub unsafe fn g() {
66
return;
77
if *ptr::null() {}; //~ ERROR unreachable
8-
//~| WARNING dereferencing a null pointer
8+
//~| ERROR dereferencing a null pointer
99
}
1010

1111
pub fn main() {}

tests/ui/unreachable-code/unreachable-bool-read-7246.stderr

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,13 @@ note: the lint level is defined here
1212
LL | #![deny(unreachable_code)]
1313
| ^^^^^^^^^^^^^^^^
1414

15-
warning: dereferencing a null pointer
15+
error: dereferencing a null pointer
1616
--> $DIR/unreachable-bool-read-7246.rs:7:8
1717
|
1818
LL | if *ptr::null() {};
1919
| ^^^^^^^^^^^^ this code causes undefined behavior when executed
2020
|
21-
= note: `#[warn(deref_nullptr)]` on by default
21+
= note: `#[deny(deref_nullptr)]` on by default
2222

23-
error: aborting due to 1 previous error; 1 warning emitted
23+
error: aborting due to 2 previous errors
2424

0 commit comments

Comments
 (0)