Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OpenJDK 13 requires -XX:+AllowRedefinitionToAddDeleteMethods flag #33

Open
juergenzimmermann opened this issue Jun 2, 2019 · 20 comments
Labels
area/java-agent help wanted We need contributions on this status/has-workaround This has a known workaround described

Comments

@juergenzimmermann
Copy link

OpenJDK 12.0.1 with even Kotlin 1.3.40-eap-67 works fine. However, using OpenJDK 13 build 23 I get the following exception:

Exception in thread "main" java.lang.RuntimeException: java.lang.UnsupportedOperationException: class redefinition failed: attempted to add a method
        at reactor.blockhound.BlockHound$Builder.install(BlockHound.java:264)
        at reactor.blockhound.BlockHound.install(BlockHound.java:64)
        at de.hska.kunde.ApplicationKt.main(Application.kt:51)
Caused by: java.lang.UnsupportedOperationException: class redefinition failed: attempted to add a method
        at java.instrument/sun.instrument.InstrumentationImpl.retransformClasses0(Native Method)
        at java.instrument/sun.instrument.InstrumentationImpl.retransformClasses(InstrumentationImpl.java:167)
        at reactor.blockhound.BlockHound$Builder.instrument(BlockHound.java:273)
        at reactor.blockhound.BlockHound$Builder.install(BlockHound.java:261)
        ... 2 more
@bsideup
Copy link
Contributor

bsideup commented Jun 2, 2019

Hi @juergenzimmermann,

