pack-bitmap: reject pseudo-merge "sampleRate" of 0

The "bitmapPseudoMerge.*.sampleRate" configuration controls what fraction of unstable commits are included in each pseudo-merge group. The config validation accepts values in the range `[0, 1]`, but a value of exactly 0 causes a division by zero in `select_pseudo_merges_1()`: if (j % (uint32_t)(1.0 / group->sample_rate)) When `sample_rate` is 0, `1.0 / 0.0` produces `+inf`, and casting infinity to `uint32_t` is undefined behavior in C. On most platforms this yields 0, making the subsequent modulo operation (`j % 0`) a fatal arithmetic trap. This path was not previously reachable because an earlier bug caused all pseudo-merge candidates to be classified as "stable" (where the sampling rate is not used), regardless of their actual commit date. Now that the date classification is fixed, the unstable path is exercised and the division by zero can fire. Fix this by changing the validation to require a strict lower bound and thus reject 0. Signed-off-by: Taylor Blau <me@ttaylorr.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Taylor Blau committed May 11, 2026 at 20:47 UTC 03c7a30ceeaee8d70ff2e2cbd9b4bce896841bfa
3 files changed +5 -5
Documentation/config/bitmap-pseudo-merge.adoc
+2 -2
@@ -47,8 +47,8 @@ will be updated more often than a reference pointing at an old commit.
47 bitmapPseudoMerge.<name>.sampleRate::
48 Determines the proportion of non-bitmapped commits (among
49 reference tips) which are selected for inclusion in an
50 - unstable pseudo-merge bitmap. Must be between `0` and `1`
51 - (inclusive). The default is `1`.
50 + unstable pseudo-merge bitmap. Must be greater than `0` and
51 + less than or equal to `1`. The default is `1`.
52
53 bitmapPseudoMerge.<name>.threshold::
54 Determines the minimum age of non-bitmapped commits (among
pseudo-merge.c
+2 -2
@@ -169,8 +169,8 @@ static int pseudo_merge_config(const char *var, const char *value,
169 }
170 } else if (!strcmp(key, "samplerate")) {
171 group->sample_rate = git_config_double(var, value, ctx->kvi);
172 - if (!(0 <= group->sample_rate && group->sample_rate <= 1)) {
173 - warning(_("%s must be between 0 and 1, using default"), var);
172 + if (!(0 < group->sample_rate && group->sample_rate <= 1)) {
173 + warning(_("%s must be between 0 (exclusive) and 1, using default"), var);
174 group->sample_rate = DEFAULT_PSEUDO_MERGE_SAMPLE_RATE;
175 }
176 } else if (!strcmp(key, "threshold")) {
t/t5333-pseudo-merge-bitmaps.sh
+1 -1
@@ -639,7 +639,7 @@ test_expect_success 'pseudo-merge commits are correctly classified by date' '
639 )
640 '
641
642 -test_expect_failure 'sampleRate=0 does not cause division by zero' '
642 +test_expect_success 'sampleRate=0 does not cause division by zero' '
643 test_when_finished "rm -fr pseudo-merge-sample-rate-zero" &&
644 git init pseudo-merge-sample-rate-zero &&
645 (