This is an automated email from the ASF dual-hosted git repository. aherbert pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/commons-rng.git
commit d01b5051799cd60f7b675e4ee1680bc35079b436 Author: aherbert <[email protected]> AuthorDate: Tue Apr 5 13:26:04 2022 +0100 RNG-175: Fix MSWS createSeed(UniformRandomProvider) to handle a bad RNG The createSeed(UniformRandomProvider) method should generate a seed even if the input RNG is non-functional. This fixes an infinite loop when the RNG output is not suitably random to create a seed. --- .../rng/simple/internal/ProviderBuilder.java | 29 +++++++++++++++++++++- .../commons/rng/simple/RandomSourceTest.java | 19 ++++++++++++++ src/changes/changes.xml | 4 +++ 3 files changed, 51 insertions(+), 1 deletion(-) diff --git a/commons-rng-simple/src/main/java/org/apache/commons/rng/simple/internal/ProviderBuilder.java b/commons-rng-simple/src/main/java/org/apache/commons/rng/simple/internal/ProviderBuilder.java index 11399b9a..78e76548 100644 --- a/commons-rng-simple/src/main/java/org/apache/commons/rng/simple/internal/ProviderBuilder.java +++ b/commons-rng-simple/src/main/java/org/apache/commons/rng/simple/internal/ProviderBuilder.java @@ -30,6 +30,7 @@ import org.apache.commons.rng.core.source32.Well19937c; import org.apache.commons.rng.core.source32.Well44497a; import org.apache.commons.rng.core.source32.Well44497b; import org.apache.commons.rng.core.source32.ISAACRandom; +import org.apache.commons.rng.core.source32.IntProvider; import org.apache.commons.rng.core.source32.MersenneTwister; import org.apache.commons.rng.core.source32.MiddleSquareWeylSequence; import org.apache.commons.rng.core.source32.MultiplyWithCarry256; @@ -281,7 +282,33 @@ public final class ProviderBuilder { @Override protected byte[] createByteArraySeed(UniformRandomProvider source) { - return NativeSeedType.convertSeedToBytes(createMswsSeed(source)); + // The seed requires approximately 4-6 calls to nextInt(). + // Wrap the input and switch to a default if the input is faulty. + final UniformRandomProvider wrapped = new IntProvider() { + /** The number of remaining calls to the source generator. */ + private int calls = 100; + /** Default generator, initialised when required. */ + private UniformRandomProvider defaultGen; + @Override + public int next() { + if (calls == 0) { + // The input source is broken. + // Seed a default + if (defaultGen == null) { + defaultGen = new SplitMix64(source.nextLong()); + } + return defaultGen.nextInt(); + } + calls--; + return source.nextInt(); + } + @Override + public long nextLong() { + // No specific requirements so always use the source + return source.nextLong(); + } + }; + return NativeSeedType.convertSeedToBytes(createMswsSeed(wrapped)); } /** diff --git a/commons-rng-simple/src/test/java/org/apache/commons/rng/simple/RandomSourceTest.java b/commons-rng-simple/src/test/java/org/apache/commons/rng/simple/RandomSourceTest.java index e5e7ea71..5bb0c8ef 100644 --- a/commons-rng-simple/src/test/java/org/apache/commons/rng/simple/RandomSourceTest.java +++ b/commons-rng-simple/src/test/java/org/apache/commons/rng/simple/RandomSourceTest.java @@ -16,6 +16,8 @@ */ package org.apache.commons.rng.simple; +import java.time.Duration; +import org.apache.commons.rng.core.source64.LongProvider; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -80,4 +82,21 @@ class RandomSourceTest { Assertions.assertFalse(RandomSource.XOR_SHIFT_1024_S_PHI.isLongJumpable(), "XOR_SHIFT_1024_S_PHI is not LongJumpable"); Assertions.assertTrue(RandomSource.XO_SHI_RO_256_SS.isLongJumpable(), "XO_SHI_RO_256_SS is LongJumpable"); } + + /** + * MSWS should not infinite loop if the input RNG fails to provide randomness to create a seed. + * See RNG-175. + */ + @Test + void testMSWSCreateSeed() { + final LongProvider broken = new LongProvider() { + @Override + public long next() { + return 0; + } + }; + Assertions.assertTimeoutPreemptively(Duration.ofMillis(100), () -> { + RandomSource.MSWS.createSeed(broken); + }); + } } diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 0b0a08cf..f986aae4 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -86,6 +86,10 @@ behavioural compatibility between releases; derived types may break behavioural compatibility. Any functional changes will be recorded in the release notes. "> + <action dev="aherbert" type="fix" issue="175"> + "RandomSource.MSWS": createSeed(UniformRandomProvider) to handle a bad RNG. + This fixes an infinite loop when the RNG output is not suitably random to create a seed. + </action> <action dev="aherbert" type="add" issue="173"> "BaseProvider": Add a static method to extend input int[] and long[] seeds to a minimum length.
