JetBrainsRuntime icon indicating copy to clipboard operation
JetBrainsRuntime copied to clipboard

InternalError when using mockito 5.3 with -XX:+AllowEnhancedClassRedefinition

Open schmidti159 opened this issue 2 years ago • 8 comments

Hi, we recently upgraded from Spring Boot 2.7 to Spring Boot 3.1 and with this we also upgraded mockito from 4.5.1 to 5.3.1 and bytebuddy from 1.12.23 to 1.14.10.

We use JBR in our development flow with -XX:+AllowEnhancedClassRedefinition to have faster development cycles when working on UI tests so no restart is required.

After the upgrade we see exceptions caused by java.lang.InternalError in our tests when we use JBR with this flag.

I uploaded a minimal reproducer here: https://github.com/schmidti159/reproducer_for-internal_error_in_jbr_with_mockito

The readme also contains the complete stacktrace and steps how to reproduce.

I am using IntelliJ IDEA 2023.2.5 to start the test and could reproduce it with JBR version 17.0.9+7-b1087.3

Could you please have a look? Having enhanced class redefinition is very valuable to our development workflow.

schmidti159 avatar Nov 28 '23 13:11 schmidti159

Thanks for reporting this, I filed JBR-6363 in our issue tracker.

mkartashev avatar Nov 28 '23 13:11 mkartashev

This problem is a bit more difficult. The sample program uses PowerMock, which redefines java.lang.Object, which results in redefining all subclasses, i.e. almost all the classes just loaded in ClassLoader. In this case, there are ~4,000 classes. The size wouldn't be such a problem, but the problem is that it redefines java.lang.Object, which has a lot of bindings and dependencies in the JVM and the current DCEVM doesn't support redefinition of this class. However, a fix is being worked on, but it won't be in the short term, this is a major intervention in the DCEVM code.

skybber avatar Dec 12 '23 14:12 skybber

