Исправление множественных Array.copy при которых обработка больших строк могла приводить к падению сервера
All checks were successful
Build rosetta-wss / build (push) Successful in 1m51s

This commit is contained in:
RoyceDa
2026-03-25 20:58:53 +02:00
parent 0cd01ebd01
commit ec888611a1

View File

@@ -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);
}
}