I'm afraid that's due to https://bugs.openjdk.java.net/browse/JDK-8192936 and similar to #21
In JDK 13+, they adjusted the spec & impl and no longer allow redefining native methods :(

We will need to find an alternative way for 13+ and J9, meanwhile, they seem to plan adding a flag to keep the behaviour for a few versions:
https://bugs.openjdk.java.net/browse/JDK-8192936?focusedCommentId=14254266&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#comment-14254266

@juergenzimmermann
Copy link
Author

@bsideup When I use -XX:+AllowRedefinitionToAddDeleteMethods the stacktrace goes away

@bsideup
Copy link
Contributor

bsideup commented Jun 2, 2019

@juergenzimmermann thanks a lot for trying it!
I will keep this issue open as a reminder to document this flag 👍

@bsideup bsideup changed the title UnsupportedOperationException with OpenJDK 13 OpenJDK 13 requires -XX:+AllowRedefinitionToAddDeleteMethods flag Jul 19, 2019
@bsideup bsideup pinned this issue Jul 19, 2019
@bsideup bsideup added the status/has-workaround This has a known workaround described label Aug 2, 2019
@yburkouski
Copy link

yburkouski commented Nov 9, 2019

Heaving quite different behavior on Oracle JDK 13 in Windows: it does not throw an error about blocking call until I add this flag

bsideup added a commit that referenced this issue Mar 26, 2020
Since OpenJDK requires `-XX:+AllowRedefinitionToAddDeleteMethod` (see #33)
starting with Java 13, we should test that the instrumentation
was applied correctly and fail fast if not.
bsideup added a commit that referenced this issue Mar 26, 2020
Since OpenJDK requires `-XX:+AllowRedefinitionToAddDeleteMethod` (see #33)
starting with Java 13, we should test that the instrumentation
was applied correctly and fail fast if not.
@sergey-morenets
Copy link

Still reproduced with JDK 14.0.1 and BlockHound 1.0.3

@jaschenk
Copy link

jaschenk commented Jul 30, 2020

Using Blockhound 1.0.4 and JDK 14.0.2 and specify the following in surefire plugin worked:

<plugins>
 ...
         <plugin>
             <groupId>org.apache.maven.plugins</groupId>
             <artifactId>maven-surefire-plugin</artifactId>
             <version>2.22.2</version>
             <configuration>
                 <argLine>-XX:+AllowRedefinitionToAddDeleteMethods</argLine>
             </configuration>
         </plugin>
 ...
 </plugins>

@abdullahumer
Copy link

any way this can be added to gradle?

@bsideup
Copy link
Contributor

bsideup commented Nov 30, 2020

@abdullahumer sure:

    tasks.withType(Test).all {
        if (JavaVersion.current().isCompatibleWith​(JavaVersion.VERSION_13)) {
            jvmArgs += [
                    "-XX:+AllowRedefinitionToAddDeleteMethods"
            ]
        }
    }

@abdullahumer
Copy link

Thanks! @bsideup

brneto pushed a commit to neueda/java-reactive-microservices-chassis that referenced this issue Jul 27, 2021
Removed due to issues with OpenJDK version 13+
reactor/BlockHound#33
@roimenashe
Copy link

Still reproduced with JDK 15.0.2 and BlockHound 1.0.6.RELEASE.
"-XX:+AllowRedefinitionToAddDeleteMethods" option still shows deprecation warning.
Any updates?

marcusdacoregio added a commit to marcusdacoregio/spring-security that referenced this issue Oct 7, 2021
The dependency is not needed anymore and there is a issue when using OpenJDK 13 or higher reactor/BlockHound#33

Issue spring-projectsgh-10343
marcusdacoregio added a commit to marcusdacoregio/spring-security that referenced this issue Oct 20, 2021
The dependency is not needed anymore and there is a issue when using OpenJDK 13 or higher reactor/BlockHound#33

Issue spring-projectsgh-10343
rwinch pushed a commit to spring-projects/spring-security that referenced this issue Oct 25, 2021
The dependency is not needed anymore and there is a issue when using OpenJDK 13 or higher reactor/BlockHound#33

Issue gh-10343
rwinch pushed a commit to spring-projects/spring-security that referenced this issue Oct 26, 2021
The dependency is not needed anymore and there is a issue when using OpenJDK 13 or higher reactor/BlockHound#33

Issue gh-10343
marcusdacoregio added a commit to marcusdacoregio/spring-security that referenced this issue Nov 1, 2021
The dependency is not needed anymore and there is a issue when using OpenJDK 13 or higher reactor/BlockHound#33

Issue spring-projectsgh-10343
sbrannen added a commit to spring-projects/spring-framework that referenced this issue Jan 11, 2022
Prior to this commit, our BlockHound integration tests were disabled
after the migration to a JDK 17 baseline since the build now always
runs on JDK 14 or higher.

To re-enable the tests we now supply the deprecated
-XX:+AllowRedefinitionToAddDeleteMethods command-line argument to the JVM
for tests in the Gradle build. Users can also configure this manually
within an IDE to run SpringCoreBlockHoundIntegrationTests.

If that command-line argument is removed from the JVM at some point in
the future, we will need to investigate an alternative solution.

See reactor/BlockHound#33 for details.
@CodeGTDLearn
Copy link

Using Blockhound 1.0.4 and JDK 14.0.2 and specify the following in surefire plugin worked:

<plugins>
 ...
         <plugin>
             <groupId>org.apache.maven.plugins</groupId>
             <artifactId>maven-surefire-plugin</artifactId>
             <version>2.22.2</version>
             <configuration>
                 <argLine>-XX:+AllowRedefinitionToAddDeleteMethods</argLine>
             </configuration>
         </plugin>
 ...
 </plugins>

In my case Using Blockhound 1.0.6 and JDK 15.0.6, worked

@KrzysztofKwiatkowskiK
Copy link

Using blockhound 1.0.6 and JDK 16.0.2 I am still getting this error and has to use the flag...

@simonbasle simonbasle added the help wanted We need contributions on this label Apr 7, 2022
@ajax-semenov-y
Copy link

Hi. As far as I understand, according to https://bugs.openjdk.org/browse/JDK-8221528.

"This option (AllowRedefinitionToAddOrDeleteMethods) is deprecated right away. The plan is to keep it for a couple of releases to allow customers (tool vendors) to remove dependency on old behavior from their tools."

Do you plan BlockHound work according to the new JVM TI behavior?

@juliojgd
Copy link

I guess that if this issue is not solved, when the option AllowRedefinitionToAddOrDeleteMethods is removed from JVM, then Blockhound is completely unusable, right?

@patpatpat123
Copy link

Now in 2023, almost four years after the original issue, would it be possible to have a fix without the -XX workaround please?

@pderop
Copy link
Member

pderop commented May 15, 2023

I will take a look, but I don't promise anything for the moment, because looking at the history of this issue, without the work around flag, it seems to be a very very big deal to redefine / retransform classes (add/delete private static and private final instance methods in the new class versions).
so, I'm afraid that for the moment, we need to continue using -XX:+AllowRedefinitionToAddDeleteMethods for JDK13+
Is there any issues if you continue using this flag for the moment ?

thanks.

@divyanshsaini1805
Copy link

divyanshsaini1805 commented Oct 17, 2023

i am using Java 17 and Spring 3.1.3, even after including the -XX:+AllowRedefinitionToAddDeleteMethods flag, i am still facing the error. Is the flag removed from JVM or has the fix stopped working?

@pderop
Copy link
Member

pderop commented Oct 19, 2023

Hi @divyanshsaini1805 ,

please open a separate issue with a reproducer project;
From my side, I did the following which worked for me using Spring 3.1.3, and java 17:

build.gradle:

plugins {
    id 'java'
    id 'org.springframework.boot' version '3.1.3'
    id 'io.spring.dependency-management' version '1.1.3'
}

apply plugin: 'application'

group = 'com.example'
version = '0.0.1-SNAPSHOT'

java {
    sourceCompatibility = '17'
}

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter'
    implementation 'io.projectreactor.netty:reactor-netty-core:1.0.37'
    implementation 'io.projectreactor.netty:reactor-netty-http:1.0.37'
    implementation('io.projectreactor.tools:blockhound:1.0.8.RELEASE')
    implementation 'javax.annotation:javax.annotation-api:1.3.2'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

tasks.named('test') {
    useJUnitPlatform()
}

task(echoServer, dependsOn: 'classes', type: JavaExec) {
    main = 'com.example.EchoServer'
    classpath = sourceSets.main.runtimeClasspath
    args ''
    systemProperty "io.netty.leakDetectionLevel", "DISABLED"
    debugOptions {
        enabled = false
        port = 5005
        server = true
        suspend = true
    }
}

DemoApplication.java:

package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class DemoApplication {
	public static void main(String[] args) {
		SpringApplication.run(DemoApplication.class, args);
	}
}

Demo.java:

package com.example.demo;

import org.springframework.stereotype.Component;
import reactor.blockhound.BlockHound;
import reactor.netty.tcp.TcpServer;

import javax.annotation.PostConstruct;

@Component
public class Demo {
    static final int PORT = Integer.parseInt(System.getProperty("port", "8080"));

    @PostConstruct
    public void init() {
        System.out.println("Jdk version used: " + System.getProperty("java.version"));
        BlockHound.install();

        TcpServer server =
                TcpServer.create()
                        .port(PORT)
                        .handle((in, out) -> {
                            try {
                                Thread.sleep(100);
                            } catch (Throwable err) {
                                err.printStackTrace();
                            }
                            return out.send(in.receive().retain());
                        });

        server.bindNow()
                .onDispose()
                .block();
    }
}

then, from one console using java17:

./gradlew build
java -XX:+AllowRedefinitionToAddDeleteMethods -jar build/libs/demo-0.0.1-SNAPSHOT.jar

from another console:

curl -v http://localhost:8080/foo

this will display the following from the first console:

reactor.blockhound.BlockingOperationError: Blocking call! java.lang.Thread.sleep
	at java.base/java.lang.Thread.sleep(Thread.java)
	at com.example.demo.Demo.lambda$init$0(Demo.java:34)
	at reactor.netty.tcp.TcpServer$OnConnectionHandle.accept(TcpServer.java:277)
	at reactor.netty.tcp.TcpServer$OnConnectionHandle.accept(TcpServer.java:264)
	at reactor.netty.transport.ServerTransportConfig$ServerTransportDoOnConnection.onStateChange(ServerTransportConfig.java:253)
	at reactor.netty.transport.ServerTransport$ChildObserver.onStateChange(ServerTransport.java:481)
	at reactor.netty.channel.ChannelOperationsHandler.channelActive(ChannelOperationsHandler.java:62)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelActive(AbstractChannelHandlerContext.java:262)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelActive(AbstractChannelHandlerContext.java:238)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelActive(AbstractChannelHandlerContext.java:231)
	at io.netty.channel.DefaultChannelPipeline$HeadContext.channelActive(DefaultChannelPipeline.java:1398)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelActive(AbstractChannelHandlerContext.java:258)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelActive(AbstractChannelHandlerContext.java:238)
	at io.netty.channel.DefaultChannelPipeline.fireChannelActive(DefaultChannelPipeline.java:895)
	at io.netty.channel.AbstractChannel$AbstractUnsafe.register0(AbstractChannel.java:522)
	at io.netty.channel.AbstractChannel$AbstractUnsafe.access$200(AbstractChannel.java:429)
	at io.netty.channel.AbstractChannel$AbstractUnsafe$1.run(AbstractChannel.java:486)
	at io.netty.util.concurrent.AbstractEventExecutor.runTask(AbstractEventExecutor.java:174)
	at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:167)
	at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:470)
	at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:569)
	at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997)
	at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
	at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
	at java.base/java.lang.Thread.run(Thread.java:833)

