Skip to content

Commit 6212525

Browse files
authored
Merge pull request #3991 from tybug/novel-prefix-overrun
Handle overruns in `generate_novel_prefix`
2 parents 4e77eea + 6b5b69d commit 6212525

File tree

4 files changed

+60
-5
lines changed

4 files changed

+60
-5
lines changed

hypothesis-python/RELEASE.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
RELEASE_TYPE: patch
2+
3+
This patch fixes a rare internal error when generating very large elements from strategies (:issue:`3874`).

hypothesis-python/src/hypothesis/internal/conjecture/datatree.py

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -755,7 +755,14 @@ def append_buf(buf):
755755
attempts = 0
756756
while True:
757757
if attempts <= 10:
758-
(v, buf) = self._draw(ir_type, kwargs, random=random)
758+
try:
759+
(v, buf) = self._draw(ir_type, kwargs, random=random)
760+
except StopTest: # pragma: no cover
761+
# it is possible that drawing from a fresh data can
762+
# overrun BUFFER_SIZE, due to eg unlucky rejection sampling
763+
# of integer probes. Retry these cases.
764+
attempts += 1
765+
continue
759766
else:
760767
(v, buf) = self._draw_from_cache(
761768
ir_type, kwargs, key=id(current_node), random=random
@@ -781,9 +788,13 @@ def append_buf(buf):
781788
attempts = 0
782789
while True:
783790
if attempts <= 10:
784-
(v, buf) = self._draw(
785-
branch.ir_type, branch.kwargs, random=random
786-
)
791+
try:
792+
(v, buf) = self._draw(
793+
branch.ir_type, branch.kwargs, random=random
794+
)
795+
except StopTest: # pragma: no cover
796+
attempts += 1
797+
continue
787798
else:
788799
(v, buf) = self._draw_from_cache(
789800
branch.ir_type, branch.kwargs, key=id(branch), random=random

hypothesis-python/tests/conjecture/test_engine.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1626,3 +1626,38 @@ def test(cd):
16261626

16271627
runner.cached_test_function_ir([node] if forced_first else [forced_node])
16281628
assert runner.call_count == 1
1629+
1630+
1631+
def test_simulate_to_evicted_data(monkeypatch):
1632+
# test that we do not rely on the false invariant that correctly simulating
1633+
# a data to a result means we have that result in the cache, due to e.g.
1634+
# cache evictions (but also potentially other trickery).
1635+
monkeypatch.setattr(engine_module, "CACHE_SIZE", 1)
1636+
1637+
node_0 = IRNode(
1638+
ir_type="integer",
1639+
value=0,
1640+
kwargs={
1641+
"min_value": None,
1642+
"max_value": None,
1643+
"weights": None,
1644+
"shrink_towards": 0,
1645+
},
1646+
was_forced=False,
1647+
)
1648+
node_1 = node_0.copy(with_value=1)
1649+
1650+
def test(data):
1651+
data.draw_integer()
1652+
1653+
runner = ConjectureRunner(test)
1654+
runner.cached_test_function_ir([node_0])
1655+
# cache size is 1 so this evicts node_0
1656+
runner.cached_test_function_ir([node_1])
1657+
assert runner.call_count == 2
1658+
1659+
# we dont throw PreviouslyUnseenBehavior when simulating, but the result
1660+
# was evicted to the cache so we will still call through to the test function.
1661+
runner.tree.simulate_test_function(ConjectureData.for_ir_tree([node_0]))
1662+
runner.cached_test_function_ir([node_0])
1663+
assert runner.call_count == 3

hypothesis-python/tests/nocover/test_regressions.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ def test_performance_issue_2027(x, y):
4646
pass
4747

4848

49-
# if this test ever fails with a flaky error, #3926 has regressed.
5049
@given(
5150
st.lists(
5251
st.floats(allow_infinity=False),
@@ -55,3 +54,10 @@ def test_performance_issue_2027(x, y):
5554
)
5655
def test_unique_floats_with_nan_is_not_flaky_3926(ls):
5756
pass
57+
58+
59+
# this will take a while to find the regression, but will eventually trigger it.
60+
# min_value=0 is critical to trigger the probing behavior which exhausts our buffer.
61+
@given(st.integers(min_value=0, max_value=1 << 25_000))
62+
def test_overrun_during_datatree_simulation_3874(n):
63+
pass

0 commit comments

Comments
 (0)