Исправление множественных 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;
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user