Thanks.

@apferrarone
Copy link

apferrarone commented Jan 12, 2024

I have tried on windows with corretto-17 and temurin-17. When I add the vm option to the Surefire plugin config in pom.xml, my unit tests work with BlockHound. But when I add the vm option to my IntelliJ run configuration or in the vm options file I still see this error when I start up my springboot app:

OpenJDK 64-Bit Server VM warning: Sharing is only supported for boot loader classes because bootstrap classpath has been appended
Exception in thread "main" java.lang.ExceptionInInitializerError
Caused by: java.lang.IllegalStateException: The instrumentation have failed.
It looks like you're running on JDK 13+.
You need to add '-XX:+AllowRedefinitionToAddDeleteMethods' JVM flag.
public static void main(String[] args) {
	System.out.println(args[0] + " ");
	SpringApplication.run(BillGenerationServiceApplication.class, args);
}

I see this: -XX:+AllowRedefinitionToAddDeleteMethods at the top of the console.

Any ideas? Thanks.

@divyanshsaini1805
Copy link

divyanshsaini1805 commented Jan 16, 2024

Hi @divyanshsaini1805 ,

please open a separate issue with a reproducer project; From my side, I did the following which worked for me using Spring 3.1.3, and java 17:

build.gradle:

plugins {
    id 'java'
    id 'org.springframework.boot' version '3.1.3'
    id 'io.spring.dependency-management' version '1.1.3'
}

