Skip to content

Commit

Permalink
Merge pull request #272 from moka-rs/fix-overflow-in-freq-sketch
Browse files Browse the repository at this point in the history
Fix occasional panic in `FrequencySketch` in debug build
  • Loading branch information
tatsuya6502 authored May 28, 2023
2 parents feded14 + 34d9ec7 commit a0d3342
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 1 deletion.
33 changes: 33 additions & 0 deletions .github/workflows/Kani.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: Kani CI

on:
pull_request:
paths-ignore:
- '.devcontainer/**'
- '.gitpod.yml'
- '.vscode/**'
- CHANGELOG.md
- README.md
push:
paths-ignore:
- '.devcontainer/**'
- '.gitpod.yml'
- '.vscode/**'
- CHANGELOG.md
- README.md

jobs:
run-kani:
runs-on: ubuntu-20.04
steps:
- name: Checkout Moka
uses: actions/checkout@v3

- name: Show CPU into
run: |
nproc
lscpu
free -m
- name: Run Kani
uses: model-checking/kani-github-action@v0.28
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

## Version 0.11.1

### Fixed

- Fixed occasional panic in internal `FrequencySketch` in debug build.
([#272][gh-pull-0272])

### Added

- Added some example programs to the `examples` directory. ([#268][gh-pull-0268], by
Expand Down Expand Up @@ -655,6 +660,7 @@ The minimum supported Rust version (MSRV) is now 1.51.0 (2021-03-25).
[gh-issue-0034]: https://github.com/moka-rs/moka/issues/34/
[gh-issue-0031]: https://github.com/moka-rs/moka/issues/31/

[gh-pull-0272]: https://github.com/moka-rs/moka/pull/272/
[gh-pull-0268]: https://github.com/moka-rs/moka/pull/268/
[gh-pull-0259]: https://github.com/moka-rs/moka/pull/259/
[gh-pull-0251]: https://github.com/moka-rs/moka/pull/251/
Expand Down
72 changes: 71 additions & 1 deletion src/common/frequency_sketch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ impl FrequencySketch {
fn index_of(&self, hash: u64, depth: u8) -> usize {
let i = depth as usize;
let mut hash = hash.wrapping_add(SEED[i]).wrapping_mul(SEED[i]);
hash += hash >> 32;
hash = hash.wrapping_add(hash >> 32);
(hash & self.table_mask) as usize
}

Expand Down Expand Up @@ -328,3 +328,73 @@ mod tests {
}
}
}

// Verify that some properties hold such as no panic occurs on any possible inputs.
#[cfg(kani)]
mod kani {
use super::FrequencySketch;

const CAPACITIES: &[u32] = &[
0,
1,
1024,
1025,
2u32.pow(24),
2u32.pow(24) + 1,
2u32.pow(30),
2u32.pow(30) + 1,
u32::MAX,
];

#[kani::proof]
fn verify_ensure_capacity() {
// Check for arbitrary capacities.
let capacity = kani::any();
let mut sketch = FrequencySketch::default();
sketch.ensure_capacity(capacity);
}

#[kani::proof]
fn verify_frequency() {
// Check for some selected capacities.
for capacity in CAPACITIES {
let mut sketch = FrequencySketch::default();
sketch.ensure_capacity(*capacity);

// Check for arbitrary hashes.
let hash = kani::any();
let frequency = sketch.frequency(hash);
assert!(frequency <= 15);
}
}

#[kani::proof]
fn verify_increment() {
// Only check for small capacities. Because Kani Rust Verifier is a model
// checking tool, it will take much longer time (exponential) to check larger
// capacities here.
for capacity in &[0, 1, 128] {
let mut sketch = FrequencySketch::default();
sketch.ensure_capacity(*capacity);

// Check for arbitrary hashes.
let hash = kani::any();
sketch.increment(hash);
}
}

#[kani::proof]
fn verify_index_of() {
// Check for arbitrary capacities.
let capacity = kani::any();
let mut sketch = FrequencySketch::default();
sketch.ensure_capacity(capacity);

// Check for arbitrary hashes.
let hash = kani::any();
for i in 0..4 {
let index = sketch.index_of(hash, i);
assert!(index < sketch.table.len());
}
}
}

0 comments on commit a0d3342

Please sign in to comment.