Skip to content

Commit 77c2d78

Browse files
bors[bot]cuviper
andauthored
Merge huonw#36
36: primal-sieve: Avoid UB use of `pointer::offset` r=cuviper a=cuviper We must not use `pointer::offset` when the result may be out of bounds. - In the `safe_assert!` checks, use `wrapping_offset`. We're comparing to both start and end pointers, so it can handle overflowing the end or even wrapping around less than start. - For other updates, use `wrapping_offset` and assign `end` if it did wrap, so further code only has to check it against the end pointer. Fixes huonw#35. I've also included a few minor updates and a release bump: - Use panic formatting in a test to avoid a deprecation - Release primal-sieve 0.3.2 - Migrate from criterion deprecations Co-authored-by: Josh Stone <cuviper@gmail.com>
2 parents 52a50d7 + 48389aa commit 77c2d78

File tree

10 files changed

+2337
-1414
lines changed

10 files changed

+2337
-1414
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ primal-sieve = { path = "primal-sieve", version = "0.3" }
2626

2727
[dev-dependencies]
2828
primal-slowsieve = { path = "primal-slowsieve", version = "0.3" }
29-
criterion = "0.3"
29+
criterion = { version = "0.3.4", features = ["html_reports"] }
3030

3131
[[bench]]
3232
name = "bench"

benches/bench.rs

Lines changed: 23 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,36 @@
11
#[macro_use]
22
extern crate criterion;
3-
use criterion::{Criterion, Fun};
3+
use criterion::Criterion;
44

55
const N: usize = 1_000_000;
66
const STEP: usize = 101;
77

88
fn is_prime(c: &mut Criterion) {
9-
let miller_rabin = Fun::new(
10-
"is_prime",
11-
|b, _| {
12-
b.iter(|| (1..N).step_by(STEP).filter(|&n| primal::is_prime(n as u64)).count())
13-
});
14-
let sieve = Fun::new(
15-
"Sieve::is_prime",
16-
|b, _| {
9+
let mut group = c.benchmark_group("is_prime");
10+
11+
group.bench_function("is_prime", |b| {
12+
b.iter(|| {
13+
(1..N)
14+
.step_by(STEP)
15+
.filter(|&n| primal::is_prime(n as u64))
16+
.count()
17+
})
18+
});
19+
20+
group.bench_function("Sieve::is_prime", |b| {
21+
let sieve = primal::Sieve::new(N);
22+
b.iter(|| (1..N).step_by(STEP).filter(|&n| sieve.is_prime(n)).count())
23+
});
24+
25+
group.bench_function("Sieve::is_prime with init", |b| {
26+
b.iter(|| {
1727
let sieve = primal::Sieve::new(N);
18-
b.iter(|| {
19-
(1..N).step_by(STEP)
20-
.filter(|&n| sieve.is_prime(n)).count()
21-
})
22-
});
23-
let sieve_with_init = Fun::new(
24-
"Sieve::is_prime with init",
25-
|b, _| {
26-
b.iter(|| {
27-
let sieve = primal::Sieve::new(N);
28-
(1..N).step_by(STEP)
29-
.filter(|&n| sieve.is_prime(n)).count()
30-
})
31-
});
28+
(1..N).step_by(STEP).filter(|&n| sieve.is_prime(n)).count()
29+
})
30+
});
3231

33-
c.bench_functions(
34-
"is_prime", vec![miller_rabin, sieve, sieve_with_init], ());
32+
group.finish();
3533
}
3634

3735
criterion_group!(benches, is_prime);
3836
criterion_main!(benches);
39-

