Skip to content

Commit 3c23206

Browse files
authored
Merge branch 'master' into mingxguo-fuzzing-mvp
2 parents 9493014 + 079c0a4 commit 3c23206

8 files changed

+537
-95
lines changed
+376
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,376 @@
1+
// Copyright 2019-2020 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
//! Helps manipulate bit fields in 32-bits words.
16+
// TODO(ia0): Remove when the module is used.
17+
#![cfg_attr(not(test), allow(dead_code, unused_macros))]
18+
19+
use crate::{StoreError, StoreResult};
20+
21+
/// Represents a bit field.
22+
///
23+
/// A bit field is a contiguous sequence of bits in a 32-bits word.
24+
///
25+
/// # Invariant
26+
///
27+
/// - The bit field must fit in a 32-bits word: `pos + len < 32`.
28+
pub struct Field {
29+
/// The position of the bit field.
30+
pub pos: usize,
31+
32+
/// The length of the bit field.
33+
pub len: usize,
34+
}
35+
36+
impl Field {
37+
/// Reads the value of a bit field.
38+
pub fn get(&self, word: u32) -> usize {
39+
((word >> self.pos) & self.mask()) as usize
40+
}
41+
42+
/// Sets the value of a bit field.
43+
///
44+
/// # Preconditions
45+
///
46+
/// - The value must fit in the bit field: `num_bits(value) < self.len`.
47+
/// - The value must only change bits from 1 to 0: `self.get(*word) & value == value`.
48+
pub fn set(&self, word: &mut u32, value: usize) {
49+
let value = value as u32;
50+
debug_assert_eq!(value & self.mask(), value);
51+
let mask = !(self.mask() << self.pos);
52+
*word &= mask | (value << self.pos);
53+
debug_assert_eq!(self.get(*word), value as usize);
54+
}
55+
56+
/// Returns a bit mask the length of the bit field.
57+
///
58+
/// The mask is meant to be applied on a value. It should be shifted to be applied to the bit
59+
/// field.
60+
fn mask(&self) -> u32 {
61+
(1 << self.len) - 1
62+
}
63+
}
64+
65+
/// Represents a constant bit field.
66+
///
67+
/// # Invariant
68+
///
69+
/// - The value must fit in the bit field: `num_bits(value) <= field.len`.
70+
pub struct ConstField {
71+
/// The bit field.
72+
pub field: Field,
73+
74+
/// The constant value.
75+
pub value: usize,
76+
}
77+
78+
impl ConstField {
79+
/// Checks that the bit field has its value.
80+
pub fn check(&self, word: u32) -> bool {
81+
self.field.get(word) == self.value
82+
}
83+
84+
/// Sets the bit field to its value.
85+
pub fn set(&self, word: &mut u32) {
86+
self.field.set(word, self.value);
87+
}
88+
}
89+
90+
/// Represents a single bit.
91+
///
92+
/// # Invariant
93+
///
94+
/// - The bit must fit in a 32-bits word: `pos < 32`.
95+
pub struct Bit {
96+
/// The position of the bit.
97+
pub pos: usize,
98+
}
99+
100+
impl Bit {
101+
/// Returns whether the value of the bit is zero.
102+
pub fn get(&self, word: u32) -> bool {
103+
word & (1 << self.pos) == 0
104+
}
105+
106+
/// Sets the value of the bit to zero.
107+
pub fn set(&self, word: &mut u32) {
108+
*word &= !(1 << self.pos);
109+
}
110+
}
111+
112+
/// Represents a checksum.
113+
///
114+
/// A checksum is a bit field counting how many bits are set to zero in the word (except in the
115+
/// checksum itself) plus some external increment. It essentially behaves like a bit field storing
116+
/// the external increment.
117+
pub struct Checksum {
118+
/// The bit field
119+
pub field: Field,
120+
}
121+
122+
impl Checksum {
123+
/// Reads the external increment from the checksum.
124+
///
125+
/// # Errors
126+
///
127+
/// Returns `InvalidStorage` if the external increment would be negative.
128+
pub fn get(&self, word: u32) -> StoreResult<usize> {
129+
let checksum = self.field.get(word);
130+
let zeros = word.count_zeros() as usize - (self.field.len - checksum.count_ones() as usize);
131+
checksum
132+
.checked_sub(zeros)
133+
.ok_or(StoreError::InvalidStorage)
134+
}
135+
136+
/// Sets the checksum to the external increment value.
137+
///
138+
/// # Preconditions
139+
///
140+
/// - The bits of the checksum bit field should be set to one: `self.field.get(*word) ==
141+
/// self.field.mask()`.
142+
/// - The checksum value should fit in the checksum bit field: `num_bits(word.count_zeros() +
143+
/// value) < self.field.len`.
144+
pub fn set(&self, word: &mut u32, value: usize) {
145+
debug_assert_eq!(self.field.get(*word), self.field.mask() as usize);
146+
self.field.set(word, word.count_zeros() as usize + value);
147+
}
148+
}
149+
150+
/// Tracks the number of bits used so far.
151+
///
152+
/// # Features
153+
///
154+
/// Only available for tests.
155+
#[cfg(any(doc, test))]
156+
pub struct Length {
157+
/// The position of the next available bit.
158+
pub pos: usize,
159+
}
160+
161+
/// Helps defining contiguous bit fields.
162+
///
163+
/// It takes a sequence of bit field descriptors as argument. A bit field descriptor is one of the
164+
/// following:
165+
/// - `$name: Bit,` to define a bit
166+
/// - `$name: Field <= $max,` to define a bit field of minimum length to store `$max`
167+
/// - `$name: Checksum <= $max,` to define a checksum of minimum length to store `$max`
168+
/// - `$name: Length,` to define a length tracker
169+
/// - `$name: ConstField = [$bits],` to define a constant bit field with value `$bits` (a sequence
170+
/// of space-separated bits)
171+
#[cfg_attr(doc, macro_export)] // For `cargo doc` to produce documentation.
172+
macro_rules! bitfield {
173+
($($input: tt)*) => {
174+
bitfield_impl! { []{ pos: 0 }[$($input)*] }
175+
};
176+
}
177+
178+
macro_rules! bitfield_impl {
179+
// Main rules:
180+
// - Input are bit field descriptors
181+
// - Position is the number of bits used by prior bit fields
182+
// - Output are the bit field definitions
183+
([$($output: tt)*]{ pos: $pos: expr }[$name: ident: Bit, $($input: tt)*]) => {
184+
bitfield_impl! {
185+
[$($output)* const $name: Bit = Bit { pos: $pos };]
186+
{ pos: $pos + 1 }
187+
[$($input)*]
188+
}
189+
};
190+
([$($output: tt)*]{ pos: $pos: expr }[$name: ident: Field <= $max: expr, $($input: tt)*]) => {
191+
bitfield_impl! {
192+
[$($output)* const $name: Field = Field { pos: $pos, len: num_bits($max) };]
193+
{ pos: $pos + $name.len }
194+
[$($input)*]
195+
}
196+
};
197+
([$($output: tt)*]{ pos: $pos: expr }
198+
[$name: ident: Checksum <= $max: expr, $($input: tt)*]) => {
199+
bitfield_impl! {
200+
[$($output)* const $name: Checksum = Checksum {
201+
field: Field { pos: $pos, len: num_bits($max) }
202+
};]
203+
{ pos: $pos + $name.field.len }
204+
[$($input)*]
205+
}
206+
};
207+
([$($output: tt)*]{ pos: $pos: expr }
208+
[$(#[$meta: meta])* $name: ident: Length, $($input: tt)*]) => {
209+
bitfield_impl! {
210+
[$($output)* $(#[$meta])* const $name: Length = Length { pos: $pos };]
211+
{ pos: $pos }
212+
[$($input)*]
213+
}
214+
};
215+
([$($output: tt)*]{ pos: $pos: expr }
216+
[$name: ident: ConstField = $bits: tt, $($input: tt)*]) => {
217+
bitfield_impl! {
218+
Reverse $name []$bits
219+
[$($output)*]{ pos: $pos }[$($input)*]
220+
}
221+
};
222+
([$($output: tt)*]{ pos: $pos: expr }[]) => { $($output)* };
223+
224+
// Auxiliary rules for constant bit fields:
225+
// - Input is a sequence of bits
226+
// - Output is the reversed sequence of bits
227+
(Reverse $name: ident [$($output_bits: tt)*] [$bit: tt $($input_bits: tt)*]
228+
[$($output: tt)*]{ pos: $pos: expr }[$($input: tt)*]) => {
229+
bitfield_impl! {
230+
Reverse $name [$bit $($output_bits)*][$($input_bits)*]
231+
[$($output)*]{ pos: $pos }[$($input)*]
232+
}
233+
};
234+
(Reverse $name: ident $bits: tt []
235+
[$($output: tt)*]{ pos: $pos: expr }[$($input: tt)*]) => {
236+
bitfield_impl! {
237+
ConstField $name { len: 0, val: 0 }$bits
238+
[$($output)*]{ pos: $pos }[$($input)*]
239+
}
240+
};
241+
242+
// Auxiliary rules for constant bit fields:
243+
// - Input is a sequence of bits in reversed order
244+
// - Output is the constant bit field definition with the sequence of bits as value
245+
(ConstField $name: ident { len: $len: expr, val: $val: expr }[]
246+
[$($output: tt)*]{ pos: $pos: expr }[$($input: tt)*]) => {
247+
bitfield_impl! {
248+
[$($output)* const $name: ConstField = ConstField {
249+
field: Field { pos: $pos, len: $len },
250+
value: $val,
251+
};]
252+
{ pos: $pos + $name.field.len }
253+
[$($input)*]
254+
}
255+
};
256+
(ConstField $name: ident { len: $len: expr, val: $val: expr }[$bit: tt $($bits: tt)*]
257+
[$($output: tt)*]{ pos: $pos: expr }[$($input: tt)*]) => {
258+
bitfield_impl! {
259+
ConstField $name { len: $len + 1, val: $val * 2 + $bit }[$($bits)*]
260+
[$($output)*]{ pos: $pos }[$($input)*]
261+
}
262+
};
263+
}
264+
265+
/// Counts the number of bits equal to zero in a byte slice.
266+
pub fn count_zeros(slice: &[u8]) -> usize {
267+
slice.iter().map(|&x| x.count_zeros() as usize).sum()
268+
}
269+
270+
/// Returns the number of bits necessary to represent a number.
271+
pub const fn num_bits(x: usize) -> usize {
272+
8 * core::mem::size_of::<usize>() - x.leading_zeros() as usize
273+
}
274+
275+
#[cfg(test)]
276+
mod tests {
277+
use super::*;
278+
279+
#[test]
280+
fn field_ok() {
281+
let field = Field { pos: 3, len: 5 };
282+
assert_eq!(field.get(0x00000000), 0);
283+
assert_eq!(field.get(0x00000007), 0);
284+
assert_eq!(field.get(0x00000008), 1);
285+
assert_eq!(field.get(0x000000f8), 0x1f);
286+
assert_eq!(field.get(0x0000ff37), 6);
287+
let mut word = 0xffffffff;
288+
field.set(&mut word, 3);
289+
assert_eq!(word, 0xffffff1f);
290+
}
291+
292+
#[test]
293+
fn const_field_ok() {
294+
let field = ConstField {
295+
field: Field { pos: 3, len: 5 },
296+
value: 9,
297+
};
298+
assert!(!field.check(0x00000000));
299+
assert!(!field.check(0x0000ffff));
300+
assert!(field.check(0x00000048));
301+
assert!(field.check(0x0000ff4f));
302+
let mut word = 0xffffffff;
303+
field.set(&mut word);
304+
assert_eq!(word, 0xffffff4f);
305+
}
306+
307+
#[test]
308+
fn bit_ok() {
309+
let bit = Bit { pos: 3 };
310+
assert!(bit.get(0x00000000));
311+
assert!(bit.get(0xfffffff7));
312+
assert!(!bit.get(0x00000008));
313+
assert!(!bit.get(0xffffffff));
314+
let mut word = 0xffffffff;
315+
bit.set(&mut word);
316+
assert_eq!(word, 0xfffffff7);
317+
}
318+
319+
#[test]
320+
fn checksum_ok() {
321+
let field = Checksum {
322+
field: Field { pos: 3, len: 5 },
323+
};
324+
assert_eq!(field.get(0x00000000), Err(StoreError::InvalidStorage));
325+
assert_eq!(field.get(0xffffffff), Ok(31));
326+
assert_eq!(field.get(0xffffff07), Ok(0));
327+
assert_eq!(field.get(0xffffff0f), Ok(1));
328+
assert_eq!(field.get(0x00ffff67), Ok(4));
329+
assert_eq!(field.get(0x7fffff07), Err(StoreError::InvalidStorage));
330+
let mut word = 0x0fffffff;
331+
field.set(&mut word, 4);
332+
assert_eq!(word, 0x0fffff47);
333+
}
334+
335+
#[test]
336+
fn bitfield_ok() {
337+
bitfield! {
338+
FIELD: Field <= 127,
339+
CONST_FIELD: ConstField = [0 1 0 1],
340+
BIT: Bit,
341+
CHECKSUM: Checksum <= 58,
342+
LENGTH: Length,
343+
}
344+
assert_eq!(FIELD.pos, 0);
345+
assert_eq!(FIELD.len, 7);
346+
assert_eq!(CONST_FIELD.field.pos, 7);
347+
assert_eq!(CONST_FIELD.field.len, 4);
348+
assert_eq!(CONST_FIELD.value, 10);
349+
assert_eq!(BIT.pos, 11);
350+
assert_eq!(CHECKSUM.field.pos, 12);
351+
assert_eq!(CHECKSUM.field.len, 6);
352+
assert_eq!(LENGTH.pos, 18);
353+
}
354+
355+
#[test]
356+
fn count_zeros_ok() {
357+
assert_eq!(count_zeros(&[0xff, 0xff]), 0);
358+
assert_eq!(count_zeros(&[0xff, 0xfe]), 1);
359+
assert_eq!(count_zeros(&[0x7f, 0xff]), 1);
360+
assert_eq!(count_zeros(&[0x12, 0x48]), 12);
361+
assert_eq!(count_zeros(&[0x00, 0x00]), 16);
362+
}
363+
364+
#[test]
365+
fn num_bits_ok() {
366+
assert_eq!(num_bits(0), 0);
367+
assert_eq!(num_bits(1), 1);
368+
assert_eq!(num_bits(2), 2);
369+
assert_eq!(num_bits(3), 2);
370+
assert_eq!(num_bits(4), 3);
371+
assert_eq!(num_bits(5), 3);
372+
assert_eq!(num_bits(8), 4);
373+
assert_eq!(num_bits(9), 4);
374+
assert_eq!(num_bits(16), 5);
375+
}
376+
}

libraries/persistent_store/src/lib.rs

+4
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@
1414

1515
#![cfg_attr(not(feature = "std"), no_std)]
1616

17+
#[macro_use]
18+
mod bitfield;
1719
mod storage;
20+
mod store;
1821

1922
pub use self::storage::{Storage, StorageError, StorageIndex, StorageResult};
23+
pub use self::store::{StoreError, StoreResult};

0 commit comments

Comments
 (0)