mirror of
https://github.com/PaperMC/Velocity.git
synced 2026-02-17 06:27:42 +01:00
Fix ByteBuf memory leak in MinecraftVarintFrameDecoder (#1715)
- Reset buffer reader index on exception to prevent memory leaks when packet decoding fails.
This commit is contained in:
@@ -91,29 +91,35 @@ public class MinecraftVarintFrameDecoder extends ByteToMessageDecoder {
|
|||||||
|
|
||||||
// try to read the length of the packet
|
// try to read the length of the packet
|
||||||
in.markReaderIndex();
|
in.markReaderIndex();
|
||||||
int length = readRawVarInt21(in);
|
try {
|
||||||
if (packetStart == in.readerIndex()) {
|
int length = readRawVarInt21(in);
|
||||||
return;
|
if (packetStart == in.readerIndex()) {
|
||||||
}
|
return;
|
||||||
if (length < 0) {
|
}
|
||||||
throw BAD_PACKET_LENGTH;
|
if (length < 0) {
|
||||||
}
|
throw BAD_PACKET_LENGTH;
|
||||||
|
}
|
||||||
|
|
||||||
if (length > 0) {
|
if (length > 0) {
|
||||||
if (state == StateRegistry.HANDSHAKE && direction == ProtocolUtils.Direction.SERVERBOUND) {
|
if (state == StateRegistry.HANDSHAKE && direction == ProtocolUtils.Direction.SERVERBOUND) {
|
||||||
if (validateServerboundHandshakePacket(in, length)) {
|
if (validateServerboundHandshakePacket(in, length)) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// note that zero-length packets are ignored
|
// note that zero-length packets are ignored
|
||||||
if (length > 0) {
|
if (length > 0) {
|
||||||
if (in.readableBytes() < length) {
|
if (in.readableBytes() < length) {
|
||||||
in.resetReaderIndex();
|
in.resetReaderIndex();
|
||||||
} else {
|
} else {
|
||||||
out.add(in.readRetainedSlice(length));
|
out.add(in.readRetainedSlice(length));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
// Reset buffer to consistent state before propagating exception to prevent memory leaks
|
||||||
|
in.resetReaderIndex();
|
||||||
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,34 +128,40 @@ public class MinecraftVarintFrameDecoder extends ByteToMessageDecoder {
|
|||||||
state.getProtocolRegistry(direction, ProtocolVersion.MINIMUM_VERSION);
|
state.getProtocolRegistry(direction, ProtocolVersion.MINIMUM_VERSION);
|
||||||
|
|
||||||
final int index = in.readerIndex();
|
final int index = in.readerIndex();
|
||||||
final int packetId = readRawVarInt21(in);
|
try {
|
||||||
// Index hasn't changed, we've read nothing
|
final int packetId = readRawVarInt21(in);
|
||||||
if (index == in.readerIndex()) {
|
// Index hasn't changed, we've read nothing
|
||||||
in.resetReaderIndex();
|
if (index == in.readerIndex()) {
|
||||||
return true;
|
in.resetReaderIndex();
|
||||||
}
|
return true;
|
||||||
final int payloadLength = length - ProtocolUtils.varIntBytes(packetId);
|
}
|
||||||
|
final int payloadLength = length - ProtocolUtils.varIntBytes(packetId);
|
||||||
|
|
||||||
MinecraftPacket packet = registry.createPacket(packetId);
|
MinecraftPacket packet = registry.createPacket(packetId);
|
||||||
|
|
||||||
// We handle every packet in this phase, if you said something we don't know, something is really wrong
|
// We handle every packet in this phase, if you said something we don't know, something is really wrong
|
||||||
if (packet == null) {
|
if (packet == null) {
|
||||||
throw UNKNOWN_PACKET;
|
throw UNKNOWN_PACKET;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We 'technically' have the incoming bytes of a payload here, and so, these can actually parse
|
// We 'technically' have the incoming bytes of a payload here, and so, these can actually parse
|
||||||
// the packet if needed, so, we'll take advantage of the existing methods
|
// the packet if needed, so, we'll take advantage of the existing methods
|
||||||
int expectedMinLen = packet.decodeExpectedMinLength(in, direction, registry.version);
|
int expectedMinLen = packet.decodeExpectedMinLength(in, direction, registry.version);
|
||||||
int expectedMaxLen = packet.decodeExpectedMaxLength(in, direction, registry.version);
|
int expectedMaxLen = packet.decodeExpectedMaxLength(in, direction, registry.version);
|
||||||
if (expectedMaxLen != -1 && payloadLength > expectedMaxLen) {
|
if (expectedMaxLen != -1 && payloadLength > expectedMaxLen) {
|
||||||
throw handleOverflow(packet, expectedMaxLen, in.readableBytes());
|
throw handleOverflow(packet, expectedMaxLen, in.readableBytes());
|
||||||
}
|
}
|
||||||
if (payloadLength < expectedMinLen) {
|
if (payloadLength < expectedMinLen) {
|
||||||
throw handleUnderflow(packet, expectedMaxLen, in.readableBytes());
|
throw handleUnderflow(packet, expectedMaxLen, in.readableBytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
in.readerIndex(index);
|
in.readerIndex(index);
|
||||||
return false;
|
return false;
|
||||||
|
} catch (Exception e) {
|
||||||
|
// Reset buffer to consistent state before propagating exception to prevent memory leaks
|
||||||
|
in.readerIndex(index);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
Reference in New Issue
Block a user