Skip to content

Commit 60f238b

Browse files
committed
Handle exceeding max string size in string_multiply
- Detect when exceeding max string size in `string_multiply` and throw a `RangeException` when that happens. - Optimize `string_multiply` implementation. Fixes #1234.
1 parent 4ef81cc commit 60f238b

File tree

1 file changed

+28
-37
lines changed

1 file changed

+28
-37
lines changed

src/main/java/com/laytonsmith/core/functions/StringHandling.java

Lines changed: 28 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -2315,55 +2315,44 @@ public Mixed exec(Target t, Environment environment, Mixed... args) throws Confi
23152315
if(times == 0 || string.isEmpty()) {
23162316
return new CString("", t);
23172317
}
2318+
if(string.length() * times < 0) {
2319+
throw new CRERangeException("Maximum string size for return value exceeded. Max size: 2147483647,"
2320+
+ " required size: " + (times * (long) string.length()) + ".", t);
2321+
}
23182322
String s = repeat(string, times);
23192323
return new CString(s, t);
23202324
}
23212325

23222326
// Code taken from Apache Commons, and modified.
2323-
private static final int PAD_LIMIT = 8192;
2324-
23252327
private static String repeat(String str, int repeat) {
23262328
int inputLength = str.length();
23272329
if(repeat == 1 || inputLength == 0) {
23282330
return str;
23292331
}
2330-
if(inputLength == 1 && repeat <= PAD_LIMIT) {
2331-
return padding(repeat, str.charAt(0));
2332+
if(inputLength == 1) {
2333+
char ch = str.charAt(0);
2334+
final char[] buf = new char[repeat];
2335+
for(int i = 0; i < repeat; i++) {
2336+
buf[i] = ch;
2337+
}
2338+
return new String(buf);
23322339
}
2333-
23342340
int outputLength = inputLength * repeat;
2335-
switch(inputLength) {
2336-
case 1:
2337-
char ch = str.charAt(0);
2338-
char[] output1 = new char[outputLength];
2339-
for(int i = repeat - 1; i >= 0; i--) {
2340-
output1[i] = ch;
2341-
}
2342-
return new String(output1);
2343-
case 2:
2344-
char ch0 = str.charAt(0);
2345-
char ch1 = str.charAt(1);
2346-
char[] output2 = new char[outputLength];
2347-
for(int i = repeat * 2 - 2; i >= 0; i--, i--) {
2348-
output2[i] = ch0;
2349-
output2[i + 1] = ch1;
2350-
}
2351-
return new String(output2);
2352-
default:
2353-
StringBuilder buf = new StringBuilder(outputLength);
2354-
for(int i = 0; i < repeat; i++) {
2355-
buf.append(str);
2356-
}
2357-
return buf.toString();
2341+
if(inputLength == 2) {
2342+
char ch0 = str.charAt(0);
2343+
char ch1 = str.charAt(1);
2344+
char[] output2 = new char[outputLength];
2345+
for(int i = repeat * 2 - 2; i >= 0; i--, i--) {
2346+
output2[i] = ch0;
2347+
output2[i + 1] = ch1;
2348+
}
2349+
return new String(output2);
23582350
}
2359-
}
2360-
2361-
private static String padding(int repeat, char padChar) throws IndexOutOfBoundsException {
2362-
final char[] buf = new char[repeat];
2363-
for(int i = 0; i < buf.length; i++) {
2364-
buf[i] = padChar;
2351+
StringBuilder buf = new StringBuilder(outputLength);
2352+
for(int i = 0; i < repeat; i++) {
2353+
buf.append(str);
23652354
}
2366-
return new String(buf);
2355+
return buf.toString();
23672356
}
23682357

23692358
@Override
@@ -2382,8 +2371,10 @@ public String docs() {
23822371
+ " For instance, string_multiply('a', 3) returns 'aaa'. If the string"
23832372
+ " is empty, an empty string is returned. If the string is null, null"
23842373
+ " is returned. If times is 0, an empty string is returned."
2385-
+ " All other string values are multiplied accordingly. Providing"
2386-
+ " a value less than 0 for times results in a RangeException.";
2374+
+ " All other string values are multiplied accordingly."
2375+
+ " Providing a value less than 0 for times results in a RangeException."
2376+
+ " When the maximum string size of 2147483647 characters would be exceeded,"
2377+
+ " a RangeException is thrown.";
23872378
}
23882379

23892380
@Override

0 commit comments

Comments
 (0)