Skip to content

Commit 6b5d4d9

Browse files
f0rkiMichael Rodler
andauthored
Enabled the use of clippy for the project. (#144)
* 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. Signed-off-by: Michael Rodler <[email protected]> Co-authored-by: Michael Rodler <[email protected]>
1 parent 9ef6d3e commit 6b5d4d9

File tree

10 files changed

+210
-75
lines changed

10 files changed

+210
-75
lines changed

.github/workflows/ci.yml

Lines changed: 33 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,13 @@ jobs:
158159
command: build
159160
args: --target aarch64-unknown-linux-gnu
160161

162+
clippy_check:
163+
runs-on: ubuntu-latest
164+
steps:
165+
- uses: actions/checkout@v3
166+
- name: Run clippy
167+
run: cargo clippy --all-targets --all-features
168+
161169
miri:
162170
name: Test with Miri
163171
runs-on: ubuntu-latest
@@ -176,6 +184,31 @@ jobs:
176184

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

180213
aarch64:
181214
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)