Исправление множественных Array.copy при которых обработка больших строк могла приводить к падению сервера
All checks were successful
Build rosetta-wss / build (push) Successful in 1m51s
All checks were successful
Build rosetta-wss / build (push) Successful in 1m51s
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
package io.orprotocol;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class Stream {
|
||||
|
||||
private byte[] stream;
|
||||
@@ -15,11 +17,12 @@ public class Stream {
|
||||
}
|
||||
|
||||
public byte[] getStream() {
|
||||
return this.stream;
|
||||
return Arrays.copyOf(this.stream, length());
|
||||
}
|
||||
|
||||
public void setStream(byte[] stream) {
|
||||
this.stream = stream;
|
||||
this.writePointer = this.stream.length << 3;
|
||||
}
|
||||
|
||||
public void writeInt8(int value) {
|
||||
@@ -119,7 +122,15 @@ public class Stream {
|
||||
public void writeString(String value) {
|
||||
int length = value.length();
|
||||
writeInt32(length);
|
||||
for (int i = 0; i < value.length(); i++) {
|
||||
|
||||
if (length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// writeInt16 -> 2 * writeInt8 -> 18 бит на символ
|
||||
reserveBits((long) length * 18L);
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
writeInt16(value.charAt(i));
|
||||
}
|
||||
}
|
||||
@@ -127,13 +138,18 @@ public class Stream {
|
||||
public String readString() {
|
||||
int length = readInt32();
|
||||
|
||||
// Security fix for string length exceeding stream capacity
|
||||
if (length < 0 || length > (stream.length - (readPointer >> 3))) {
|
||||
System.out.println("Stream readString length invalid: " + length + ", stream length: " + stream.length + ", readPointer: " + readPointer);
|
||||
if (length < 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
StringBuilder value = new StringBuilder();
|
||||
// На один символ тратится 18 бит (через writeInt16/readInt16)
|
||||
long remainingBits = ((long) stream.length << 3) - readPointer;
|
||||
long requiredBits = (long) length * 18L;
|
||||
if (requiredBits > remainingBits) {
|
||||
return "";
|
||||
}
|
||||
|
||||
StringBuilder value = new StringBuilder(length);
|
||||
for (int i = 0; i < length; i++) {
|
||||
value.append((char) readInt16());
|
||||
}
|
||||
@@ -142,6 +158,11 @@ public class Stream {
|
||||
|
||||
public void writeBytes(byte[] value) {
|
||||
writeInt32(value.length);
|
||||
|
||||
if (value.length > 0) {
|
||||
reserveBits((long) value.length * 9L);
|
||||
}
|
||||
|
||||
for (int i = 0; i < value.length; i++) {
|
||||
writeInt8(value[i]);
|
||||
}
|
||||
@@ -149,6 +170,10 @@ public class Stream {
|
||||
|
||||
public byte[] readBytes() {
|
||||
int length = readInt32();
|
||||
if (length < 0) {
|
||||
return new byte[0];
|
||||
}
|
||||
|
||||
byte[] value = new byte[length];
|
||||
for (int i = 0; i < length; i++) {
|
||||
value[i] = (byte) readInt8();
|
||||
@@ -161,19 +186,46 @@ public class Stream {
|
||||
}
|
||||
|
||||
public int length() {
|
||||
return this.stream.length;
|
||||
return (writePointer + 7) >> 3;
|
||||
}
|
||||
|
||||
public byte[] getBuffer() {
|
||||
return this.stream;
|
||||
}
|
||||
|
||||
private void ensureCapacity(int byteIndex) {
|
||||
if (byteIndex >= stream.length) {
|
||||
byte[] newStream = new byte[byteIndex + 1];
|
||||
System.arraycopy(stream, 0, newStream, 0, stream.length);
|
||||
stream = newStream;
|
||||
}
|
||||
private void reserveBits(long bitsToWrite) {
|
||||
if (bitsToWrite <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
long lastBitIndex = (long) writePointer + bitsToWrite - 1;
|
||||
if (lastBitIndex < 0) {
|
||||
throw new IllegalStateException("Bit index overflow");
|
||||
}
|
||||
|
||||
long byteIndexLong = lastBitIndex >> 3;
|
||||
if (byteIndexLong > Integer.MAX_VALUE) {
|
||||
throw new IllegalStateException("Stream too large");
|
||||
}
|
||||
|
||||
ensureCapacity((int) byteIndexLong);
|
||||
}
|
||||
|
||||
private void ensureCapacity(int byteIndex) {
|
||||
int requiredSize = byteIndex + 1;
|
||||
if (requiredSize <= stream.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
int newSize = (stream.length == 0) ? 32 : stream.length;
|
||||
while (newSize < requiredSize) {
|
||||
if (newSize > (Integer.MAX_VALUE / 2)) {
|
||||
newSize = requiredSize;
|
||||
break;
|
||||
}
|
||||
newSize <<= 1;
|
||||
}
|
||||
|
||||
stream = Arrays.copyOf(stream, newSize);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user