Skip to content

Commit 67d0376

Browse files
authored
Merge pull request #410 from alpaylan/fix/count-overflow
Fix the overflow at (#408)
2 parents 4364c4b + 882ffa3 commit 67d0376

3 files changed

Lines changed: 22 additions & 2 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
- `TestResult.stats` `TestResult.warnings` `TestResult.collect`
5555
- Clarify documentation for the `int*` and `nat*` generators
5656
- Disabled duplicated pretty-printed feedback when using `QCheck_alcotest` runner
57+
- Fixed the overflow bug when `~count > max_int - 200` affecting `Test.{make_cell,make,make_neg}` in both QCheck and QCheck2
5758

5859

5960
## 0.91 (2025-12-21)

src/core/QCheck2.ml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1618,7 +1618,7 @@ module Test = struct
16181618
let count = global_count count in
16191619
let long_factor = global_long_factor long_factor in
16201620
let positive = not negative in
1621-
let max_gen = match max_gen with None -> count + 200 | Some x->x in
1621+
let max_gen = match max_gen with None -> max count (count + 200) | Some x->x in
16221622
{
16231623
law;
16241624
gen;
@@ -1645,7 +1645,7 @@ module Test = struct
16451645
let positive = not negative in
16461646
(* Make a "fake" QCheck2 arbitrary with no shrinking *)
16471647
let fake_gen = Gen.make_primitive ~gen ~shrink:(fun _ -> Seq.empty) in
1648-
let max_gen = match max_gen with None -> count + 200 | Some x->x in
1648+
let max_gen = match max_gen with None -> max count (count + 200) | Some x->x in
16491649
{
16501650
law;
16511651
gen = fake_gen;

test/core/QCheck2_unit_tests.ml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -617,6 +617,23 @@ module TestCount = struct
617617
with
618618
| _ -> ()
619619

620+
(* Regression for https://github.com/c-cube/qcheck/issues/408:
621+
[make_cell] computed [max_gen = count + 200] without checking for
622+
overflow, so [count >= max_int - 199] wrapped to a negative int
623+
and [check_cell] silently ran zero iterations. *)
624+
let test_count_max_int_no_overflow () =
625+
let cell =
626+
QCheck2.(Test.make_cell ~name:"never_true" ~count:max_int
627+
Gen.int (fun _ -> false))
628+
in
629+
let result =
630+
QCheck2.Test.check_cell ~rand:(Random.State.make [|0|]) cell
631+
in
632+
let tested = QCheck2.TestResult.get_count_gen result in
633+
Alcotest.(check bool)
634+
"check_cell with count=max_int runs at least one iteration"
635+
true (tested >= 1)
636+
620637
let tests =
621638
("Test.make ~count", Alcotest.[
622639
test_case "make with custom count" `Quick test_count_10;
@@ -625,6 +642,8 @@ module TestCount = struct
625642
test_case "make with 0 count" `Quick test_count_0;
626643
test_case "make with negative count should fail"
627644
`Quick test_count_negative_fail;
645+
test_case "check_cell with count=max_int does not overflow"
646+
`Quick test_count_max_int_no_overflow;
628647
])
629648
end
630649

0 commit comments

Comments
 (0)