HHH-13259 Fix StackOverflowError in StringHelper

Before fix method org.hibernate.internal.util.StringHelper#replace
matched placeholders illegally in case when ordinal parameters list was
expanded. Ex. placeholder ?1 was matched with ?11, ?12, ?13 etc. For
queries with 2 or more IN clauses with different collections there were
a situation when ?1 from the first clause matched with already expanded
placeholders from the second collection. Each match led to recursive
call of replace method. If collection in second clause was very long
then StackOverflowError occurred.

Fix adds check of partial placeholder match for wholeWords mode which
is used in expanding list parameters. Partial matches are skipped
during replace.
This commit is contained in:
Legohuman 2019-08-10 00:33:24 +02:00 committed by Sanne Grinovero
parent fed93b0ae9
commit 35037dac7b
2 changed files with 39 additions and 1 deletions

View File

@ -123,7 +123,7 @@ public final class StringHelper {
if ( template == null ) {
return null;
}
int loc = template.indexOf( placeholder );
int loc = indexOfPlaceHolder( template, placeholder, wholeWords );
if ( loc < 0 ) {
return template;
}
@ -189,6 +189,24 @@ public final class StringHelper {
return buf.toString();
}
private static int indexOfPlaceHolder(String template, String placeholder, boolean wholeWords) {
if ( wholeWords ) {
int placeholderIndex = -1;
boolean isPartialPlaceholderMatch;
do {
placeholderIndex = template.indexOf( placeholder, placeholderIndex + 1 );
isPartialPlaceholderMatch = placeholderIndex != -1 &&
template.length() > placeholderIndex + placeholder.length() &&
Character.isJavaIdentifierPart( template.charAt( placeholderIndex + placeholder.length() ) );
} while ( placeholderIndex != -1 && isPartialPlaceholderMatch );
return placeholderIndex;
}
else {
return template.indexOf( placeholder );
}
}
/**
* Used to find the ordinal parameters (e.g. '?1') in a string.
*/

View File

@ -100,4 +100,24 @@ public class StringHelperTest extends BaseUnitTestCase {
Assert.assertFalse( StringHelper.isQuoted( "a", sqlServerDialect ) );
}
@Test
public void replaceRepeatingPlaceholdersWithoutStackOverflow() {
String ordinalParameters = generateOrdinalParameters( 3, 19999 );
String result = StringHelper.replace(
"select * from books where category in (?1) and id in(" + ordinalParameters + ") and parent_category in (?1) and id in(" + ordinalParameters + ")",
"?1", "?1, ?2", true, true );
assertEquals( "select * from books where category in (?1, ?2) and id in(" + ordinalParameters + ") and parent_category in (?1, ?2) and id in(" + ordinalParameters + ")", result );
}
private String generateOrdinalParameters(int startPosition, int endPosition) {
StringBuilder builder = new StringBuilder();
for ( int i = startPosition; i <= endPosition; i++ ) {
builder.append( '?' ).append( i );
if ( i < endPosition ) {
builder.append( ", " );
}
}
return builder.toString();
}
}