Skip to content

Commit 990024f

Browse files
committed
crc-fast-rust: fixing the memory leak under software.rs I reintroduced.
1 parent 632486b commit 990024f

File tree

1 file changed

+199
-30
lines changed

1 file changed

+199
-30
lines changed

src/arch/software.rs

Lines changed: 199 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,45 @@ use crate::CrcParams;
99
use crc::Algorithm;
1010
use crc::Table;
1111

12+
// Caching for custom CRC algorithms to prevent repeated memory leaks
13+
#[cfg(feature = "alloc")]
14+
#[cfg(feature = "std")]
15+
use std::collections::HashMap;
16+
#[cfg(feature = "alloc")]
17+
#[cfg(feature = "std")]
18+
use std::sync::{Mutex, OnceLock};
19+
20+
#[cfg(feature = "alloc")]
21+
#[cfg(all(not(feature = "std"), feature = "cache"))]
22+
use hashbrown::HashMap;
23+
#[cfg(feature = "alloc")]
24+
#[cfg(all(not(feature = "std"), feature = "cache"))]
25+
use spin::{Mutex, Once};
26+
27+
// Cache key types for custom algorithms
28+
#[cfg(feature = "alloc")]
29+
type Crc32Key = (u32, u32, bool, bool, u32, u32);
30+
#[cfg(feature = "alloc")]
31+
type Crc64Key = (u64, u64, bool, bool, u64, u64);
32+
33+
// Global caches for custom algorithms (std version)
34+
#[cfg(feature = "alloc")]
35+
#[cfg(feature = "std")]
36+
static CUSTOM_CRC32_CACHE: OnceLock<Mutex<HashMap<Crc32Key, &'static Algorithm<u32>>>> =
37+
OnceLock::new();
38+
#[cfg(feature = "alloc")]
39+
#[cfg(feature = "std")]
40+
static CUSTOM_CRC64_CACHE: OnceLock<Mutex<HashMap<Crc64Key, &'static Algorithm<u64>>>> =
41+
OnceLock::new();
42+
43+
// Global caches for custom algorithms (no_std + cache version)
44+
#[cfg(feature = "alloc")]
45+
#[cfg(all(not(feature = "std"), feature = "cache"))]
46+
static CUSTOM_CRC32_CACHE: Once<Mutex<HashMap<Crc32Key, &'static Algorithm<u32>>>> = Once::new();
47+
#[cfg(feature = "alloc")]
48+
#[cfg(all(not(feature = "std"), feature = "cache"))]
49+
static CUSTOM_CRC64_CACHE: Once<Mutex<HashMap<Crc64Key, &'static Algorithm<u64>>>> = Once::new();
50+
1251
#[allow(unused)]
1352
const RUST_CRC32_AIXM: crc::Crc<u32, Table<16>> =
1453
crc::Crc::<u32, Table<16>>::new(&crc::CRC_32_AIXM);
@@ -104,21 +143,86 @@ pub(crate) fn update(state: u64, data: &[u8], params: CrcParams) -> u64 {
104143
extern crate alloc;
105144
use alloc::boxed::Box;
106145

107-
let algorithm: Algorithm<u32> = Algorithm {
108-
width: params.width,
109-
poly: params.poly as u32,
110-
init: params.init as u32,
111-
refin: params.refin,
112-
refout: params.refout,
113-
xorout: params.xorout as u32,
114-
check: params.check as u32,
115-
residue: 0x00000000, // unused in this context
116-
};
117-
118-
// ugly, but the crc crate is difficult to work with...
119-
let static_algorithm = Box::leak(Box::new(algorithm));
120-
121-
crc::Crc::<u32, Table<16>>::new(static_algorithm)
146+
// Use cache if std or cache feature is enabled
147+
#[cfg(any(feature = "std", feature = "cache"))]
148+
{
149+
let key: Crc32Key = (
150+
params.poly as u32,
151+
params.init as u32,
152+
params.refin,
153+
params.refout,
154+
params.xorout as u32,
155+
params.check as u32,
156+
);
157+
158+
#[cfg(feature = "std")]
159+
{
160+
let cache =
161+
CUSTOM_CRC32_CACHE.get_or_init(|| Mutex::new(HashMap::new()));
162+
let mut cache_guard = cache.lock().unwrap();
163+
164+
let static_algorithm =
165+
cache_guard.entry(key).or_insert_with(|| {
166+
let algorithm = Algorithm {
167+
width: params.width,
168+
poly: params.poly as u32,
169+
init: params.init as u32,
170+
refin: params.refin,
171+
refout: params.refout,
172+
xorout: params.xorout as u32,
173+
check: params.check as u32,
174+
residue: 0x00000000,
175+
};
176+
Box::leak(Box::new(algorithm))
177+
});
178+
179+
crc::Crc::<u32, Table<16>>::new(static_algorithm)
180+
}
181+
182+
#[cfg(all(not(feature = "std"), feature = "cache"))]
183+
{
184+
let cache =
185+
CUSTOM_CRC32_CACHE.call_once(|| Mutex::new(HashMap::new()));
186+
let mut cache_guard = cache.lock();
187+
188+
let static_algorithm =
189+
cache_guard.entry(key).or_insert_with(|| {
190+
let algorithm = Algorithm {
191+
width: params.width,
192+
poly: params.poly as u32,
193+
init: params.init as u32,
194+
refin: params.refin,
195+
refout: params.refout,
196+
xorout: params.xorout as u32,
197+
check: params.check as u32,
198+
residue: 0x00000000,
199+
};
200+
Box::leak(Box::new(algorithm))
201+
});
202+
203+
crc::Crc::<u32, Table<16>>::new(static_algorithm)
204+
}
205+
}
206+
207+
// Without cache, just leak (no_std without cache feature)
208+
#[cfg(not(any(feature = "std", feature = "cache")))]
209+
{
210+
let algorithm: Algorithm<u32> = Algorithm {
211+
width: params.width,
212+
poly: params.poly as u32,
213+
init: params.init as u32,
214+
refin: params.refin,
215+
refout: params.refout,
216+
xorout: params.xorout as u32,
217+
check: params.check as u32,
218+
residue: 0x00000000, // unused in this context
219+
};
220+
221+
// ugly, but the crc crate is difficult to work with...
222+
let static_algorithm = Box::leak(Box::new(algorithm));
223+
224+
crc::Crc::<u32, Table<16>>::new(static_algorithm)
225+
}
122226
}
123227
#[cfg(not(feature = "alloc"))]
124228
panic!("Custom CRC parameters require the 'alloc' feature")
@@ -142,21 +246,86 @@ pub(crate) fn update(state: u64, data: &[u8], params: CrcParams) -> u64 {
142246
extern crate alloc;
143247
use alloc::boxed::Box;
144248

145-
let algorithm: Algorithm<u64> = Algorithm {
146-
width: params.width,
147-
poly: params.poly,
148-
init: params.init,
149-
refin: params.refin,
150-
refout: params.refout,
151-
xorout: params.xorout,
152-
check: params.check,
153-
residue: 0x0000000000000000, // unused in this context
154-
};
155-
156-
// ugly, but the crc crate is difficult to work with...
157-
let static_algorithm = Box::leak(Box::new(algorithm));
158-
159-
crc::Crc::<u64, Table<16>>::new(static_algorithm)
249+
// Use cache if std or cache feature is enabled
250+
#[cfg(any(feature = "std", feature = "cache"))]
251+
{
252+
let key: Crc64Key = (
253+
params.poly,
254+
params.init,
255+
params.refin,
256+
params.refout,
257+
params.xorout,
258+
params.check,
259+
);
260+
261+
#[cfg(feature = "std")]
262+
{
263+
let cache =
264+
CUSTOM_CRC64_CACHE.get_or_init(|| Mutex::new(HashMap::new()));
265+
let mut cache_guard = cache.lock().unwrap();
266+
267+
let static_algorithm =
268+
cache_guard.entry(key).or_insert_with(|| {
269+
let algorithm = Algorithm {
270+
width: params.width,
271+
poly: params.poly,
272+
init: params.init,
273+
refin: params.refin,
274+
refout: params.refout,
275+
xorout: params.xorout,
276+
check: params.check,
277+
residue: 0x0000000000000000,
278+
};
279+
Box::leak(Box::new(algorithm))
280+
});
281+
282+
crc::Crc::<u64, Table<16>>::new(static_algorithm)
283+
}
284+
285+
#[cfg(all(not(feature = "std"), feature = "cache"))]
286+
{
287+
let cache =
288+
CUSTOM_CRC64_CACHE.call_once(|| Mutex::new(HashMap::new()));
289+
let mut cache_guard = cache.lock();
290+
291+
let static_algorithm =
292+
cache_guard.entry(key).or_insert_with(|| {
293+
let algorithm = Algorithm {
294+
width: params.width,
295+
poly: params.poly,
296+
init: params.init,
297+
refin: params.refin,
298+
refout: params.refout,
299+
xorout: params.xorout,
300+
check: params.check,
301+
residue: 0x0000000000000000,
302+
};
303+
Box::leak(Box::new(algorithm))
304+
});
305+
306+
crc::Crc::<u64, Table<16>>::new(static_algorithm)
307+
}
308+
}
309+
310+
// Without cache, just leak (no_std without cache feature)
311+
#[cfg(not(any(feature = "std", feature = "cache")))]
312+
{
313+
let algorithm: Algorithm<u64> = Algorithm {
314+
width: params.width,
315+
poly: params.poly,
316+
init: params.init,
317+
refin: params.refin,
318+
refout: params.refout,
319+
xorout: params.xorout,
320+
check: params.check,
321+
residue: 0x0000000000000000, // unused in this context
322+
};
323+
324+
// ugly, but the crc crate is difficult to work with...
325+
let static_algorithm = Box::leak(Box::new(algorithm));
326+
327+
crc::Crc::<u64, Table<16>>::new(static_algorithm)
328+
}
160329
}
161330
#[cfg(not(feature = "alloc"))]
162331
panic!("Custom CRC parameters require the 'alloc' feature")

0 commit comments

Comments
 (0)