Skip to content

Commit 4c5202a

Browse files
author
Michael Rodler
committed
Enabled the use of clippy for the project.
* Run clippy in CI - Require SAFETY documents in front of every unsafe block. - Set MSRV version in clippy.toml to avoid lints that break the MSRV * Several fixes to make clippy happy - Ran cargo clippy --fix - Added some clippy exceptions - Added many SAFETY comments to unsafe blocks * Tested MIRAI static analyzer to find "unintentional panics" - added some debug-build overflow checks to satsify MIRAI - Currently, installing MIRAI takes way too long in CI so it is disabled for now. Need to find a way to cache this.
1 parent 9ef6d3e commit 4c5202a

File tree

10 files changed

+213
-75
lines changed

10 files changed

+213
-75
lines changed

.github/workflows/ci.yml

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ jobs:
1818
- msrv_x64
1919
- msrv_aarch64
2020
- miri
21+
- clippy_check
2122
steps:
2223
- run: exit 0
2324

@@ -158,6 +159,16 @@ jobs:
158159
command: build
159160
args: --target aarch64-unknown-linux-gnu
160161

162+
clippy_check:
163+
runs-on: ubuntu-latest
164+
# Make sure CI fails on all warnings, including Clippy lints
165+
env:
166+
RUSTFLAGS: "-Dwarnings"
167+
steps:
168+
- uses: actions/checkout@v3
169+
- name: Run Clippy
170+
run: cargo clippy --all-targets --all-features
171+
161172
miri:
162173
name: Test with Miri
163174
runs-on: ubuntu-latest
@@ -176,6 +187,31 @@ jobs:
176187

177188
- name: Test
178189
run: MIRIFLAGS="-Zmiri-tag-raw-pointers -Zmiri-check-number-validity" cargo miri test
190+
#
191+
# mirai:
192+
# name: MIRAI static analysis
193+
# runs-on: ubuntu-latest
194+
#
195+
# steps:
196+
# - name: Checkout
197+
# uses: actions/checkout@v1
198+
#
199+
# - name: Install Rust
200+
# uses: actions-rs/toolchain@v1
201+
# with:
202+
# profile: minimal
203+
# toolchain: nightly-2023-05-09
204+
# components: clippy, rustfmt, rustc-dev, rust-src, rust-std, llvm-tools-preview
205+
# override: true
206+
#
207+
# - name: install mirai
208+
# run: cargo install --locked --git https://github.com/facebookexperimental/MIRAI/ mirai
209+
# env:
210+
# # MIRAI_FLAGS: --diag=(default|verify|library|paranoid)
211+
# MIRAI_FLAGS: --diag=default
212+
#
213+
# - name: cargo mirai
214+
# run: cargo mirai --lib
179215

180216
aarch64:
181217
name: Test aarch64 (neon)

benches/parse.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,9 +112,10 @@ fn header(c: &mut Criterion) {
112112
c.benchmark_group("header")
113113
.throughput(Throughput::Bytes(input.len() as u64))
114114
.bench_function(name, |b| b.iter(|| {
115-
black_box({
115+
{
116116
let _ = httparse::parse_headers(input, &mut headers).unwrap();
117-
});
117+
};
118+
black_box(());
118119
}));
119120
}
120121

