BufferOverflowException with specific buffer sizes
See original GitHub issueWhen Netty reallocates pooled buffers that are approximately 256 to 1024 bytes, a BufferOverflowException
can be thrown. Furthermore, the exception is swallowed and is not printed by LoggingHandler
(I was only able to find it by capturing it from a debugger).
I’m on JDK 13 and therefore Unsafe
isn’t available.
Expected behavior
Buffers that are between 256 and 1024 bytes should be reallocated successfully. In my application. it always works when the buffer is outside of that range and always throws when the buffer is inside of the range.
Actual behavior
io.netty.handler.codec.EncoderException: java.nio.BufferOverflowException
at io.netty.codec@4.1.44.Final/io.netty.handler.codec.MessageToByteEncoder.write(MessageToByteEncoder.java:125)
at io.netty.transport@4.1.44.Final/io.netty.channel.AbstractChannelHandlerContext.invokeWrite0(AbstractChannelHandlerContext.java:715)
at io.netty.transport@4.1.44.Final/io.netty.channel.AbstractChannelHandlerContext.invokeWrite(AbstractChannelHandlerContext.java:707)
at io.netty.transport@4.1.44.Final/io.netty.channel.AbstractChannelHandlerContext.write(AbstractChannelHandlerContext.java:790)
at io.netty.transport@4.1.44.Final/io.netty.channel.AbstractChannelHandlerContext.write(AbstractChannelHandlerContext.java:700)
at io.netty.codec@4.1.44.Final/io.netty.handler.codec.MessageToMessageEncoder.write(MessageToMessageEncoder.java:112)
at io.netty.transport@4.1.44.Final/io.netty.channel.AbstractChannelHandlerContext.invokeWrite0(AbstractChannelHandlerContext.java:715)
at io.netty.transport@4.1.44.Final/io.netty.channel.AbstractChannelHandlerContext.invokeWrite(AbstractChannelHandlerContext.java:707)
at io.netty.transport@4.1.44.Final/io.netty.channel.AbstractChannelHandlerContext.write(AbstractChannelHandlerContext.java:790)
at io.netty.transport@4.1.44.Final/io.netty.channel.AbstractChannelHandlerContext.write(AbstractChannelHandlerContext.java:700)
at io.netty.handler@4.1.44.Final/io.netty.handler.logging.LoggingHandler.write(LoggingHandler.java:235)
at io.netty.transport@4.1.44.Final/io.netty.channel.AbstractChannelHandlerContext.invokeWrite0(AbstractChannelHandlerContext.java:715)
at io.netty.transport@4.1.44.Final/io.netty.channel.AbstractChannelHandlerContext.invokeWriteAndFlush(AbstractChannelHandlerContext.java:762)
at io.netty.transport@4.1.44.Final/io.netty.channel.AbstractChannelHandlerContext$WriteTask.run(AbstractChannelHandlerContext.java:1089)
at io.netty.common@4.1.44.Final/io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:164)
at io.netty.common@4.1.44.Final/io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:472)
at io.netty.transport@4.1.44.Final/io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:500)
at io.netty.common@4.1.44.Final/io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)
at io.netty.common@4.1.44.Final/io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
at io.netty.common@4.1.44.Final/io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.base/java.lang.Thread.run(Thread.java:830)
Caused by: java.nio.BufferOverflowException
at java.base/java.nio.DirectByteBuffer.put(DirectByteBuffer.java:411)
at io.netty.buffer@4.1.44.Final/io.netty.buffer.PoolArena$DirectArena.memoryCopy(PoolArena.java:795)
at io.netty.buffer@4.1.44.Final/io.netty.buffer.PoolArena$DirectArena.memoryCopy(PoolArena.java:704)
at io.netty.buffer@4.1.44.Final/io.netty.buffer.PoolArena.reallocate(PoolArena.java:405)
at io.netty.buffer@4.1.44.Final/io.netty.buffer.PooledByteBuf.capacity(PooledByteBuf.java:118)
at io.netty.buffer@4.1.44.Final/io.netty.buffer.AbstractByteBuf.ensureWritable0(AbstractByteBuf.java:306)
at io.netty.buffer@4.1.44.Final/io.netty.buffer.AbstractByteBuf.ensureWritable(AbstractByteBuf.java:282)
at io.netty.codec@4.1.44.Final/io.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender.encode(ProtobufVarint32LengthFieldPrepender.java:48)
at io.netty.codec@4.1.44.Final/io.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender.encode(ProtobufVarint32LengthFieldPrepender.java:40)
at io.netty.codec@4.1.44.Final/io.netty.handler.codec.MessageToByteEncoder.write(MessageToByteEncoder.java:107)
... 20 more
This leads to messages of certain sizes getting dropped out of the pipeline.
Minimal yet complete reproducer code (or URL to code)
I haven’t been able to reproduce outside of my application (and I tried pretty hard). I suspect that the allocation sequence of pooled buffers in my application must be important. I’ll try to come up with a way to test this easily in my application.
Netty version
4.1.44.Final
JVM version (e.g. java -version
)
openjdk 13.0.1 2019-10-15
OpenJDK Runtime Environment (build 13.0.1+9)
OpenJDK 64-Bit Server VM (build 13.0.1+9, mixed mode)
OS version (e.g. uname -a
)
Linux OCTOLOGY 5.4.6-arch1-1 #1 SMP PREEMPT Sat, 21 Dec 2019 16:34:41 +0000 x86_64 GNU/Linux
Issue Analytics
- State:
- Created 4 years ago
- Comments:6 (3 by maintainers)
Top GitHub Comments
Thanks. I can confirm that reverting b0feb5a81fd03f35b9e26108efc71070d0a52288 fixes the issue.
I’ve opened #9912 to fix the main bug, but haven’t looked at the exception swallowing yet.