netty/netty

Netty 4.2.0.Alpha1 throws `NoSuchMethodError: java.nio.ByteBuffer.limit(I)Ljava/nio/ByteBuffer`

Opened this issue · 13 comments

The issue is not reproducible with

  • Netty 4.2.0.Final-SNAPSHOT
  • Java 17

Expected behavior

Do not observe NoSuchMethodError

Actual behavior

Netty 4.2.0.Alpha1 throws NoSuchMethodError: java.nio.ByteBuffer.limit(I)Ljava/nio/ByteBuffer

Steps to reproduce

Run io.netty.example.http.helloworld.HttpHelloWorldServer with Java 8

Minimal yet complete reproducer code (or URL to code)

Clone https://github.com/violetagg/GH-14119
Run HttpHelloWorldServer
Request curl http://localhost:8080
You should be able to see

java.lang.NoSuchMethodError: java.nio.ByteBuffer.limit(I)Ljava/nio/ByteBuffer;
	at io.netty.buffer.PooledByteBuf._internalNioBuffer(PooledByteBuf.java:191)
	at io.netty.buffer.PooledByteBuf.internalNioBuffer(PooledByteBuf.java:203)
	at io.netty.buffer.PooledByteBuf.setBytes(PooledByteBuf.java:255)
	at io.netty.buffer.AbstractByteBuf.writeBytes(AbstractByteBuf.java:1132)
	at io.netty.channel.socket.nio.NioSocketChannel.doReadBytes(NioSocketChannel.java:350)
	at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:151)
	at io.netty.channel.nio.AbstractNioChannel$AbstractNioUnsafe.handle(AbstractNioChannel.java:445)
	at io.netty.channel.nio.NioIoHandler$DefaultNioRegistration.handle(NioIoHandler.java:373)
	at io.netty.channel.nio.NioIoHandler.processSelectedKey(NioIoHandler.java:572)
	at io.netty.channel.nio.NioIoHandler.processSelectedKeysOptimized(NioIoHandler.java:547)
	at io.netty.channel.nio.NioIoHandler.processSelectedKeys(NioIoHandler.java:488)
	at io.netty.channel.nio.NioIoHandler.run(NioIoHandler.java:465)
	at io.netty.channel.SingleThreadIoEventLoop.runIo(SingleThreadIoEventLoop.java:170)
	at io.netty.channel.SingleThreadIoEventLoop.run(SingleThreadIoEventLoop.java:150)
	at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:994)
	at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
	at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
	at java.lang.Thread.run(Thread.java:750)

Netty version

Netty 4.2.0.Alpha1

JVM version (e.g. java -version)

Java 8

OS version (e.g. uname -a)

Mac OS

@violetagg I suspect it will work with Java8 correct ?

@violetagg I suspect it will work with Java8 correct ?

With Java 8 -> NoSuchMethodError
With Java 11/17 -> Ok

/.../corretto-1.8.0_412/Contents/Home/bin/java ... org.example.HttpHelloWorldServer
Jun 13, 2024 1:57:57 PM io.netty.handler.logging.LoggingHandler channelRegistered
INFO: [id: 0x8ab61724] REGISTERED
Jun 13, 2024 1:57:57 PM io.netty.handler.logging.LoggingHandler bind
INFO: [id: 0x8ab61724] BIND: 0.0.0.0/0.0.0.0:8080
Open your web browser and navigate to http://127.0.0.1:8080/
Jun 13, 2024 1:57:57 PM io.netty.handler.logging.LoggingHandler channelActive
INFO: [id: 0x8ab61724, L:/0:0:0:0:0:0:0:0:8080] ACTIVE
Jun 13, 2024 1:58:05 PM io.netty.handler.logging.LoggingHandler channelRead
INFO: [id: 0x8ab61724, L:/0:0:0:0:0:0:0:0:8080] READ: [id: 0xbe49a786, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:57273]
Jun 13, 2024 1:58:05 PM io.netty.handler.logging.LoggingHandler channelReadComplete
INFO: [id: 0x8ab61724, L:/0:0:0:0:0:0:0:0:8080] READ COMPLETE
java.lang.NoSuchMethodError: java.nio.ByteBuffer.limit(I)Ljava/nio/ByteBuffer;
	at io.netty.buffer.PooledByteBuf._internalNioBuffer(PooledByteBuf.java:191)
	at io.netty.buffer.PooledByteBuf.internalNioBuffer(PooledByteBuf.java:203)
	at io.netty.buffer.PooledByteBuf.setBytes(PooledByteBuf.java:255)
	at io.netty.buffer.AbstractByteBuf.writeBytes(AbstractByteBuf.java:1132)
	at io.netty.channel.socket.nio.NioSocketChannel.doReadBytes(NioSocketChannel.java:350)
	at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:151)
	at io.netty.channel.nio.AbstractNioChannel$AbstractNioUnsafe.handle(AbstractNioChannel.java:445)
	at io.netty.channel.nio.NioIoHandler$DefaultNioRegistration.handle(NioIoHandler.java:373)
	at io.netty.channel.nio.NioIoHandler.processSelectedKey(NioIoHandler.java:572)
	at io.netty.channel.nio.NioIoHandler.processSelectedKeysOptimized(NioIoHandler.java:547)
	at io.netty.channel.nio.NioIoHandler.processSelectedKeys(NioIoHandler.java:488)
	at io.netty.channel.nio.NioIoHandler.run(NioIoHandler.java:465)
	at io.netty.channel.SingleThreadIoEventLoop.runIo(SingleThreadIoEventLoop.java:170)
	at io.netty.channel.SingleThreadIoEventLoop.run(SingleThreadIoEventLoop.java:150)
	at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:994)
	at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
	at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
	at java.lang.Thread.run(Thread.java:750)

The core issue is this: https://github.com/netty/netty/blob/4.2/pom.xml#L6209-L6210

When compiling with Java 11, if you want to compile and bind against the Java 8 API, you have to use the <maven.compiler.release>8</maven.compiler.release> instead.

Without this, the bytecode binds to the new ByteBuffer limit(int) override defined on ByteBuffer and introduced in Java 9, instead of the Buffer limit(int) defined on parent Buffer existing in Java 8.

@violetagg seems like I messed up things when releasing...

@slandelle this will not work as of today as we have references to sun.misc.Unsafe in the code. That said I think we could get rid of these by using varhandles. I will take a stab on this.

The release build still need to be done with Java 8, AFAIK.

@chrisvest I think if we change the pom.xml to use the right release mode it would not...

The only downside of using method handles would be that it will have a small perf hit imho... @franz1981 @chrisvest thoughts ?

If method handle is in a static final, it uses invokeExact with the right casts and arguments, it shouldn't. But there is really no other solution ?

@franz1981 if we want to compile with java 8+ no...

@franz1981 if we want to compile with java 8+ no...

https://www.morling.dev/blog/bytebuffer-and-the-dreaded-nosuchmethoderror/

I was reading this to refresh my bad memory on this issue I hit myself in the past

@franz1981 if we use <maven.compiler.release>8</maven.compiler.release> we can have a reference to sun.misc.Unsafe in our code ;)

@chrisvest @franz1981 unfortunately this would also mean that we would need to use invoke(...) and not invokeExact(...). So I assume there would be a perf hit. WDYT ?