Thank you for your analysis. I was not aware that the sample was using PowerMock explicitly, so I looked at it again. The root cause of why it only occurred now, is that Mockito changed the default MockMaker with version 5. Before it was using the subclass MockMaker, now the default is the inline MockMaker (see https://github.com/mockito/mockito/releases/tag/v5.0.0).

So if the subclass MockMaker is enough for the current project a simple workaround is to add this dependency to the project:

    <dependency>
      <groupId>org.mockito</groupId>
      <artifactId>mockito-subclass</artifactId>
      <scope>test</scope>
    </dependency>

schmidti159 avatar Jan 11 '24 16:01 schmidti159

There is a jbr branch with the patch available at:

https://github.com/JetBrains/JetBrainsRuntime/tree/vladimir.dvorak/JBR-6363

if you know how to build a JDK, it would be great if you could try it on your case, but don't feel it's necessary

skybber avatar Jan 22 '24 09:01 skybber

New release https://github.com/JetBrains/JetBrainsRuntime/releases/tag/jbr-release-17.0.10b1186.1 support redefinition of java.lang.object, so this issue should be fixed now

skybber avatar Feb 12 '24 06:02 skybber

We faced a very similar issue on JBR 21 and Spring Boot 3.4.4 (Mockito 5.14.2). Actually, JBR (including the latest 21.0.6) doesn't work with any kind of Spring mock (including the new one @MockitoSpyBean).

Caused by: java.lang.LinkageError: loader constraint violation: when resolving method 'void java.util.concurrent.ThreadPoolExecutor.<init>(int, int, long, java.util.concurrent.TimeUnit, java.util.concurrent.BlockingQueue, java.util.concurrent.ThreadFactory, java.util.concurrent.RejectedExecutionHandler)' the class loader 'app' of the current class, org/springframework/scheduling/concurrent/ThreadPoolTaskExecutor$1, and the class loader 'bootstrap' for the method's defining class, java/util/concurrent/ThreadPoolExecutor, have different Class objects for the type java/util/concurrent/RejectedExecutionHandler used in the signature (org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor$1 is in unnamed module of loader 'app'; java.util.concurrent.ThreadPoolExecutor is in module java.base of loader 'bootstrap')
	at org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor$1.<init>(ThreadPoolTaskExecutor.java:285)
[INFO] 
[INFO] Results:
[INFO] 
[ERROR] Errors: 
[ERROR]   JbrEnhancedClassRedefinitionTest » IllegalArgument Class [org.springframework.test.context.transaction.TransactionalTestExecutionListener] is not assignable to factory type [org.springframework.test.context.TestExecutionListener]       

In other cases (not reflected in the reproducer) we got:

Caused by: java.lang.VerifyError: Bad type on operand stack
Exception Details:
  Location:
    org/apache/catalina/loader/WebappLoader.setPermissions()V @62: invokevirtual
  Reason:
    Type 'java/io/FilePermission' (current frame, stack[1]) is not assignable to 'java/security/Permission'
  Current Frame:
    bci: @62
    flags: { }
    locals: { 'org/apache/catalina/loader/WebappLoader', 'jakarta/servlet/ServletContext', 'java/io/File', 'java/lang/String' }
    stack: { 'org/apache/catalina/loader/WebappClassLoaderBase', 'java/io/FilePermission' }
  Bytecode:

We believe all these issues have the same cause.

After adding in pom.xml:

<dependency>
  <groupId>org.mockito</groupId>
  <artifactId>mockito-subclass</artifactId>
  <scope>test</scope>
</dependency>

the problem was resolved. Here is the reproducer - https://github.com/tfactor2/reproducer-jbr-enhanced-class-redifinition.

@skybber - I added the comment in an already closed issue; if needed, I can create a separate issue, no problem.

tfactor2 avatar May 08 '25 17:05 tfactor2

@tfactor2, it looks like JetBrains team does no check updates on closed issues. I would suggest creating a new one to get their attention.

orange-buffalo avatar Jun 03 '25 06:06 orange-buffalo

Sorry for the delayed response, and thank you for bringing this up. We’ll take a closer look at the issue and investigate further.

skybber avatar Jun 03 '25 06:06 skybber

I encountered the same when using JBRSDK, and I made a minimal test case here at https://github.com/liufuyang/jbr-mockito-issue-259 The test cases only do a simple Mockito test with mockito agent attached (so mocking static methods is allowed). When not using -XX:+AllowEnhancedClassRedefinition with JBRSDK, then it has no issue.

I think it is related to the issue above, but the internal error I saw seems a bit different:

#
# A fatal error has been detected by the Java Runtime Environment:
#
#  Internal Error (reflection.cpp:667), pid=21780, tid=37672
#  guarantee(resolved_class->is_subclass_of(member_class)) failed: must be!
#
# JRE version: OpenJDK Runtime Environment JBR-21.0.8+9-1163.62-nomod (21.0.8+9) (build 21.0.8+9-b1163.62)
# Java VM: OpenJDK 64-Bit Server VM JBR-21.0.8+9-1163.62-nomod (21.0.8+9-b1163.62, mixed mode, sharing, tiered, compressed oops, compressed class ptrs, g1 gc, windows-amd64)
# No core dump will be written. Minidumps are not enabled by default on client versions of Windows
#
JNI global refs:
JNI global refs: 16, weak refs: 0

JNI global refs memory usage: 835, weak refs: 833

OOME stack traces (most recent first):
Classloader memory used:
Loader bootstrap                                                                       : 816K
Loader jdk.internal.loader.ClassLoaders$AppClassLoader                                 : 82616B

Classes loaded by more than one classloader:
Class java.lang.ThreadBuilders$BoundVirtualThread                                     : loaded 2 times (x 109B)
Class java.net.URLStreamHandler                                                       : loaded 2 times (x 83B)
Class jdk.internal.reflect.DelegatingClassLoader                                      : loaded 2 times (x 101B)
Class sun.net.www.protocol.file.Handler                                               : loaded 2 times (x 84B)
Class java.lang.ClassLoader                                                           : loaded 2 times (x 101B)
Class java.lang.ref.Finalizer$FinalizerThread                                         : loaded 2 times (x 105B)
Class java.lang.ref.Reference$ReferenceHandler                                        : loaded 2 times (x 105B)
Class java.lang.Thread                                                                : loaded 2 times (x 105B)
Class jdk.internal.loader.ClassLoaders$BootClassLoader                                : loaded 2 times (x 110B)
Class java.security.SecureClassLoader                                                 : loaded 2 times (x 102B)
Class java.net.URLClassLoader                                                         : loaded 2 times (x 112B)
Class java.lang.VirtualThread                                                         : loaded 2 times (x 109B)
Class jdk.internal.loader.ClassLoaders$AppClassLoader                                 : loaded 2 times (x 111B)
Class java.io.FileOutputStream                                                        : loaded 2 times (x 87B)
Class sun.net.www.protocol.jar.Handler                                                : loaded 2 times (x 84B)
Class jdk.internal.loader.BuiltinClassLoader                                          : loaded 2 times (x 110B)
Class java.io.File                                                                    : loaded 2 times (x 121B)
Class jdk.internal.misc.InnocuousThread                                               : loaded 2 times (x 105B)
Class jdk.internal.loader.ClassLoaders$PlatformClassLoader                            : loaded 2 times (x 110B)
Class java.lang.BaseVirtualThread                                                     : loaded 2 times (x 108B)

# An error report file with more information is saved as:
# C:\sbs\workspace\jbr-mockito-issue\app\hs_err_pid21780.log
[0.322s][warning][os] Loading hsdis library failed
#
# If you would like to submit a bug report, please visit:
#   https://youtrack.jetbrains.com/issues/JBR
#

@skybber Thanks and let me know if you think I should create a different ticket.

liufuyang avatar Oct 27 '25 11:10 liufuyang

Thanks a lot for the reproducer! I’ll check it out and see where the problem is. No need to create a new issue.

skybber avatar Oct 27 '25 16:10 skybber

I couldn’t reproduce the crash on my side with same JBR version. According logs the JVM crashes before test execution. From your hs_err_pid*.log I see your JVM is launched with a Palo Alto agent (which I don't have):

-agentpath:C:\Program Files\Palo Alto Networks\Traps\cyjagent.dll

Could you try temporarily disabling that agent and run the test again? If it still crashes, please share the new hs_err .

Thanks!

skybber avatar Oct 27 '25 20:10 skybber

Aha, I see, thanks, I might not be able to disable the agent in my work environment without some IT help (as in my project setup it is not explicitly set, must due to some office security software set it up automatically). But now I am quite sure it might be related to that. Please consider it is resolved for me now, otherwise I will come back with updated hs_err log :)

liufuyang avatar Oct 27 '25 22:10 liufuyang