build.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ fn main() {
66
// We check rustc version to enable features beyond MSRV, such as:
77
// - 1.59 => neon_intrinsics
88
let rustc = env::var_os("RUSTC").unwrap_or(OsString::from("rustc"));
9-
let output = Command::new(&rustc)
9+
let output = Command::new(rustc)
1010
.arg("--version")
1111
.output()
1212
.expect("failed to check 'rustc --version'")
@@ -105,7 +105,7 @@ impl Version {
105105
let s = s.trim_start_matches("rustc ");
106106

107107
let mut iter = s
108-
.split(".")
108+
.split('.')
109109
.take(3)
110110
.map(|s| match s.find(|c: char| !c.is_ascii_digit()) {
111111
Some(end) => &s[..end],

clippy.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
msrv = "1.36"

src/iter.rs

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use core::convert::TryFrom;
55
pub struct Bytes<'a> {
66
start: *const u8,
77
end: *const u8,
8+
/// INVARIANT: start <= cursor && cursor <= end
89
cursor: *const u8,
910
phantom: core::marker::PhantomData<&'a ()>,
1011
}
@@ -14,6 +15,7 @@ impl<'a> Bytes<'a> {
1415
#[inline]
1516
pub fn new(slice: &'a [u8]) -> Bytes<'a> {
1617
let start = slice.as_ptr();
18+
// SAFETY: obtain pointer to slice end; start points to slice start.
1719
let end = unsafe { start.add(slice.len()) };
1820
let cursor = start;
1921
Bytes {
@@ -32,7 +34,7 @@ impl<'a> Bytes<'a> {
3234
#[inline]
3335
pub fn peek(&self) -> Option<u8> {
3436
if self.cursor < self.end {
35-
// SAFETY: bounds checked
37+
// SAFETY: bounds checked
3638
Some(unsafe { *self.cursor })
3739
} else {
3840
None
@@ -41,9 +43,11 @@ impl<'a> Bytes<'a> {
4143

4244
#[inline]
4345
pub fn peek_ahead(&self, n: usize) -> Option<u8> {
46+
// SAFETY: obtain a potentially OOB pointer that is later compared against the `self.end`
47+
// pointer.
4448
let ptr = unsafe { self.cursor.add(n) };
4549
if ptr < self.end {
46-
// SAFETY: bounds checked
50+
// SAFETY: bounds checked pointer dereference is safe
4751
Some(unsafe { *ptr })
4852
} else {
4953
None
@@ -58,11 +62,21 @@ impl<'a> Bytes<'a> {
5862
self.as_ref().get(..n)?.try_into().ok()
5963
}
6064

65+
/// Advance by 1, equivalent to calling `advance(1)`.
66+
///
67+
/// # Safety
68+
///
69+
/// Caller must ensure that Bytes hasn't been advanced/bumped by more than [`Bytes::len()`].
6170
#[inline]
6271
pub unsafe fn bump(&mut self) {
6372
self.advance(1)
6473
}
6574

75+
/// Advance cursor by `n`
76+
///
77+
/// # Safety
78+
///
79+
/// Caller must ensure that Bytes hasn't been advanced/bumped by more than [`Bytes::len()`].
6680
#[inline]
6781
pub unsafe fn advance(&mut self, n: usize) {
6882
self.cursor = self.cursor.add(n);
@@ -74,15 +88,25 @@ impl<'a> Bytes<'a> {
7488
self.end as usize - self.cursor as usize
7589
}
7690

91+
#[inline]
92+
pub fn is_empty(&self) -> bool {
93+
self.len() == 0
94+
}
95+
7796
#[inline]
7897
pub fn slice(&mut self) -> &'a [u8] {
79-
// not moving position at all, so it's safe
98+
// SAFETY: not moving position at all, so it's safe
8099
let slice = unsafe { slice_from_ptr_range(self.start, self.cursor) };
81100
self.commit();
82101
slice
83102
}
84103

85104
// TODO: this is an anti-pattern, should be removed
105+
/// Deprecated. Do not use!
106+
/// # Safety
107+
///
108+
/// Caller must ensure that `skip` is at most the number of advances (i.e., `bytes.advance(3)`
109+
/// implies a skip of at most 3).
86110
#[inline]
87111
pub unsafe fn slice_skip(&mut self, skip: usize) -> &'a [u8] {
88112
debug_assert!(self.cursor.sub(skip) >= self.start);
@@ -96,6 +120,9 @@ impl<'a> Bytes<'a> {
96120
self.start = self.cursor
97121
}
98122

123+
/// # Safety
124+
///
125+
/// see [`Bytes::advance`] safety comment.
99126
#[inline]
100127
pub unsafe fn advance_and_commit(&mut self, n: usize) {
101128
self.advance(n);
@@ -117,6 +144,9 @@ impl<'a> Bytes<'a> {
117144
self.end
118145
}
119146

147+
/// # Safety
148+
///
149+
/// Must ensure invariant `bytes.start() <= ptr && ptr <= bytes.end()`.
120150
#[inline]
121151
pub unsafe fn set_cursor(&mut self, ptr: *const u8) {
122152
debug_assert!(ptr >= self.start);
@@ -128,10 +158,14 @@ impl<'a> Bytes<'a> {
128158
impl<'a> AsRef<[u8]> for Bytes<'a> {
129159
#[inline]
130160
fn as_ref(&self) -> &[u8] {
161+
// SAFETY: not moving position at all, so it's safe
131162
unsafe { slice_from_ptr_range(self.cursor, self.end) }
132163
}
133164
}
134165

166+
/// # Safety
167+
///
168+
/// Must ensure start and end point to the same memory object to uphold memory safety.
135169
#[inline]
136170
unsafe fn slice_from_ptr_range<'a>(start: *const u8, end: *const u8) -> &'a [u8] {
137171
debug_assert!(start <= end);
@@ -144,7 +178,7 @@ impl<'a> Iterator for Bytes<'a> {
144178
#[inline]
145179
fn next(&mut self) -> Option<u8> {
146180
if self.cursor < self.end {
147-
// SAFETY: bounds checked
181+
// SAFETY: bounds checked dereference
148182
unsafe {
149183
let b = *self.cursor;
150184
self.bump();

0 commit comments

Comments
 (0)