A DESCRIPTION OF THE PROBLEM :
The L128X256MixRandom(byte[]) constructor converts the byte[] to a long[]. The required state size is 8 longs. The current code uses 6 longs. The result is an ArrayIndexOutOfBoundsException is thrown by the byte[] constructor.
This code:
// Convert the seed to 6 long values, of which the last 4 are not all zero.
long[] data = RandomSupport.convertSeedBytesToLongs(seed, 6, 4);
Should be:
// Convert the seed to 8 long values, of which the last 4 are not all zero.
long[] data = RandomSupport.convertSeedBytesToLongs(seed, 8, 4);
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
This does not readily manifest in code. The RandomGeneratorFactory creates the generator using a try-catch block:
public T create(byte[] seed) {
Objects.requireNonNull(seed, "seed must not be null");
try {
ensureConstructors();
return ctorBytes.newInstance(seed);
} catch (Exception ex) {
return create();
}
}
The ArrayIndexOutOfBoundsException is caught and a default generator is constructed.
The generator should be the same when the same seed is used:
import java.util.random.*;
public class L128X256MixRandomBug {
public static void main(String[] args) {
byte[] seed = {1, 2, 3, 4, 5};
for (String name : new String[]{
"L32X64MixRandom",
"L64X128StarStarRandom",
"L64X128MixRandom",
"L64X256MixRandom",
"L64X1024MixRandom",
"L128X128MixRandom",
"L128X256MixRandom",
"L128X1024MixRandom",
}) {
// This should be reproducible
RandomGenerator g1 = RandomGeneratorFactory.of(name).create(seed);
RandomGenerator g2 = RandomGeneratorFactory.of(name).create(seed);
System.out.printf("%-21s is reproducible %b%n", name,
g1.nextLong() == g2.nextLong());
}
}
}
With access to the internal class it should be simple to show that:
// any byte[] length should fail
new L128X256MixRandom(new byte[3])
will throw an ArrayIndexOutOfBoundsException.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
> java L128X256MixRandomBug
L32X64MixRandom is reproducible true
L64X128StarStarRandom is reproducible true
L64X128MixRandom is reproducible true
L64X256MixRandom is reproducible true
L64X1024MixRandom is reproducible true
L128X128MixRandom is reproducible true
L128X256MixRandom is reproducible true
L128X1024MixRandom is reproducible true
ACTUAL -
> java L128X256MixRandomBug
L32X64MixRandom is reproducible true
L64X128StarStarRandom is reproducible true
L64X128MixRandom is reproducible true
L64X256MixRandom is reproducible true
L64X1024MixRandom is reproducible true
L128X128MixRandom is reproducible true
L128X256MixRandom is reproducible false
L128X1024MixRandom is reproducible true
---------- BEGIN SOURCE ----------
Driver program provided.
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
None. The user will be unaware that the input byte[] has been ignored and a default instance was returned.
FREQUENCY : always
The L128X256MixRandom(byte[]) constructor converts the byte[] to a long[]. The required state size is 8 longs. The current code uses 6 longs. The result is an ArrayIndexOutOfBoundsException is thrown by the byte[] constructor.
This code:
// Convert the seed to 6 long values, of which the last 4 are not all zero.
long[] data = RandomSupport.convertSeedBytesToLongs(seed, 6, 4);
Should be:
// Convert the seed to 8 long values, of which the last 4 are not all zero.
long[] data = RandomSupport.convertSeedBytesToLongs(seed, 8, 4);
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
This does not readily manifest in code. The RandomGeneratorFactory creates the generator using a try-catch block:
public T create(byte[] seed) {
Objects.requireNonNull(seed, "seed must not be null");
try {
ensureConstructors();
return ctorBytes.newInstance(seed);
} catch (Exception ex) {
return create();
}
}
The ArrayIndexOutOfBoundsException is caught and a default generator is constructed.
The generator should be the same when the same seed is used:
import java.util.random.*;
public class L128X256MixRandomBug {
public static void main(String[] args) {
byte[] seed = {1, 2, 3, 4, 5};
for (String name : new String[]{
"L32X64MixRandom",
"L64X128StarStarRandom",
"L64X128MixRandom",
"L64X256MixRandom",
"L64X1024MixRandom",
"L128X128MixRandom",
"L128X256MixRandom",
"L128X1024MixRandom",
}) {
// This should be reproducible
RandomGenerator g1 = RandomGeneratorFactory.of(name).create(seed);
RandomGenerator g2 = RandomGeneratorFactory.of(name).create(seed);
System.out.printf("%-21s is reproducible %b%n", name,
g1.nextLong() == g2.nextLong());
}
}
}
With access to the internal class it should be simple to show that:
// any byte[] length should fail
new L128X256MixRandom(new byte[3])
will throw an ArrayIndexOutOfBoundsException.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
> java L128X256MixRandomBug
L32X64MixRandom is reproducible true
L64X128StarStarRandom is reproducible true
L64X128MixRandom is reproducible true
L64X256MixRandom is reproducible true
L64X1024MixRandom is reproducible true
L128X128MixRandom is reproducible true
L128X256MixRandom is reproducible true
L128X1024MixRandom is reproducible true
ACTUAL -
> java L128X256MixRandomBug
L32X64MixRandom is reproducible true
L64X128StarStarRandom is reproducible true
L64X128MixRandom is reproducible true
L64X256MixRandom is reproducible true
L64X1024MixRandom is reproducible true
L128X128MixRandom is reproducible true
L128X256MixRandom is reproducible false
L128X1024MixRandom is reproducible true
---------- BEGIN SOURCE ----------
Driver program provided.
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
None. The user will be unaware that the input byte[] has been ignored and a default instance was returned.
FREQUENCY : always