-
Bug
-
Resolution: Fixed
-
P3
-
17
-
b15
-
generic
-
generic
-
Verified
Issue | Fix Version | Assignee | Priority | Status | Resolution | Resolved In Build |
---|---|---|---|---|---|---|
JDK-8313409 | 17.0.10-oracle | Johny Jose | P3 | Resolved | Fixed | b02 |
JDK-8279151 | 17.0.3 | Aleksey Shipilev | P3 | Resolved | Fixed | b01 |
A DESCRIPTION OF THE PROBLEM :
Class: java.base/jdk/internal/util/random/RandomSupport.java
Internal Class: RandomSupport.AbstractSplittableWithBrineGenerator
Method: makeSplitsSpliterator
This method is intending to create a salt from a random long. The salt should have random letters of size 4 for each consecutive 4 bits and then the last 4 bits as ff, i.e. all bits set.
However the loop is never executed, the random bits are not used and the salt is always the same.
This condition is false on the first execution:
long multiplier = (1L << SALT_SHIFT) - 1;
long salt = multiplier << (64 - SALT_SHIFT);
while ((salt & multiplier) != 0) {
multiplier == 0xffL
salt == 0xff00_0000_0000_0000L
The bitwise AND returns false and the salt is kept as the initial value.
I believe the intention is to keep shifting the ff digit in the salt to the right while appending random 4 bit digits at the top of the salt. When the initial ff digit reaches the least significant bits then this is detected and the loop stops.
This can be corrected by changing:
while ((salt & multiplier) != 0) {
to
while ((salt & multiplier) == 0) {
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
I am not familiar with how to make this bug manifest in code. It will apply to splittable generators. I believe the intention is that a call to 'SplittableGenerator#splits()' will create a stream of generators that will have a distinct state cycle (because the salt is random and unique). However the salt will not be random and so successive calls to splits() will create streams of generators that are all using the same state cycle. However given that the salt is only part of the seed state then the output from the generators will still be random and different.
Here is test code for the salt generation:
@Test
public void testSalt() {
SplittableRandom rng = new SplittableRandom(42L);
for (int shift = 3; shift <= 5; shift++) {
for (int i = 0; i < 10; i++) {
long bits = rng.nextLong();
System.out.printf("%d %22d -> %22d or %22d%n", shift, bits, getSalt1(shift, bits), getSalt2(shift, bits));
}
}
}
private static long getSalt1(int SALT_SHIFT, long bits) {
long multiplier = (1L << SALT_SHIFT) - 1;
long salt = multiplier << (64 - SALT_SHIFT);
while ((salt & multiplier) != 0) {
long digit = Math.multiplyHigh(bits, multiplier);
salt = (salt >>> SALT_SHIFT) | (digit << (64 - SALT_SHIFT));
bits *= multiplier;
}
return salt;
}
private static long getSalt2(int SALT_SHIFT, long bits) {
long multiplier = (1L << SALT_SHIFT) - 1;
long salt = multiplier << (64 - SALT_SHIFT);
while ((salt & multiplier) == 0) {
long digit = Math.multiplyHigh(bits, multiplier);
salt = (salt >>> SALT_SHIFT) | (digit << (64 - SALT_SHIFT));
bits *= multiplier;
}
return salt;
}
This will output the same salt using the current implementation or a random salt using the updated version:
3 -4767286540954276203 -> -2305843009213693952 or 4349124269383043310
3 2949826092126892291 -> -2305843009213693952 or 8945531224453011486
3 5139283748462763858 -> -2305843009213693952 or 517819905960023966
3 6349198060258255764 -> -2305843009213693952 or -6659264277579162322
3 701532786141963250 -> -2305843009213693952 or 5085857321298041998
3 -2430762948046562554 -> -2305843009213693952 or -7817602704379359106
3 4028864712777624925 -> -2305843009213693952 or -2622394274348337634
3 -3677692746721775708 -> -2305843009213693952 or 2708571132827182830
3 6270620877612482005 -> -2305843009213693952 or 5716212649416045870
3 -7037763681458882642 -> -2305843009213693952 or -2998217625047725730
4 3779771651426294207 -> -1152921504606846976 or 212116472798449983
4 9094045341461139646 -> -1152921504606846976 or -3440073421829053057
4 -8976257307478440218 -> -1152921504606846976 or -7620503532181156977
4 -8854191821003330121 -> -1152921504606846976 or 8417340289440550287
4 -6176718654468026660 -> -1152921504606846976 or -5759382560450891857
4 3752715396868486130 -> -1152921504606846976 or 1725956634110967871
4 1910607418205583989 -> -1152921504606846976 or 2729220554143385887
4 9140336935745592861 -> -1152921504606846976 or -7417744488025262465
4 1723436047706647047 -> -1152921504606846976 or 7718206646484469279
4 -5737926661510088608 -> -1152921504606846976 or 4401412089535661503
5 -787210419263134744 -> -576460752303423488 or 8568385709579009520
5 1347604182271487641 -> -576460752303423488 or -1429488610206153232
5 -7382086223805147691 -> -576460752303423488 or -737100742167566352
5 -7013100964912248687 -> -576460752303423488 or -5246235741689107984
5 1368025501988796752 -> -576460752303423488 or 3035404726796699120
5 5120214421805786385 -> -576460752303423488 or -7156035961266843152
5 -4759641710321948619 -> -576460752303423488 or -4432805587863457296
5 -3956836574347814625 -> -576460752303423488 or 7601807688214426608
5 -1071251766013039353 -> -576460752303423488 or 4194725726029200880
5 -5641428018500444605 -> -576460752303423488 or 1152243442133003760
---------- BEGIN SOURCE ----------
Given that the salt member variable is package private it should be possible to construct a RandomSplitsSpliteratorWithSalt class using the AbstractSplittableWithBrineGenerator.makeSplitsSpliterator method and assert that the salt is always the same.
---------- END SOURCE ----------
Class: java.base/jdk/internal/util/random/RandomSupport.java
Internal Class: RandomSupport.AbstractSplittableWithBrineGenerator
Method: makeSplitsSpliterator
This method is intending to create a salt from a random long. The salt should have random letters of size 4 for each consecutive 4 bits and then the last 4 bits as ff, i.e. all bits set.
However the loop is never executed, the random bits are not used and the salt is always the same.
This condition is false on the first execution:
long multiplier = (1L << SALT_SHIFT) - 1;
long salt = multiplier << (64 - SALT_SHIFT);
while ((salt & multiplier) != 0) {
multiplier == 0xffL
salt == 0xff00_0000_0000_0000L
The bitwise AND returns false and the salt is kept as the initial value.
I believe the intention is to keep shifting the ff digit in the salt to the right while appending random 4 bit digits at the top of the salt. When the initial ff digit reaches the least significant bits then this is detected and the loop stops.
This can be corrected by changing:
while ((salt & multiplier) != 0) {
to
while ((salt & multiplier) == 0) {
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
I am not familiar with how to make this bug manifest in code. It will apply to splittable generators. I believe the intention is that a call to 'SplittableGenerator#splits()' will create a stream of generators that will have a distinct state cycle (because the salt is random and unique). However the salt will not be random and so successive calls to splits() will create streams of generators that are all using the same state cycle. However given that the salt is only part of the seed state then the output from the generators will still be random and different.
Here is test code for the salt generation:
@Test
public void testSalt() {
SplittableRandom rng = new SplittableRandom(42L);
for (int shift = 3; shift <= 5; shift++) {
for (int i = 0; i < 10; i++) {
long bits = rng.nextLong();
System.out.printf("%d %22d -> %22d or %22d%n", shift, bits, getSalt1(shift, bits), getSalt2(shift, bits));
}
}
}
private static long getSalt1(int SALT_SHIFT, long bits) {
long multiplier = (1L << SALT_SHIFT) - 1;
long salt = multiplier << (64 - SALT_SHIFT);
while ((salt & multiplier) != 0) {
long digit = Math.multiplyHigh(bits, multiplier);
salt = (salt >>> SALT_SHIFT) | (digit << (64 - SALT_SHIFT));
bits *= multiplier;
}
return salt;
}
private static long getSalt2(int SALT_SHIFT, long bits) {
long multiplier = (1L << SALT_SHIFT) - 1;
long salt = multiplier << (64 - SALT_SHIFT);
while ((salt & multiplier) == 0) {
long digit = Math.multiplyHigh(bits, multiplier);
salt = (salt >>> SALT_SHIFT) | (digit << (64 - SALT_SHIFT));
bits *= multiplier;
}
return salt;
}
This will output the same salt using the current implementation or a random salt using the updated version:
3 -4767286540954276203 -> -2305843009213693952 or 4349124269383043310
3 2949826092126892291 -> -2305843009213693952 or 8945531224453011486
3 5139283748462763858 -> -2305843009213693952 or 517819905960023966
3 6349198060258255764 -> -2305843009213693952 or -6659264277579162322
3 701532786141963250 -> -2305843009213693952 or 5085857321298041998
3 -2430762948046562554 -> -2305843009213693952 or -7817602704379359106
3 4028864712777624925 -> -2305843009213693952 or -2622394274348337634
3 -3677692746721775708 -> -2305843009213693952 or 2708571132827182830
3 6270620877612482005 -> -2305843009213693952 or 5716212649416045870
3 -7037763681458882642 -> -2305843009213693952 or -2998217625047725730
4 3779771651426294207 -> -1152921504606846976 or 212116472798449983
4 9094045341461139646 -> -1152921504606846976 or -3440073421829053057
4 -8976257307478440218 -> -1152921504606846976 or -7620503532181156977
4 -8854191821003330121 -> -1152921504606846976 or 8417340289440550287
4 -6176718654468026660 -> -1152921504606846976 or -5759382560450891857
4 3752715396868486130 -> -1152921504606846976 or 1725956634110967871
4 1910607418205583989 -> -1152921504606846976 or 2729220554143385887
4 9140336935745592861 -> -1152921504606846976 or -7417744488025262465
4 1723436047706647047 -> -1152921504606846976 or 7718206646484469279
4 -5737926661510088608 -> -1152921504606846976 or 4401412089535661503
5 -787210419263134744 -> -576460752303423488 or 8568385709579009520
5 1347604182271487641 -> -576460752303423488 or -1429488610206153232
5 -7382086223805147691 -> -576460752303423488 or -737100742167566352
5 -7013100964912248687 -> -576460752303423488 or -5246235741689107984
5 1368025501988796752 -> -576460752303423488 or 3035404726796699120
5 5120214421805786385 -> -576460752303423488 or -7156035961266843152
5 -4759641710321948619 -> -576460752303423488 or -4432805587863457296
5 -3956836574347814625 -> -576460752303423488 or 7601807688214426608
5 -1071251766013039353 -> -576460752303423488 or 4194725726029200880
5 -5641428018500444605 -> -576460752303423488 or 1152243442133003760
---------- BEGIN SOURCE ----------
Given that the salt member variable is package private it should be possible to construct a RandomSplitsSpliteratorWithSalt class using the AbstractSplittableWithBrineGenerator.makeSplitsSpliterator method and assert that the salt is always the same.
---------- END SOURCE ----------
- backported by
-
JDK-8279151 AbstractSplittableWithBrineGenerator does not create a random salt
- Resolved
-
JDK-8313409 AbstractSplittableWithBrineGenerator does not create a random salt
- Resolved
- csr for
-
JDK-8273183 AbstractSplittableWithBrineGenerator does not create a random salt
- Closed
- links to
-
Commit openjdk/jdk17u-dev/83f1749b
-
Commit openjdk/jdk/5e1df2c7
-
Review openjdk/jdk17u-dev/6
-
Review openjdk/jdk17u/288
-
Review openjdk/jdk/5449
(3 links to)