[med-svn] [Git][med-team/jellyfish][master] Fix key claim tracking during hash resizing on carry overflow Closes: #1148450

Andreas Tille (@tille) gitlab at salsa.debian.org
Tue Sep 22 13:56:03 BST 2026



Andreas Tille pushed to branch master at Debian Med / jellyfish


Commits:
c1339f0e by Andreas Tille at 2026-09-22T14:55:13+02:00
Fix key claim tracking during hash resizing on carry overflow Closes: #1148450

- - - - -


3 changed files:

- debian/changelog
- + debian/patches/fix_hash_counter_resizing_carry.patch
- debian/patches/series


Changes:

=====================================
debian/changelog
=====================================
@@ -1,3 +1,11 @@
+jellyfish (2.3.1-7) UNRELEASED; urgency=medium
+
+  [ Maximiliano Curia ]
+  * Fix key claim tracking during hash resizing on carry overflow
+    Closes: #1148450
+
+ -- Andreas Tille <tille at debian.org>  Tue, 22 Sep 2026 14:51:44 +0200
+
 jellyfish (2.3.1-6) unstable; urgency=medium
 
   * Team upload.


=====================================
debian/patches/fix_hash_counter_resizing_carry.patch
=====================================
@@ -0,0 +1,123 @@
+Description: Fix key claim tracking during hash resizing on carry overflow
+ When a value is a multiple of 2^val_len and overflows to carry during insertion,
+ carry_shift equals the original value even though the key was claimed and its
+ lower bits stored. Track key claim status explicitly to prevent duplicate adds
+ and incorrect is_new return values after table resizing.
+Author: Maximiliano Curia <maxy at debian.org>
+Bug-Debian: https://bugs.debian.org/1148450
+Forwarded: no
+
+Index: jellyfish/include/jellyfish/hash_counter.hpp
+===================================================================
+--- jellyfish.orig/include/jellyfish/hash_counter.hpp
++++ jellyfish/include/jellyfish/hash_counter.hpp
+@@ -97,16 +97,17 @@ public:
+ 
+     //    while(!ary_->add(k, v, &carry_shift, is_new_ptr, id_ptr)) {
+     while(true) {
+-      if(ary_->add(k, v, &carry_shift, is_new_ptr, id_ptr)) break;
++      bool key_claimed = false;
++      if(ary_->add(k, v, &carry_shift, is_new_ptr, id_ptr, &key_claimed)) break;
+       handle_full_ary();
+ 
+-      // If carry_shift == v, failed to allocate the first field for
++      // If !key_claimed, failed to allocate the first field for
+       // key, hence status of is_new and value for id are not
+-      // determined yet. On the other hand, if carry_shift < v, we
++      // determined yet. On the other hand, if key_claimed is true, we
+       // failed while adding extra field for large key, so the status
+       // of is_new and value of id are known. We do not update them in future
+       // calls.
+-      if(carry_shift != v) {
++      if(key_claimed) {
+         is_new_ptr = &is_new_void;
+         id_ptr     = &id_void;
+         v          = carry_shift;
+@@ -156,9 +157,10 @@ public:
+     uint64_t carry_shift = 0;
+ 
+     while(true) {
+-      if(ary_->update_add(k, v, &carry_shift, tmp_key))
++      bool key_found = false;
++      if(ary_->update_add(k, v, &carry_shift, tmp_key, &key_found))
+         return true;
+-      if(carry_shift == v)
++      if(!key_found)
+         return false;
+       handle_full_ary();
+       v = carry_shift;
+Index: jellyfish/include/jellyfish/large_hash_array.hpp
+===================================================================
+--- jellyfish.orig/include/jellyfish/large_hash_array.hpp
++++ jellyfish/include/jellyfish/large_hash_array.hpp
+@@ -288,10 +288,11 @@ public:
+    * proper size doubling is perform, one need to call add again with
+    * val set to carry_shift.
+    */
+-  inline bool add(const key_type& key, mapped_type val, word* carry_shift, bool* is_new, size_t* id) {
++  inline bool add(const key_type& key, mapped_type val, word* carry_shift, bool* is_new, size_t* id, bool* key_claimed = 0) {
+     uint64_t hash = hash_matrix_.times(key);
+     *carry_shift  = 0;
+-    return add_rec(hash & size_mask_, key, val, false, is_new, id, carry_shift);
++    if(key_claimed) *key_claimed = false;
++    return add_rec(hash & size_mask_, key, val, false, is_new, id, carry_shift, key_claimed);
+   }
+ 
+   inline bool add(const key_type& key, mapped_type val, word* carry_shift) {
+@@ -332,12 +333,14 @@ public:
+ 
+ 
+   // Optimization. Use tmp_key as buffer. Avoids allocation if update_add is called repeatedly.
+-  bool update_add(const key_type& key, mapped_type val, word* carry_shift, key_type& tmp_key) {
++  bool update_add(const key_type& key, mapped_type val, word* carry_shift, key_type& tmp_key, bool* key_found = 0) {
+     size_t          id;
+     word*           w;
+     const offset_t* o;
+ 
++    if(key_found) *key_found = false;
+     if(get_key_id(key, &id, tmp_key, (const word**)&w, &o)) {
++      if(key_found) *key_found = true;
+       *carry_shift = 0;
+       return add_rec_at(id, key, val, o, w, carry_shift);
+     } else {
+@@ -654,24 +657,27 @@ public:
+   // carry_shift is properly set to the value of the carry shifted by
+   // the right number of bits so a further call to add with
+   // carry_shift as val finishes the operation.
+-  bool add_rec(size_t id, const key_type& key, word val, bool large, bool* is_new, size_t* eid, word* carry_shift) {
++  bool add_rec(size_t id, const key_type& key, word val, bool large, bool* is_new, size_t* eid, word* carry_shift, bool* key_claimed = 0) {
+     const offset_t *ao = 0;
+     word	   *w  = 0;
+ 
+     bool claimed = false;
+     if(large)
+       claimed = claim_large_key(&id, &ao, &w);
+-    else
++    else {
+       claimed = claim_key(key, is_new, &id, &ao, &w);
++      if(claimed && key_claimed)
++        *key_claimed = true;
++    }
+     if(!claimed) {
+       *carry_shift = val << (*carry_shift);
+       return false;
+     }
+     *eid = id;
+-    return add_rec_at(id, key, val, ao, w, carry_shift);
++    return add_rec_at(id, key, val, ao, w, carry_shift, key_claimed);
+   }
+ 
+-  bool add_rec_at(size_t id, const key_type& key, word val, const offset_t* ao, word* w, word* carry_shift) {
++  bool add_rec_at(size_t id, const key_type& key, word val, const offset_t* ao, word* w, word* carry_shift, bool* key_claimed = 0) {
+     // Increment value
+     word *vw       = w + ao->val.woff;
+     word  cary     = add_val(vw, val, ao->val.boff, ao->val.mask1);
+@@ -690,7 +696,7 @@ public:
+     id = (id + reprobes_[0]) & size_mask_;
+     size_t ignore_eid;
+     bool   ignore_is_new;
+-    return add_rec(id, key, cary, true, &ignore_is_new, &ignore_eid, carry_shift);
++    return add_rec(id, key, cary, true, &ignore_is_new, &ignore_eid, carry_shift, key_claimed);
+ 
+       // // Adding failed, table is full. Need to back-track and
+       // // substract val.


=====================================
debian/patches/series
=====================================
@@ -3,3 +3,4 @@ manpage_whatis_entry.patch
 portability.patch
 test_needs_bash
 python3
+fix_hash_counter_resizing_carry.patch



View it on GitLab: https://salsa.debian.org/med-team/jellyfish/-/commit/c1339f0e4de59baf4266d701eabda2459e5d6e78

-- 
View it on GitLab: https://salsa.debian.org/med-team/jellyfish/-/commit/c1339f0e4de59baf4266d701eabda2459e5d6e78
You're receiving this email because of your account on salsa.debian.org. Manage all notifications: https://salsa.debian.org/-/profile/notifications | Help: https://salsa.debian.org/help


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/debian-med-commit/attachments/20260922/341f92a4/attachment-0001.htm>


More information about the debian-med-commit mailing list