Add suspicious_open_options lint.

Checks for the suspicious use of OpenOptions::create()
without an explicit OpenOptions::truncate().

create() alone will either create a new file or open an
existing file. If the file already exists, it will be
overwritten when written to, but the file will not be
truncated by default. If less data is written to the file
than it already contains, the remainder of the file will
remain unchanged, and the end of the file will contain old
data.
In most cases, one should either use `create_new` to ensure
the file is created from scratch, or ensure `truncate` is
called so that the truncation behaviour is explicit.
`truncate(true)` will ensure the file is entirely overwritten
with new data, whereas `truncate(false)` will explicitely
keep the default behavior.

```rust
use std::fs::OpenOptions;

OpenOptions::new().create(true).truncate(true);
```
This commit is contained in:
atwam 2023-10-04 13:56:18 +01:00
parent 692f53fe8f
commit 6c201db005
No known key found for this signature in database
9 changed files with 132 additions and 102 deletions

View file

@ -2,6 +2,7 @@ use std::fs::OpenOptions;
#[allow(unused_must_use)]
#[warn(clippy::nonsensical_open_options)]
#[warn(clippy::suspicious_open_options)]
fn main() {
OpenOptions::new().read(true).truncate(true).open("foo.txt");
//~^ ERROR: file opened with `truncate` and `read`
@ -19,4 +20,6 @@ fn main() {
//~^ ERROR: the method `append` is called more than once
OpenOptions::new().truncate(true).truncate(false).open("foo.txt");
//~^ ERROR: the method `truncate` is called more than once
OpenOptions::new().create(true).open("foo.txt");
//~^ ERROR: file opened with `create`, but `truncate` behavior not defined
}

View file

@ -1,5 +1,5 @@
error: file opened with `truncate` and `read`
--> $DIR/open_options.rs:6:5
--> $DIR/open_options.rs:7:5
|
LL | OpenOptions::new().read(true).truncate(true).open("foo.txt");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -8,40 +8,55 @@ LL | OpenOptions::new().read(true).truncate(true).open("foo.txt");
= help: to override `-D warnings` add `#[allow(clippy::nonsensical_open_options)]`
error: file opened with `append` and `truncate`
--> $DIR/open_options.rs:9:5
--> $DIR/open_options.rs:10:5
|
LL | OpenOptions::new().append(true).truncate(true).open("foo.txt");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: the method `read` is called more than once
--> $DIR/open_options.rs:12:5
--> $DIR/open_options.rs:13:5
|
LL | OpenOptions::new().read(true).read(false).open("foo.txt");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: the method `create` is called more than once
--> $DIR/open_options.rs:14:5
--> $DIR/open_options.rs:15:5
|
LL | OpenOptions::new().create(true).create(false).open("foo.txt");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: file opened with `create`, but `truncate` behavior not defined
--> $DIR/open_options.rs:15:5
|
LL | OpenOptions::new().create(true).create(false).open("foo.txt");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `-D clippy::suspicious-open-options` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::suspicious_open_options)]`
error: the method `write` is called more than once
--> $DIR/open_options.rs:16:5
--> $DIR/open_options.rs:17:5
|
LL | OpenOptions::new().write(true).write(false).open("foo.txt");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: the method `append` is called more than once
--> $DIR/open_options.rs:18:5
--> $DIR/open_options.rs:19:5
|
LL | OpenOptions::new().append(true).append(false).open("foo.txt");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: the method `truncate` is called more than once
--> $DIR/open_options.rs:20:5
--> $DIR/open_options.rs:21:5
|
LL | OpenOptions::new().truncate(true).truncate(false).open("foo.txt");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 7 previous errors
error: file opened with `create`, but `truncate` behavior not defined
--> $DIR/open_options.rs:23:5
|
LL | OpenOptions::new().create(true).open("foo.txt");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 9 previous errors

View file

@ -80,6 +80,7 @@ fn main() {
.write(true)
.read(true)
.create(true)
.truncate(true)
.open("foo.txt")
.unwrap();
@ -104,6 +105,7 @@ fn msrv_1_54() {
.write(true)
.read(true)
.create(true)
.truncate(true)
.open("foo.txt")
.unwrap();
@ -124,6 +126,7 @@ fn msrv_1_55() {
.write(true)
.read(true)
.create(true)
.truncate(true)
.open("foo.txt")
.unwrap();

View file

@ -80,6 +80,7 @@ fn main() {
.write(true)
.read(true)
.create(true)
.truncate(true)
.open("foo.txt")
.unwrap();
@ -104,6 +105,7 @@ fn msrv_1_54() {
.write(true)
.read(true)
.create(true)
.truncate(true)
.open("foo.txt")
.unwrap();
@ -124,6 +126,7 @@ fn msrv_1_55() {
.write(true)
.read(true)
.create(true)
.truncate(true)
.open("foo.txt")
.unwrap();

View file

@ -14,7 +14,7 @@ LL | t.seek(SeekFrom::Start(0));
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `rewind()`
error: used `seek` to go to the start of the stream
--> $DIR/seek_to_start_instead_of_rewind.rs:133:7
--> $DIR/seek_to_start_instead_of_rewind.rs:136:7
|
LL | f.seek(SeekFrom::Start(0));
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `rewind()`