apply plugin: 'application'

group = 'com.example'
version = '0.0.1-SNAPSHOT'

java {
    sourceCompatibility = '17'
}

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter'
    implementation 'io.projectreactor.netty:reactor-netty-core:1.0.37'
    implementation 'io.projectreactor.netty:reactor-netty-http:1.0.37'
    implementation('io.projectreactor.tools:blockhound:1.0.8.RELEASE')
    implementation 'javax.annotation:javax.annotation-api:1.3.2'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

tasks.named('test') {
    useJUnitPlatform()
}

task(echoServer, dependsOn: 'classes', type: JavaExec) {
    main = 'com.example.EchoServer'
    classpath = sourceSets.main.runtimeClasspath
    args ''
    systemProperty "io.netty.leakDetectionLevel", "DISABLED"
    debugOptions {
        enabled = false
        port = 5005
        server = true
        suspend = true
    }
}

DemoApplication.java:

package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class DemoApplication {
	public static void main(String[] args) {
		SpringApplication.run(DemoApplication.class, args);
	}
}

Demo.java:

package com.example.demo;

import org.springframework.stereotype.Component;
import reactor.blockhound.BlockHound;
import reactor.netty.tcp.TcpServer;

import javax.annotation.PostConstruct;

@Component
public class Demo {
    static final int PORT = Integer.parseInt(System.getProperty("port", "8080"));

    @PostConstruct
    public void init() {
        System.out.println("Jdk version used: " + System.getProperty("java.version"));
        BlockHound.install();

        TcpServer server =
                TcpServer.create()
                        .port(PORT)
                        .handle((in, out) -> {
                            try {
                                Thread.sleep(100);
                            } catch (Throwable err) {
                                err.printStackTrace();
                            }
                            return out.send(in.receive().retain());
                        });

        server.bindNow()
                .onDispose()
                .block();
    }
}

then, from one console using java17:

./gradlew build
java -XX:+AllowRedefinitionToAddDeleteMethods -jar build/libs/demo-0.0.1-SNAPSHOT.jar

from another console:

curl -v http://localhost:8080/foo

this will display the following from the first console:

reactor.blockhound.BlockingOperationError: Blocking call! java.lang.Thread.sleep
	at java.base/java.lang.Thread.sleep(Thread.java)
	at com.example.demo.Demo.lambda$init$0(Demo.java:34)
	at reactor.netty.tcp.TcpServer$OnConnectionHandle.accept(TcpServer.java:277)
	at reactor.netty.tcp.TcpServer$OnConnectionHandle.accept(TcpServer.java:264)
	at reactor.netty.transport.ServerTransportConfig$ServerTransportDoOnConnection.onStateChange(ServerTransportConfig.java:253)
	at reactor.netty.transport.ServerTransport$ChildObserver.onStateChange(ServerTransport.java:481)
	at reactor.netty.channel.ChannelOperationsHandler.channelActive(ChannelOperationsHandler.java:62)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelActive(AbstractChannelHandlerContext.java:262)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelActive(AbstractChannelHandlerContext.java:238)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelActive(AbstractChannelHandlerContext.java:231)
	at io.netty.channel.DefaultChannelPipeline$HeadContext.channelActive(DefaultChannelPipeline.java:1398)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelActive(AbstractChannelHandlerContext.java:258)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelActive(AbstractChannelHandlerContext.java:238)
	at io.netty.channel.DefaultChannelPipeline.fireChannelActive(DefaultChannelPipeline.java:895)
	at io.netty.channel.AbstractChannel$AbstractUnsafe.register0(AbstractChannel.java:522)
	at io.netty.channel.AbstractChannel$AbstractUnsafe.access$200(AbstractChannel.java:429)
	at io.netty.channel.AbstractChannel$AbstractUnsafe$1.run(AbstractChannel.java:486)
	at io.netty.util.concurrent.AbstractEventExecutor.runTask(AbstractEventExecutor.java:174)
	at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:167)
	at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:470)
	at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:569)
	at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997)
	at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
	at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
	at java.base/java.lang.Thread.run(Thread.java:833)

Thanks.

hi, i know it's been a super long time, but since this thread is a lot active, i would like to add my part,
for Spring 3.1.3, and java 17,
the -XX:+AllowRedefinitionToAddDeleteMethods flag works good indeed if used with the following command:
java -XX:+AllowRedefinitionToAddDeleteMethods -jar target/Required_jar_file.jar,

pderop added a commit that referenced this issue Apr 4, 2024
using Blockhound with JDK 22 is not working, even when using "-XX:+AllowRedefinitionToAddDeleteMethods" option:

Caused by: java.lang.IllegalStateException: The instrumentation have failed.
 It looks like you're running on JDK 13+.
 You need to add '-XX:+AllowRedefinitionToAddDeleteMethods' JVM flag.
 See #33 for more info.
         at reactor.blockhound.BlockHound$Builder.testInstrumentation(BlockHound.java:538)
         at reactor.blockhound.BlockHound$Builder.install(BlockHound.java:501)
         at reactor.blockhound.BlockHound.install(BlockHound.java:91)
         at reactor.blockhound.junit.platform.BlockHoundTestExecutionListener.<clinit>(BlockHoundTestExecutionListener.java:19)
         ... 39 more

this is because during initialization, Blockhound is trying to instrument the Thread.sleep() method, and if it does not work, then the initialization fails and assumes that the failure comes from a missing "-XX:+AllowRedefinitionToAddDeleteMethods" option.

but, here the problem is that in JDK 22, the internal native method called by Thread.sleep has changed, it's "Thread.sleepNanos0" instead of "Thread.sleep0".

This PR corrects the instrumentation for Thread.sleepNanos0 native method when the JDK version is detected to be 22+

Fixes #404
cprutle added a commit to CybercentreCanada/assemblyline-java-client that referenced this issue Apr 8, 2024
cprutle added a commit to CybercentreCanada/assemblyline-java-client that referenced this issue Apr 8, 2024
cprutle added a commit to CybercentreCanada/assemblyline-java-client that referenced this issue Apr 8, 2024
)

* Bump org.apache.maven.plugins:maven-gpg-plugin from 3.1.0 to 3.2.2

Bumps [org.apache.maven.plugins:maven-gpg-plugin](https://github.com/apache/maven-gpg-plugin) from 3.1.0 to 3.2.2.
- [Release notes](https://github.com/apache/maven-gpg-plugin/releases)
- [Commits](apache/maven-gpg-plugin@maven-gpg-plugin-3.1.0...maven-gpg-plugin-3.2.2)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-gpg-plugin
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* work around for issue  reactor/BlockHound#33

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: cprutle <calla.rutledge@cyber.gc.ca>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/java-agent help wanted We need contributions on this status/has-workaround This has a known workaround described
Projects
None yet
Development

No branches or pull requests