Skip to content

Commit 7170c73

Browse files
committed
stats: fix UB in from_slice
1 parent 717b850 commit 7170c73

File tree

1 file changed

+44
-28
lines changed

1 file changed

+44
-28
lines changed

src/stats.rs

+44-28
Original file line numberDiff line numberDiff line change
@@ -93,40 +93,56 @@ fn value_histogram_index(size: u32) -> Option<usize> {
9393
}
9494
}
9595

96+
#[inline(always)]
97+
fn read_array<T, const N: usize, F>(cursor: &mut Cursor<&[u8]>, reader: F) -> [T; N]
98+
where
99+
F: Fn(&mut Cursor<&[u8]>) -> T,
100+
{
101+
// SAFETY:
102+
// https://doc.rust-lang.org/std/mem/union.MaybeUninit.html#initializing-an-array-element-by-element
103+
let mut data: [MaybeUninit<T>; N] = unsafe { MaybeUninit::uninit().assume_init() };
104+
for item in &mut data[..] {
105+
item.write(reader(cursor));
106+
}
107+
data.map(|x| unsafe { x.assume_init() })
108+
}
109+
96110
impl ColumnStats {
97-
#[allow(clippy::uninit_assumed_init)]
98111
pub fn from_slice(data: &[u8]) -> ColumnStats {
99112
let mut cursor = Cursor::new(data);
100-
let mut value_histogram: [AtomicU32; HISTOGRAM_BUCKETS] =
101-
unsafe { MaybeUninit::uninit().assume_init() };
102-
for item in value_histogram.iter_mut() {
103-
*item = read_u32(&mut cursor);
104-
}
105-
let mut query_histogram: [AtomicU64; SIZE_TIERS] =
106-
unsafe { MaybeUninit::uninit().assume_init() };
107-
for item in query_histogram.iter_mut() {
108-
*item = read_u64(&mut cursor);
109-
}
110-
let mut stats = ColumnStats {
113+
let cursor = &mut cursor;
114+
115+
let value_histogram = read_array(cursor, read_u32);
116+
let query_histogram = read_array(cursor, read_u64);
117+
let oversized = read_u64(cursor);
118+
let oversized_bytes = read_u64(cursor);
119+
let total_values = read_u64(cursor);
120+
let total_bytes = read_u64(cursor);
121+
let commits = read_u64(cursor);
122+
let inserted_new = read_u64(cursor);
123+
let inserted_overwrite = read_u64(cursor);
124+
let removed_hit = read_u64(cursor);
125+
let removed_miss = read_u64(cursor);
126+
let queries_miss = read_u64(cursor);
127+
let uncompressed_bytes = read_u64(cursor);
128+
let compression_delta = read_array(cursor, read_i64);
129+
130+
ColumnStats {
111131
value_histogram,
112132
query_histogram,
113-
oversized: read_u64(&mut cursor),
114-
oversized_bytes: read_u64(&mut cursor),
115-
total_values: read_u64(&mut cursor),
116-
total_bytes: read_u64(&mut cursor),
117-
commits: read_u64(&mut cursor),
118-
inserted_new: read_u64(&mut cursor),
119-
inserted_overwrite: read_u64(&mut cursor),
120-
removed_hit: read_u64(&mut cursor),
121-
removed_miss: read_u64(&mut cursor),
122-
queries_miss: read_u64(&mut cursor),
123-
uncompressed_bytes: read_u64(&mut cursor),
124-
compression_delta: unsafe { MaybeUninit::uninit().assume_init() },
125-
};
126-
for item in stats.compression_delta.iter_mut() {
127-
*item = read_i64(&mut cursor);
133+
oversized,
134+
oversized_bytes,
135+
total_values,
136+
total_bytes,
137+
commits,
138+
inserted_new,
139+
inserted_overwrite,
140+
removed_hit,
141+
removed_miss,
142+
queries_miss,
143+
uncompressed_bytes,
144+
compression_delta,
128145
}
129-
stats
130146
}
131147

132148
pub fn empty() -> ColumnStats {

0 commit comments

Comments
 (0)