Исправление множественных 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; package io.orprotocol;
import java.util.Arrays;
public class Stream { public class Stream {
private byte[] stream; private byte[] stream;
@@ -15,11 +17,12 @@ public class Stream {
} }
public byte[] getStream() { public byte[] getStream() {
return this.stream; return Arrays.copyOf(this.stream, length());
} }
public void setStream(byte[] stream) { public void setStream(byte[] stream) {
this.stream = stream; this.stream = stream;
this.writePointer = this.stream.length << 3;
} }
public void writeInt8(int value) { public void writeInt8(int value) {
@@ -27,13 +30,13 @@ public class Stream {
int int8Value = Math.abs(value) & 0xFF; int int8Value = Math.abs(value) & 0xFF;
ensureCapacity(writePointer >> 3); ensureCapacity(writePointer >> 3);
stream[writePointer >> 3] |= (byte)(negationBit << (7 - (writePointer & 7))); stream[writePointer >> 3] |= (byte) (negationBit << (7 - (writePointer & 7)));
writePointer++; writePointer++;
for (int i = 0; i < 8; i++) { for (int i = 0; i < 8; i++) {
int bit = (int8Value >> (7 - i)) & 1; int bit = (int8Value >> (7 - i)) & 1;
ensureCapacity(writePointer >> 3); ensureCapacity(writePointer >> 3);
stream[writePointer >> 3] |= (byte)(bit << (7 - (writePointer & 7))); stream[writePointer >> 3] |= (byte) (bit << (7 - (writePointer & 7)));
writePointer++; writePointer++;
} }
} }
@@ -55,7 +58,7 @@ public class Stream {
public void writeBit(int value) { public void writeBit(int value) {
int bit = value & 1; int bit = value & 1;
ensureCapacity(writePointer >> 3); ensureCapacity(writePointer >> 3);
stream[writePointer >> 3] |= (byte)(bit << (7 - (writePointer & 7))); stream[writePointer >> 3] |= (byte) (bit << (7 - (writePointer & 7)));
writePointer++; writePointer++;
} }
@@ -94,8 +97,8 @@ public class Stream {
} }
public void writeInt64(long value) { public void writeInt64(long value) {
int high = (int)(value >> 32); int high = (int) (value >> 32);
int low = (int)value; int low = (int) value;
writeInt32(high); writeInt32(high);
writeInt32(low); writeInt32(low);
} }
@@ -119,29 +122,47 @@ public class Stream {
public void writeString(String value) { public void writeString(String value) {
int length = value.length(); int length = value.length();
writeInt32(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)); writeInt16(value.charAt(i));
} }
} }
public String readString() { public String readString() {
int length = readInt32(); int length = readInt32();
// Security fix for string length exceeding stream capacity if (length < 0) {
if (length < 0 || length > (stream.length - (readPointer >> 3))) {
System.out.println("Stream readString length invalid: " + length + ", stream length: " + stream.length + ", readPointer: " + readPointer);
return ""; 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++) { for (int i = 0; i < length; i++) {
value.append((char)readInt16()); value.append((char) readInt16());
} }
return value.toString(); return value.toString();
} }
public void writeBytes(byte[] value) { public void writeBytes(byte[] value) {
writeInt32(value.length); writeInt32(value.length);
if (value.length > 0) {
reserveBits((long) value.length * 9L);
}
for (int i = 0; i < value.length; i++) { for (int i = 0; i < value.length; i++) {
writeInt8(value[i]); writeInt8(value[i]);
} }
@@ -149,9 +170,13 @@ public class Stream {
public byte[] readBytes() { public byte[] readBytes() {
int length = readInt32(); int length = readInt32();
if (length < 0) {
return new byte[0];
}
byte[] value = new byte[length]; byte[] value = new byte[length];
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
value[i] = (byte)readInt8(); value[i] = (byte) readInt8();
} }
return value; return value;
} }
@@ -161,19 +186,46 @@ public class Stream {
} }
public int length() { public int length() {
return this.stream.length; return (writePointer + 7) >> 3;
} }
public byte[] getBuffer() { public byte[] getBuffer() {
return this.stream; return this.stream;
} }
private void ensureCapacity(int byteIndex) { private void reserveBits(long bitsToWrite) {
if (byteIndex >= stream.length) { if (bitsToWrite <= 0) {
byte[] newStream = new byte[byteIndex + 1]; return;
System.arraycopy(stream, 0, newStream, 0, stream.length);
stream = newStream;
} }
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);
}
}