generators/src/bin/wheel-generator.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -263,17 +263,21 @@ pub unsafe fn hardcoded_sieve(bytes: &mut [u8], si_: &mut usize, wi_: &mut usize
263263

264264
for info in cur_infos {
265265
println!("\
266-
{indent} safe_assert!(start <= p.offset(prime_ * {sl} + {off}) &&
267-
{indent} p.offset(prime_ * {sl} + {off}) < end);
266+
{indent} safe_assert!(start <= p.wrapping_offset(prime_ * {sl} + {off}) &&
267+
{indent} p.wrapping_offset(prime_ * {sl} + {off}) < end);
268268
{indent} *p.offset(prime_ * {sl} + {off}) &= {bit};",
269269
// p starts at offset 1 * prime_, so strip off
270270
// that factor.
271271
sl = info.total_mult_factor - 1,
272272
off = info.total_add_factor / wheel,
273273
bit = info.unset_bit, indent = indent);
274274
}
275+
// We can't use `p.offset(_)` here because this might go past `end`, which would be UB.
276+
// That's fine with `wrapping_offset` as long as it's not dereferenced, but we also need to
277+
// guard against the (unlikely) possibility of wrapping the entire address space.
275278
println!("
276-
{indent} p = p.offset(prime_ * {} + {})
279+
{indent} let p2 = p.wrapping_offset(prime_ * {} + {});
280+
{indent} p = if p <= p2 {{ p2 }} else {{ end }};
277281
{indent}}}",
278282
wheel, c,
279283
indent = indent);
@@ -288,7 +292,9 @@ pub unsafe fn hardcoded_sieve(bytes: &mut [u8], si_: &mut usize, wi_: &mut usize
288292
println!("\
289293
{indent} if p >= end {{ wi = {val}; break 'outer; }}
290294
{indent} safe_assert!(start <= p && p < end);
291-
{indent} *p &= {}; p = p.offset(prime_ * {} + {});
295+
{indent} *p &= {};
296+
{indent} let p2 = p.wrapping_offset(prime_ * {} + {});
297+
{indent} p = if p <= p2 {{ p2 }} else {{ end }};
292298
{indent} {}
293299
{indent}}}",
294300

primal-sieve/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "primal-sieve"
3-
version = "0.3.1"
3+
version = "0.3.2"
44
authors = ["Huon Wilson <dbau.pp@gmail.com>"]
55
edition = "2018"
66

@@ -22,7 +22,7 @@ smallvec = "1"
2222
[dev-dependencies]
2323
primal-slowsieve = { path = "../primal-slowsieve", version = "0.3" }
2424
primal = { path = "..", version = "0.3" }
25-
criterion = "0.3"
25+
criterion = { version = "0.3.4", features = ["html_reports"] }
2626

2727
[[bench]]
2828
name = "bench"

primal-sieve/benches/bench.rs

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,30 @@
11
#[macro_use]
22
extern crate criterion;
33

4-
use primal_sieve::{StreamingSieve, Sieve, Primes};
5-
use criterion::{Criterion, ParameterizedBenchmark};
4+
use criterion::{BenchmarkId, Criterion};
5+
use primal_sieve::{Primes, Sieve, StreamingSieve};
66

77
const SIZES: [usize; 5] = [100, 10_000, 100_000, 1_000_000, 10_000_000];
88

99
macro_rules! create_benchmarks {
1010
($(
1111
fn $group_id: ident($input: expr) {
12-
$first_name: expr => $first_func: expr,
13-
$($rest_name: expr => $rest_func: expr,)*
12+
$($name: expr => $func: expr,)*
1413
}
1514
)*) => {
1615
$(
1716
fn $group_id(c: &mut Criterion) {
1817
let input = $input;
18+
let mut group = c.benchmark_group(stringify!($group_id));
1919

20-
let bench = ParameterizedBenchmark::new(
21-
$first_name, $first_func, input.iter().copied())
22-
$( .with_function($rest_name, $rest_func) )*;
23-
c.bench(stringify!($group_id), bench);
20+
$(
21+
for i in &input {
22+
let id = BenchmarkId::new($name, i);
23+
group.bench_with_input(id, i, $func);
24+
}
25+
)*
26+
27+
group.finish();
2428
}
2529
)*
2630
}

primal-sieve/src/streaming/primes.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ mod tests {
220220
// will take too long, but we can cut it short by unwinding.
221221
Primes::all().fold((), |(), p| {
222222
if p > 123456789 {
223-
panic!(format!("{}", p));
223+
panic!("{}", p);
224224
}
225225
})
226226
}

0 commit comments

Comments
 (0)