Fix for LANG-1286: RandomStringUtils random method can overflow...
This commit is contained in:
parent
f13d18cff3
commit
f643b4fa93
|
@ -46,6 +46,7 @@ The <action> type attribute can be add,update,fix,remove.
|
|||
<body>
|
||||
|
||||
<release version="3.6" date="2016-MM-DD" description="TBD">
|
||||
<action issue="LANG-1286" type="fix" dev="djones">RandomStringUtils random method can overflow and return characters outside of specified range</action>
|
||||
<action issue="LANG-660" type="add" dev="djones">Add methods to insert arrays into arrays at an index</action>
|
||||
<action issue="LANG-1292" type="fix" dev="djones">WordUtils.wrap throws StringIndexOutOfBoundsException</action>
|
||||
<action issue="LANG-1287" type="fix" dev="pschumacher" due-to="Ivan Morozov">RandomStringUtils#random can enter infinite loop if end parameter is to small</action>
|
||||
|
|
|
@ -315,7 +315,7 @@ public class RandomStringUtils {
|
|||
* to {@code ' '} and {@code 'z'}, the ASCII printable
|
||||
* characters, will be used, unless letters and numbers are both
|
||||
* {@code false}, in which case, start and end are set to
|
||||
* {@code 0} and {@code Integer.MAX_VALUE}.
|
||||
* {@code 0} and {@link Character#MAX_CODE_POINT}.
|
||||
*
|
||||
* <p>If set is not {@code null}, characters between start and
|
||||
* end are chosen.</p>
|
||||
|
@ -356,7 +356,7 @@ public class RandomStringUtils {
|
|||
end = chars.length;
|
||||
} else {
|
||||
if (!letters && !numbers) {
|
||||
end = Integer.MAX_VALUE;
|
||||
end = Character.MAX_CODE_POINT;
|
||||
} else {
|
||||
end = 'z' + 1;
|
||||
start = ' ';
|
||||
|
@ -379,50 +379,49 @@ public class RandomStringUtils {
|
|||
}
|
||||
}
|
||||
|
||||
final char[] buffer = new char[count];
|
||||
StringBuffer buffer = new StringBuffer(count);
|
||||
final int gap = end - start;
|
||||
|
||||
while (count-- != 0) {
|
||||
char ch;
|
||||
int codePoint;
|
||||
if (chars == null) {
|
||||
ch = (char) (random.nextInt(gap) + start);
|
||||
} else {
|
||||
ch = chars[random.nextInt(gap) + start];
|
||||
}
|
||||
if (letters && Character.isLetter(ch)
|
||||
|| numbers && Character.isDigit(ch)
|
||||
|| !letters && !numbers) {
|
||||
if(ch >= 56320 && ch <= 57343) {
|
||||
if(count == 0) {
|
||||
count++;
|
||||
} else {
|
||||
// low surrogate, insert high surrogate after putting it in
|
||||
buffer[count] = ch;
|
||||
count--;
|
||||
buffer[count] = (char) (55296 + random.nextInt(128));
|
||||
}
|
||||
} else if(ch >= 55296 && ch <= 56191) {
|
||||
if(count == 0) {
|
||||
count++;
|
||||
} else {
|
||||
// high surrogate, insert low surrogate before putting it in
|
||||
buffer[count] = (char) (56320 + random.nextInt(128));
|
||||
count--;
|
||||
buffer[count] = ch;
|
||||
}
|
||||
} else if(ch >= 56192 && ch <= 56319) {
|
||||
// private high surrogate, no effing clue, so skip it
|
||||
codePoint = random.nextInt(gap) + start;
|
||||
|
||||
switch (Character.getType(codePoint)) {
|
||||
case Character.UNASSIGNED:
|
||||
case Character.PRIVATE_USE:
|
||||
case Character.SURROGATE:
|
||||
count++;
|
||||
} else {
|
||||
buffer[count] = ch;
|
||||
continue;
|
||||
}
|
||||
|
||||
} else {
|
||||
codePoint = chars[random.nextInt(gap) + start];
|
||||
}
|
||||
|
||||
final int numberOfChars = Character.charCount(codePoint);
|
||||
if (count == 0 && numberOfChars > 1) {
|
||||
count++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (letters && Character.isLetter(codePoint)
|
||||
|| numbers && Character.isDigit(codePoint)
|
||||
|| !letters && !numbers) {
|
||||
buffer.appendCodePoint(codePoint);
|
||||
|
||||
if (numberOfChars == 2) {
|
||||
count--;
|
||||
}
|
||||
|
||||
} else {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return new String(buffer);
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* <p>Creates a random string whose length is the number of characters
|
||||
* specified.</p>
|
||||
|
|
|
@ -533,5 +533,32 @@ public class RandomStringUtilsTest {
|
|||
// just to be complete
|
||||
assertEquals(orig, copy);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test for LANG-1286. Creates situation where old code would
|
||||
* overflow a char and result in a code point outside the specified
|
||||
* range.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void testCharOverflow() throws Exception {
|
||||
int start = Character.MAX_VALUE;
|
||||
int end = Integer.MAX_VALUE;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
Random fixedRandom = new Random() {
|
||||
@Override
|
||||
public int nextInt(int n) {
|
||||
// Prevents selection of 'start' as the character
|
||||
return super.nextInt(n - 1) + 1;
|
||||
}
|
||||
};
|
||||
|
||||
String result = RandomStringUtils.random(2, start, end, false, false, null, fixedRandom);
|
||||
int c = result.codePointAt(0);
|
||||
assertTrue(String.format("Character '%d' not in range [%d,%d).", c, start, end), c >= start && c < end);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue