diff --git a/Cargo.lock b/Cargo.lock index 75cc76c..80cec8d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -205,7 +205,7 @@ dependencies = [ [[package]] name = "croaring-sys" -version = "4.5.1" +version = "4.6.1" dependencies = [ "cc", ] diff --git a/README.md b/README.md index a0679cc..d47e415 100644 --- a/README.md +++ b/README.md @@ -127,7 +127,7 @@ Current documentation is available at https://docs.rs/croaring/latest/croaring/ ## CRoaring Version -This crate uses [CRoaring version `4.5.1`](https://github.com/RoaringBitmap/CRoaring/releases/tag/v4.5.1). +This crate uses [CRoaring version `4.6.1`](https://github.com/RoaringBitmap/CRoaring/releases/tag/v4.6.1). The version of this crate does not necessarily match the version of CRoaring: the major version of the crate is only incremented when there are breaking changes in the Rust API: It is possible (and has happened) that breaking changes in the CRoaring C API do not necessitate a major version bump in this crate. diff --git a/croaring-sys/CRoaring/bindgen_bundled_version.rs b/croaring-sys/CRoaring/bindgen_bundled_version.rs index 93b44f2..b60bc89 100644 --- a/croaring-sys/CRoaring/bindgen_bundled_version.rs +++ b/croaring-sys/CRoaring/bindgen_bundled_version.rs @@ -1,8 +1,8 @@ /* automatically generated by rust-bindgen 0.72.1 */ -pub const ROARING_VERSION: &[u8; 6] = b"4.5.1\0"; +pub const ROARING_VERSION: &[u8; 6] = b"4.6.1\0"; pub const ROARING_VERSION_MAJOR: _bindgen_ty_1 = 4; -pub const ROARING_VERSION_MINOR: _bindgen_ty_1 = 5; +pub const ROARING_VERSION_MINOR: _bindgen_ty_1 = 6; pub const ROARING_VERSION_REVISION: _bindgen_ty_1 = 1; pub type _bindgen_ty_1 = ::core::ffi::c_uint; extern "C" { @@ -1005,6 +1005,13 @@ extern "C" { #[doc = " Returns a copy of a bitmap.\n The returned pointer may be NULL in case of errors."] pub fn roaring64_bitmap_copy(r: *const roaring64_bitmap_t) -> *mut roaring64_bitmap_t; } +extern "C" { + #[doc = " Copies a bitmap from src to dest. It is assumed that the pointer dest\n is to an already allocated bitmap. The content of the dest bitmap is\n freed/deleted.\n\n It might be preferable and simpler to call roaring64_bitmap_copy except\n that roaring64_bitmap_overwrite can save on memory allocations.\n"] + pub fn roaring64_bitmap_overwrite( + dest: *mut roaring64_bitmap_t, + src: *const roaring64_bitmap_t, + ); +} extern "C" { #[doc = " Creates a new bitmap of a pointer to N 64-bit integers."] pub fn roaring64_bitmap_of_ptr(n_args: usize, vals: *const u64) -> *mut roaring64_bitmap_t; @@ -1155,6 +1162,10 @@ extern "C" { #[doc = " Returns the largest value in the set, or 0 if empty."] pub fn roaring64_bitmap_maximum(r: *const roaring64_bitmap_t) -> u64; } +extern "C" { + #[doc = " Remove run-length encoding even when it is more space efficient.\n Return whether a change was applied."] + pub fn roaring64_bitmap_remove_run_compression(r: *mut roaring64_bitmap_t) -> bool; +} extern "C" { #[doc = " Returns true if the result has at least one run container."] pub fn roaring64_bitmap_run_optimize(r: *mut roaring64_bitmap_t) -> bool; @@ -1319,6 +1330,14 @@ extern "C" { #[doc = " In-place version of `roaring64_bitmap_flip_closed`. Compute the negation of\n the bitmap in the interval [min, max]. The number of negated values is `max -\n min + 1`. Areas outside the range are passed through unchanged."] pub fn roaring64_bitmap_flip_closed_inplace(r: *mut roaring64_bitmap_t, min: u64, max: u64); } +extern "C" { + #[doc = " Return a copy of the bitmap with all values shifted by offset.\n\n If `positive` is true, the shift is added, otherwise subtracted. Values that\n overflow or underflow uint64_t are dropped. The caller is responsible for\n freeing the returned bitmap."] + pub fn roaring64_bitmap_add_offset_signed( + r: *const roaring64_bitmap_t, + positive: bool, + offset: u64, + ) -> *mut roaring64_bitmap_t; +} extern "C" { #[doc = " How many bytes are required to serialize this bitmap.\n\n This is meant to be compatible with other languages:\n https://github.com/RoaringBitmap/RoaringFormatSpec#extension-for-64-bit-implementations"] pub fn roaring64_bitmap_portable_size_in_bytes(r: *const roaring64_bitmap_t) -> usize; diff --git a/croaring-sys/CRoaring/roaring.c b/croaring-sys/CRoaring/roaring.c index 811906a..abc1833 100644 --- a/croaring-sys/CRoaring/roaring.c +++ b/croaring-sys/CRoaring/roaring.c @@ -1,5 +1,5 @@ // !!! DO NOT EDIT - THIS IS AN AUTO-GENERATED FILE !!! -// Created by amalgamation.sh on 2025-12-30T22:56:55Z +// Created by amalgamation.sh on 2026-03-09T14:59:44Z /* * The CRoaring project is under a dual license (Apache/MIT). @@ -819,9 +819,8 @@ static const uint8_t shuffle_mask16[] = { * Optimized by D. Lemire on May 3rd 2013 */ CROARING_TARGET_AVX2 -int32_t intersect_vector16(const uint16_t *__restrict__ A, size_t s_a, - const uint16_t *__restrict__ B, size_t s_b, - uint16_t *C) { +int32_t intersect_vector16(const uint16_t *A, size_t s_a, const uint16_t *B, + size_t s_b, uint16_t *C) { size_t count = 0; size_t i_a = 0, i_b = 0; const int vectorlength = sizeof(__m128i) / sizeof(uint16_t); @@ -920,8 +919,8 @@ int array_container_to_uint32_array_vector16(void *vout, const uint16_t *array, return outpos; } -int32_t intersect_vector16_inplace(uint16_t *__restrict__ A, size_t s_a, - const uint16_t *__restrict__ B, size_t s_b) { +int32_t intersect_vector16_inplace(uint16_t *A, size_t s_a, const uint16_t *B, + size_t s_b) { size_t count = 0; size_t i_a = 0, i_b = 0; const int vectorlength = sizeof(__m128i) / sizeof(uint16_t); @@ -1015,10 +1014,8 @@ int32_t intersect_vector16_inplace(uint16_t *__restrict__ A, size_t s_a, CROARING_UNTARGET_AVX2 CROARING_TARGET_AVX2 -int32_t intersect_vector16_cardinality(const uint16_t *__restrict__ A, - size_t s_a, - const uint16_t *__restrict__ B, - size_t s_b) { +int32_t intersect_vector16_cardinality(const uint16_t *A, size_t s_a, + const uint16_t *B, size_t s_b) { size_t count = 0; size_t i_a = 0, i_b = 0; const int vectorlength = sizeof(__m128i) / sizeof(uint16_t); @@ -1091,9 +1088,8 @@ CROARING_TARGET_AVX2 // Warning: // This function may not be safe if A == C or B == C. ///////// -int32_t difference_vector16(const uint16_t *__restrict__ A, size_t s_a, - const uint16_t *__restrict__ B, size_t s_b, - uint16_t *C) { +int32_t difference_vector16(const uint16_t *A, size_t s_a, const uint16_t *B, + size_t s_b, uint16_t *C) { // we handle the degenerate case if (s_a == 0) return 0; if (s_b == 0) { @@ -2090,9 +2086,9 @@ static int uint16_compare(const void *a, const void *b) { CROARING_TARGET_AVX2 // a one-pass SSE union algorithm // This function may not be safe if array1 == output or array2 == output. -uint32_t union_vector16(const uint16_t *__restrict__ array1, uint32_t length1, - const uint16_t *__restrict__ array2, uint32_t length2, - uint16_t *__restrict__ output) { +uint32_t union_vector16(const uint16_t *array1, uint32_t length1, + const uint16_t *array2, uint32_t length2, + uint16_t *output) { if ((length1 < 8) || (length2 < 8)) { return (uint32_t)union_uint16(array1, length1, array2, length2, output); } @@ -2214,9 +2210,9 @@ static inline uint32_t unique_xor(uint16_t *out, uint32_t len) { } CROARING_TARGET_AVX2 // a one-pass SSE xor algorithm -uint32_t xor_vector16(const uint16_t *__restrict__ array1, uint32_t length1, - const uint16_t *__restrict__ array2, uint32_t length2, - uint16_t *__restrict__ output) { +uint32_t xor_vector16(const uint16_t *array1, uint32_t length1, + const uint16_t *array2, uint32_t length2, + uint16_t *output) { if ((length1 < 8) || (length2 < 8)) { return xor_uint16(array1, length1, array2, length2, output); } @@ -8561,6 +8557,10 @@ extern bool container_iterator_next(const container_t *c, uint8_t typecode, extern bool container_iterator_prev(const container_t *c, uint8_t typecode, roaring_container_iterator_t *it, uint16_t *value); +extern bool container_contains( + const container_t *c, uint16_t val, + uint8_t typecode // !!! should be second argument? +); void container_free(container_t *c, uint8_t type) { switch (type) { @@ -18195,6 +18195,43 @@ roaring64_bitmap_t *roaring64_bitmap_copy(const roaring64_bitmap_t *r) { return result; } +void roaring64_bitmap_overwrite(roaring64_bitmap_t *dest, + const roaring64_bitmap_t *src) { + if (dest == src) { + return; + } + + // Free dest's containers. + art_iterator_t it = art_init_iterator(&dest->art, /*first=*/true); + while (it.value != NULL) { + leaf_t leaf = (leaf_t)*it.value; + container_free(get_container(dest, leaf), get_typecode(leaf)); + art_iterator_next(&it); + } + art_free(&dest->art); + + // Reinitialize dest. + art_init_cleared(&dest->art); + dest->flags = 0; + dest->first_free = 0; + if (dest->capacity > 0) { + memset(dest->containers, 0, + sizeof(dest->containers[0]) * dest->capacity); + } + + // Copy src's containers into dest. + it = art_init_iterator((art_t *)&src->art, /*first=*/true); + while (it.value != NULL) { + leaf_t leaf = (leaf_t)*it.value; + uint8_t typecode = get_typecode(leaf); + container_t *container = get_copy_of_container( + get_container(src, leaf), &typecode, /*copy_on_write=*/false); + leaf_t dest_leaf = add_container(dest, container, typecode); + art_insert(&dest->art, it.key, (art_val_t)dest_leaf); + art_iterator_next(&it); + } +} + /** * Steal the containers from a 32-bit bitmap and insert them into a 64-bit * bitmap (with an offset) @@ -18863,6 +18900,26 @@ uint64_t roaring64_bitmap_maximum(const roaring64_bitmap_t *r) { it.key, container_maximum(get_container(r, leaf), get_typecode(leaf))); } +bool roaring64_bitmap_remove_run_compression(roaring64_bitmap_t *r) { + art_iterator_t it = art_init_iterator(&r->art, /*first=*/true); + bool removed = false; + while (it.value != NULL) { + leaf_t *leaf = (leaf_t *)it.value; + if (get_typecode(*leaf) == RUN_CONTAINER_TYPE) { + run_container_t *run = CAST_run(get_container(r, *leaf)); + int32_t card = run_container_cardinality(run); + uint8_t new_typecode; + container_t *new_container = + convert_to_bitset_or_array_container(run, card, &new_typecode); + run_container_free(run); + replace_container(r, leaf, new_container, new_typecode); + removed = true; + } + art_iterator_next(&it); + } + return removed; +} + bool roaring64_bitmap_run_optimize(roaring64_bitmap_t *r) { art_iterator_t it = art_init_iterator(&r->art, /*first=*/true); bool has_run_container = false; @@ -19821,6 +19878,131 @@ void roaring64_bitmap_flip_closed_inplace(roaring64_bitmap_t *r, uint64_t min, } } +roaring64_bitmap_t *roaring64_bitmap_add_offset_signed( + const roaring64_bitmap_t *r, bool positive, uint64_t offset) { + if (offset == 0) { + return roaring64_bitmap_copy(r); + } + + roaring64_bitmap_t *answer = roaring64_bitmap_create(); + + // Decompose the offset into a signed container-level shift and an + // intra-container shift. For negative offsets the low 16 bits wrap: e.g. + // -1 = container_offset(-1) + in_offset(0xffff), because shifting by -1 + // container is a shift of -0x1_0000, so we need to shift up within + // containers to get back to -1 + uint16_t low16 = (uint16_t)offset; + int64_t container_offset; + uint16_t in_offset; + if (positive) { + container_offset = (int64_t)(offset >> 16); + in_offset = low16; + } else if (low16 == 0) { + container_offset = -(int64_t)(offset >> 16); + in_offset = 0; + } else { + container_offset = -(int64_t)(offset >> 16) - 1; + in_offset = (uint16_t)-low16; + } + + art_iterator_t it = art_init_iterator((art_t *)&r->art, /*first=*/true); + + if (in_offset == 0) { + while (it.value != NULL) { + leaf_t leaf = (leaf_t)*it.value; + int64_t k = + (int64_t)(combine_key(it.key, 0) >> 16) + container_offset; + if ((uint64_t)k < (uint64_t)1 << 48) { + uint8_t new_high48[ART_KEY_BYTES]; + split_key((uint64_t)k << 16, new_high48); + uint8_t typecode = get_typecode(leaf); + container_t *container = + get_copy_of_container(get_container(r, leaf), &typecode, + /*copy_on_write=*/false); + leaf_t new_leaf = add_container(answer, container, typecode); + art_insert(&answer->art, new_high48, (art_val_t)new_leaf); + } + art_iterator_next(&it); + } + return answer; + } + + // Track the most recently inserted hi container so that the next + // iteration's lo can merge with it without re-searching the ART. + leaf_t *prev_hi_leaf = NULL; + int64_t prev_hi_k = -1; + + while (it.value != NULL) { + leaf_t leaf = (leaf_t)*it.value; + int64_t k = (int64_t)(combine_key(it.key, 0) >> 16) + container_offset; + + container_t *lo = NULL, *hi = NULL; + container_t **lo_ptr = NULL, **hi_ptr = NULL; + + if ((uint64_t)k < (uint64_t)1 << 48) { + lo_ptr = &lo; + } + if ((uint64_t)(k + 1) < (uint64_t)1 << 48) { + hi_ptr = &hi; + } + if (lo_ptr == NULL && hi_ptr == NULL) { + art_iterator_next(&it); + continue; + } + + uint8_t typecode = get_typecode(leaf); + const container_t *c = + container_unwrap_shared(get_container(r, leaf), &typecode); + container_add_offset(c, typecode, lo_ptr, hi_ptr, in_offset); + + if (lo != NULL) { + if (prev_hi_leaf != NULL && prev_hi_k == k) { + uint8_t existing_type = get_typecode(*prev_hi_leaf); + container_t *existing_c = get_container(answer, *prev_hi_leaf); + uint8_t merged_type; + container_t *merged_c = container_ior( + existing_c, existing_type, lo, typecode, &merged_type); + if (merged_c != existing_c) { + container_free(existing_c, existing_type); + } + replace_container(answer, prev_hi_leaf, merged_c, merged_type); + container_free(lo, typecode); + } else { + uint8_t lo_high48[ART_KEY_BYTES]; + split_key((uint64_t)k << 16, lo_high48); + leaf_t new_leaf = add_container(answer, lo, typecode); + art_insert(&answer->art, lo_high48, (art_val_t)new_leaf); + } + } + + prev_hi_leaf = NULL; + if (hi != NULL) { + uint8_t hi_high48[ART_KEY_BYTES]; + split_key((uint64_t)(k + 1) << 16, hi_high48); + leaf_t new_leaf = add_container(answer, hi, typecode); + prev_hi_leaf = (leaf_t *)art_insert(&answer->art, hi_high48, + (art_val_t)new_leaf); + prev_hi_k = k + 1; + } + + art_iterator_next(&it); + } + + // Repair containers (e.g., convert low-cardinality bitset containers to + // array containers after lazy union operations). + art_iterator_t repair_it = art_init_iterator(&answer->art, /*first=*/true); + while (repair_it.value != NULL) { + leaf_t *leaf_ptr = (leaf_t *)repair_it.value; + uint8_t typecode = get_typecode(*leaf_ptr); + container_t *repaired = container_repair_after_lazy( + get_container(answer, *leaf_ptr), &typecode); + replace_container(answer, leaf_ptr, repaired, typecode); + art_iterator_next(&repair_it); + } + + return answer; +} + // Returns the number of distinct high 32-bit entries in the bitmap. static inline uint64_t count_high32(const roaring64_bitmap_t *r) { art_iterator_t it = art_init_iterator((art_t *)&r->art, /*first=*/true); diff --git a/croaring-sys/CRoaring/roaring.h b/croaring-sys/CRoaring/roaring.h index 7f25528..c8e6d1c 100644 --- a/croaring-sys/CRoaring/roaring.h +++ b/croaring-sys/CRoaring/roaring.h @@ -1,5 +1,5 @@ // !!! DO NOT EDIT - THIS IS AN AUTO-GENERATED FILE !!! -// Created by amalgamation.sh on 2025-12-30T22:56:55Z +// Created by amalgamation.sh on 2026-03-09T14:59:44Z /* * The CRoaring project is under a dual license (Apache/MIT). @@ -59,10 +59,10 @@ // /include/roaring/roaring_version.h automatically generated by release.py, do not change by hand #ifndef ROARING_INCLUDE_ROARING_VERSION #define ROARING_INCLUDE_ROARING_VERSION -#define ROARING_VERSION "4.5.1" +#define ROARING_VERSION "4.6.1" enum { ROARING_VERSION_MAJOR = 4, - ROARING_VERSION_MINOR = 5, + ROARING_VERSION_MINOR = 6, ROARING_VERSION_REVISION = 1 }; #endif // ROARING_INCLUDE_ROARING_VERSION @@ -1410,12 +1410,11 @@ static inline int32_t count_greater(const uint16_t *array, int32_t lenarray, * C should have capacity greater than the minimum of s_1 and s_b + 8 * where 8 is sizeof(__m128i)/sizeof(uint16_t). */ -int32_t intersect_vector16(const uint16_t *__restrict__ A, size_t s_a, - const uint16_t *__restrict__ B, size_t s_b, - uint16_t *C); +int32_t intersect_vector16(const uint16_t *A, size_t s_a, const uint16_t *B, + size_t s_b, uint16_t *C); -int32_t intersect_vector16_inplace(uint16_t *__restrict__ A, size_t s_a, - const uint16_t *__restrict__ B, size_t s_b); +int32_t intersect_vector16_inplace(uint16_t *A, size_t s_a, const uint16_t *B, + size_t s_b); /** * Take an array container and write it out to a 32-bit array, using base @@ -1430,10 +1429,8 @@ int avx512_array_container_to_uint32_array(void *vout, const uint16_t *array, /** * Compute the cardinality of the intersection using SSE4 instructions */ -int32_t intersect_vector16_cardinality(const uint16_t *__restrict__ A, - size_t s_a, - const uint16_t *__restrict__ B, - size_t s_b); +int32_t intersect_vector16_cardinality(const uint16_t *A, size_t s_a, + const uint16_t *B, size_t s_b); /* Computes the intersection between one small and one large set of uint16_t. * Stores the result into buffer and return the number of elements. */ @@ -1508,22 +1505,21 @@ size_t union_uint32(const uint32_t *set_1, size_t size_1, const uint32_t *set_2, /** * A fast SSE-based union function. */ -uint32_t union_vector16(const uint16_t *__restrict__ set_1, uint32_t size_1, - const uint16_t *__restrict__ set_2, uint32_t size_2, - uint16_t *__restrict__ buffer); +uint32_t union_vector16(const uint16_t *set_1, uint32_t size_1, + const uint16_t *set_2, uint32_t size_2, + uint16_t *buffer); /** * A fast SSE-based XOR function. */ -uint32_t xor_vector16(const uint16_t *__restrict__ array1, uint32_t length1, - const uint16_t *__restrict__ array2, uint32_t length2, - uint16_t *__restrict__ output); +uint32_t xor_vector16(const uint16_t *array1, uint32_t length1, + const uint16_t *array2, uint32_t length2, + uint16_t *output); /** * A fast SSE-based difference function. */ -int32_t difference_vector16(const uint16_t *__restrict__ A, size_t s_a, - const uint16_t *__restrict__ B, size_t s_b, - uint16_t *C); +int32_t difference_vector16(const uint16_t *A, size_t s_a, const uint16_t *B, + size_t s_b, uint16_t *C); /** * Generic union function, returns just the cardinality. @@ -5430,9 +5426,9 @@ static inline container_t *container_remove( } /** - * Check whether a value is in a container, requires a typecode + * Check whether a value is in a container, requires a typecode */ -static inline bool container_contains( +inline bool container_contains( const container_t *c, uint16_t val, uint8_t typecode // !!! should be second argument? ) { @@ -9195,6 +9191,18 @@ void roaring64_bitmap_free(roaring64_bitmap_t *r); */ roaring64_bitmap_t *roaring64_bitmap_copy(const roaring64_bitmap_t *r); +/** + * Copies a bitmap from src to dest. It is assumed that the pointer dest + * is to an already allocated bitmap. The content of the dest bitmap is + * freed/deleted. + * + * It might be preferable and simpler to call roaring64_bitmap_copy except + * that roaring64_bitmap_overwrite can save on memory allocations. + * + */ +void roaring64_bitmap_overwrite(roaring64_bitmap_t *dest, + const roaring64_bitmap_t *src); + /** * Creates a new bitmap of a pointer to N 64-bit integers. */ @@ -9455,6 +9463,12 @@ uint64_t roaring64_bitmap_minimum(const roaring64_bitmap_t *r); */ uint64_t roaring64_bitmap_maximum(const roaring64_bitmap_t *r); +/** + * Remove run-length encoding even when it is more space efficient. + * Return whether a change was applied. + */ +bool roaring64_bitmap_remove_run_compression(roaring64_bitmap_t *r); + /** * Returns true if the result has at least one run container. */ @@ -9651,6 +9665,38 @@ void roaring64_bitmap_flip_inplace(roaring64_bitmap_t *r, uint64_t min, */ void roaring64_bitmap_flip_closed_inplace(roaring64_bitmap_t *r, uint64_t min, uint64_t max); +/** + * Return a copy of the bitmap with all values shifted by offset. + * + * If `positive` is true, the shift is added, otherwise subtracted. Values that + * overflow or underflow uint64_t are dropped. The caller is responsible for + * freeing the returned bitmap. + */ +roaring64_bitmap_t *roaring64_bitmap_add_offset_signed( + const roaring64_bitmap_t *r, bool positive, uint64_t offset); + +/** + * Return a copy of the bitmap with all values shifted up by offset. + * + * Values that overflow or underflow uint64_t are dropped. The caller is + * responsible for freeing the returned bitmap. + */ +static inline roaring64_bitmap_t *roaring64_bitmap_add_offset( + const roaring64_bitmap_t *r, uint64_t offset) { + return roaring64_bitmap_add_offset_signed(r, true, offset); +} + +/** + * Return a copy of the bitmap with all values shifted down by offset. + * + * Values that overflow or underflow uint64_t are dropped. The caller is + * responsible for freeing the returned bitmap. + */ +static inline roaring64_bitmap_t *roaring64_bitmap_sub_offset( + const roaring64_bitmap_t *r, uint64_t offset) { + return roaring64_bitmap_add_offset_signed(r, false, offset); +} + /** * How many bytes are required to serialize this bitmap. * diff --git a/croaring-sys/CRoaring/roaring.hh b/croaring-sys/CRoaring/roaring.hh index 83fe563..a409792 100644 --- a/croaring-sys/CRoaring/roaring.hh +++ b/croaring-sys/CRoaring/roaring.hh @@ -1,5 +1,5 @@ // !!! DO NOT EDIT - THIS IS AN AUTO-GENERATED FILE !!! -// Created by amalgamation.sh on 2025-12-30T22:56:55Z +// Created by amalgamation.sh on 2026-03-09T14:59:44Z /* * The CRoaring project is under a dual license (Apache/MIT). @@ -744,6 +744,15 @@ class Roaring { return Roaring(r); } + /** + * Compute how many bytes would be read by readSafe. Returns 0 if the + * serialized data is invalid. + * This is meant to be compatible with the Java and Go versions. + */ + static size_t serializedSizeInBytesSafe(const char *buf, size_t maxbytes) { + return api::roaring_bitmap_portable_deserialize_size(buf, maxbytes); + } + /** * How many bytes are required to serialize this bitmap (meant to be * compatible with Java and Go versions) @@ -2294,6 +2303,9 @@ class Roaring64Map { ROARING_TERMINATE("ran out of bytes"); } Roaring64Map result; + if (maxbytes < sizeof(uint64_t)) { + ROARING_TERMINATE("ran out of bytes"); + } uint64_t map_size; std::memcpy(&map_size, buf, sizeof(uint64_t)); buf += sizeof(uint64_t); @@ -2309,11 +2321,15 @@ class Roaring64Map { buf += sizeof(uint32_t); maxbytes -= sizeof(uint32_t); // read map value Roaring + size_t needed_bytes = + Roaring::serializedSizeInBytesSafe(buf, maxbytes); + if (needed_bytes == 0) { + ROARING_TERMINATE("invalid serialized data"); + } Roaring read_var = Roaring::readSafe(buf, maxbytes); // forward buffer past the last Roaring Bitmap - size_t tz = read_var.getSizeInBytes(true); - buf += tz; - maxbytes -= tz; + buf += needed_bytes; + maxbytes -= needed_bytes; result.emplaceOrInsert(key, std::move(read_var)); } return result; diff --git a/croaring-sys/Cargo.toml b/croaring-sys/Cargo.toml index 7449e34..443f17c 100644 --- a/croaring-sys/Cargo.toml +++ b/croaring-sys/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "croaring-sys" -version = "4.5.1" +version = "4.6.1" edition = "2021" authors = ["croaring-rs developers"] license = "Apache-2.0" diff --git a/fuzz/Cargo.lock b/fuzz/Cargo.lock index 644dec5..4deb25b 100644 --- a/fuzz/Cargo.lock +++ b/fuzz/Cargo.lock @@ -49,7 +49,7 @@ checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" [[package]] name = "croaring" -version = "2.5.1" +version = "2.5.2" dependencies = [ "allocator-api2", "croaring-sys", @@ -66,7 +66,7 @@ dependencies = [ [[package]] name = "croaring-sys" -version = "4.5.1" +version = "4.6.1" dependencies = [ "cc", ]