From c11d0f03fa33880bc152df64d528f1896601502b Mon Sep 17 00:00:00 2001 From: Rob Patro Date: Mon, 9 Mar 2026 21:21:08 -0400 Subject: [PATCH] Fix UB in file_merging_iterator sentinel and is_member comparison file_merging_iterator used std::numeric_limits::max() as a sentinel value, but minimizer_tuple has no std::numeric_limits specialization. This returns a default-constructed object with uninitialized members (UB), causing segfaults when merging >16 minimizer files via the winner tree path. Use T::max() instead, which minimizer_tuple properly defines. Also fix is_member() which compared lookup_result directly against uint64_t instead of comparing lookup_result.kmer_id. Co-Authored-By: Claude Opus 4.6 --- include/builder/file_merging_iterator.hpp | 4 ++-- src/dictionary.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/builder/file_merging_iterator.hpp b/include/builder/file_merging_iterator.hpp index 301ad77..911bcaa 100644 --- a/include/builder/file_merging_iterator.hpp +++ b/include/builder/file_merging_iterator.hpp @@ -94,7 +94,7 @@ struct file_merging_iterator // m_tree[p] = uint32_t(-1); --m_num_files_to_merge; } - const T inf = std::numeric_limits::max(); + const T inf = T::max(); while (p) { uint64_t is_r_child = (p & 1) == 0; uint32_t i = 0; @@ -128,7 +128,7 @@ struct file_merging_iterator // uint32_t l = build(2 * p + 1); uint32_t r = build(2 * p + 2); uint32_t i = 0; - const T inf = std::numeric_limits::max(); + const T inf = T::max(); T const* ptr_l = (l == uint32_t(-1)) ? &inf : m_iterators[l].begin; T const* ptr_r = (r == uint32_t(-1)) ? &inf : m_iterators[r].begin; i = (*ptr_l < *ptr_r) ? l : r; diff --git a/src/dictionary.cpp b/src/dictionary.cpp index d0838c9..c1b43f7 100644 --- a/src/dictionary.cpp +++ b/src/dictionary.cpp @@ -80,11 +80,11 @@ lookup_result dictionary::lookup(Kmer uint_kmer, template bool dictionary::is_member(char const* string_kmer, bool check_reverse_complement) const { - return lookup(string_kmer, check_reverse_complement) != constants::invalid_uint64; + return lookup(string_kmer, check_reverse_complement).kmer_id != constants::invalid_uint64; } template bool dictionary::is_member(Kmer uint_kmer, bool check_reverse_complement) const { - return lookup(uint_kmer, check_reverse_complement) != constants::invalid_uint64; + return lookup(uint_kmer, check_reverse_complement).kmer_id != constants::invalid_uint64; } template