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

Test with PowerMock fails when run on java 1.7.0_65 #524

Closed
johanhaleby opened this issue Jul 25, 2015 · 34 comments
Closed

Test with PowerMock fails when run on java 1.7.0_65 #524

johanhaleby opened this issue Jul 25, 2015 · 34 comments

Comments

@johanhaleby
Copy link
Collaborator

From begul1234 on July 17, 2014 10:28:21

What steps will reproduce the problem? - Have a unit test annotated with @RunWith(PowerMockRunner.class) @PrepareForTest(MyEndpoint.class)
and use mockStatic(MyEndpoint.class); in the setUp method of the test. What is the expected output? What do you see instead? I would expect that the test runs normally and without error as it did before with older java versions (1.7.0_55 works).

Instead the test fails with the following stacktrace:
java.lang.VerifyError: Bad method call from inside of a branch Exception Details: Location: net/sample/api/endpoint/AbstractB2CJaxRsEndpoint.(Lorg/powermock/core/IndicateReloadClass;)V @41: invokespecial Reason: Error exists in the bytecode Bytecode: 0000000: 2a2b 4e4d 1210 b800 1604 bd00 0d59 032d 0000010: 5313 0126 b800 1bb8 0021 3a05 1905 b200 0000020: 25a5 000e 2a01 c000 27b7 002a a700 0a2c 0000030: 2db7 002a 0157 b1 Stackmap Table: full_frame(@47,{UninitializedThis,Object[#39],UninitializedThis,Object[#39],Top,Object[#13]},{}) full_frame(@54,{Object[#2],Object[#39],Object[#2],Object[#39],Top,Object[#13]},{})
java.lang.VerifyError: Bad method call from inside of a branch
Exception Details:
Location:
net/sample/api/endpoint/AbstractB2CJaxRsEndpoint.(Lorg/powermock/core/IndicateReloadClass;)V @41: invokespecial
Reason:
Error exists in the bytecode
Bytecode:
0000000: 2a2b 4e4d 1210 b800 1604 bd00 0d59 032d
0000010: 5313 0126 b800 1bb8 0021 3a05 1905 b200
0000020: 25a5 000e 2a01 c000 27b7 002a a700 0a2c
0000030: 2db7 002a 0157 b1
Stackmap Table:
full_frame(@47,{UninitializedThis,Object[#39],UninitializedThis,Object[#39],Top,Object[#13]},{})
full_frame(@54,{Object[#2],Object[#39],Object[#2],Object[#39],Top,Object[#13]},{})

at java.lang.Class.getDeclaredConstructors0(Native Method)
at java.lang.Class.privateGetDeclaredConstructors(Class.java:2532)
at java.lang.Class.getDeclaredConstructors(Class.java:1901)
at org.mockito.internal.creation.jmock.ClassImposterizer.setConstructorsAccessible(ClassImposterizer.java:75)
at org.mockito.internal.creation.jmock.ClassImposterizer.imposterise(ClassImposterizer.java:70)
at org.powermock.api.mockito.internal.mockcreation.MockCreator.createMethodInvocationControl(MockCreator.java:110)
at org.powermock.api.mockito.internal.mockcreation.MockCreator.mock(MockCreator.java:60)
at org.powermock.api.mockito.PowerMockito.mockStatic(PowerMockito.java:70)
at net.sample.api.endpoint.contacting.communication.peer.CommunicationTest.setUp(CommunicationTest.java:82)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.junit.internal.runners.MethodRoadie.runBefores(MethodRoadie.java:132)
at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:95)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.executeTest(PowerMockJUnit44RunnerDelegateImpl.java:296)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit49RunnerDelegateImpl$PowerMockJUnit49MethodRunner.executeTestInSuper(PowerMockJUnit49RunnerDelegateImpl.java:116)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit49RunnerDelegateImpl$PowerMockJUnit49MethodRunner.executeTest(PowerMockJUnit49RunnerDelegateImpl.java:77)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runBeforesThenTestThenAfters(PowerMockJUnit44RunnerDelegateImpl.java:284)
at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:86)
at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:49)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.invokeTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:209)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.runMethods(PowerMockJUnit44RunnerDelegateImpl.java:148)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$1.run(PowerMockJUnit44RunnerDelegateImpl.java:122)
at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:33)
at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:45)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.run(PowerMockJUnit44RunnerDelegateImpl.java:120)
at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.run(JUnit4TestSuiteChunkerImpl.java:101)
at org.powermock.modules.junit4.common.internal.impl.AbstractCommonPowerMockRunner.run(AbstractCommonPowerMockRunner.java:53)
at org.powermock.modules.junit4.PowerMockRunner.run(PowerMockRunner.java:53)
at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:249)
at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:142)
at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:113)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:189)
at org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:165)
at org.apache.maven.surefire.booter.ProviderFactory.invokeProvider(ProviderFactory.java:85)
at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:104)
at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:75) What version of the product are you using? On what operating system? PowerMock 1.5.5 on MacOSX or Linux Please provide any additional information below.

Original issue: http://code.google.com/p/powermock/issues/detail?id=504

@johanhaleby
Copy link
Collaborator Author

From JDever...@gmail.com on August 13, 2014 13:34:22

I believe the original bug was patched in 1.7's 67 patch, but the bug still seems to exist with PowerMock...

@johanhaleby
Copy link
Collaborator Author

From awo...@fedora-commons.org on August 19, 2014 06:29:08

This is a show-stopper for our use of PowerMock. Are there plans on the horizon? or is the recommendation to move to a different test library?

@johanhaleby
Copy link
Collaborator Author

From epa...@gmail.com on August 19, 2014 13:03:07

I wonder if PowerMock needs to be rebuilt with a newer JDK version.

@johanhaleby
Copy link
Collaborator Author

From thinking...@gmail.com on August 20, 2014 14:47:48

There is a work-around for this issue: run the junit tests with a '-noverify' jvm argument

@johanhaleby
Copy link
Collaborator Author

From lauri.va...@gmail.com on August 21, 2014 05:21:03

I added a comment to https://issues.jboss.org/browse/JASSIST-228 that suggest another workaround for this problem. (unfortunatelly they are maintaining their server currently and i cannot quote myself from there)

However, if you still feel that you need to have your java class file verifyed (hence -noverify is out for you) you can use -XX:-UseSplitVerifier option when you start your tests.

And if you are like me, and start your tests with maven, then you need to add something similar to your pom.xml



org.apache.maven.plugins
maven-surefire-plugin
2.10

-XX:-UseSplitVerifier



@johanhaleby
Copy link
Collaborator Author

From johan.ha...@gmail.com on August 24, 2014 23:00:22

I'm not sure if there's anything I can do from the PowerMock side to improve this?

@johanhaleby
Copy link
Collaborator Author

From johan.ha...@gmail.com on August 24, 2014 23:01:22

Issue 505 has been merged into this issue.

@johanhaleby
Copy link
Collaborator Author

From f...@noidea.de on August 27, 2014 06:06:57

You must avoid branching before a super call.

You could change the ExprEditor in the MainMockTransformer Line 269-273 to use no branching. Or use branching only if really needed and verify it. (I don't know how to call the JVM verifier, using CtClasses .toClass().getDeclaredConstructors() would throw a Exception) From thereon you could show a nice error message explaining the details.

@johanhaleby
Copy link
Collaborator Author

From johan.ha...@gmail.com on August 27, 2014 10:34:49

Could you help out and provide a pull request for this? That would be great.

@johanhaleby
Copy link
Collaborator Author

From johan.ha...@gmail.com on August 28, 2014 04:39:32

Hmm I really would like to solve this but I'm not sure how to solve this without branching..

@johanhaleby
Copy link
Collaborator Author

From f...@noidea.de on August 28, 2014 05:18:03

Just disable constructor mocking if

    CtClass ctClass = ClassPool.getDefault().makeClass("TestForBadOperandWhenInvokingInit");

    //      java.lang.VerifyError: Bad operand type when invoking \<init>
    ctClass.addConstructor(CtNewConstructor.make(new CtClass[0], new CtClass[0], "{if (1 != 2){ super();}}", ctClass));
    final Class<?> clazz = ctClass.toClass();

    clazz.getDeclaredConstructors();

throws an Exception and log it out. There is already a fix commited for the next JDK version, so this bug should not haunt us for long.

@johanhaleby
Copy link
Collaborator Author

From matt.mil...@gmail.com on August 28, 2014 22:07:07

I don't believe that this is a bug in the JDK. Oracle has decided to make their byte code verification rules stricter-details here http://www.takipiblog.com/oracles-latest-java-8-update-broke-your-tools-how-did-it-happen/ .

I also don't believe that there will be a fix in future versions of java as it is not a bug it is a feature. Oracle Java 8u20 still has this "feature".

The suggestion to use the SplitVerifier may work in Java 7 but I believe that the SplitVerifier has been removed in java 8. There is the option to turn off verification completely for tests (ie -noverify) but the confidence is lost that your code will work in production without this option and I don't think disabling bytecode verification in production is a great idea.

The OpenJDK team may of reverted the change but I don't think oracle will be so nice :)

The only real option is to fix the offending PowerMock class.

@johanhaleby
Copy link
Collaborator Author

From johan.ha...@gmail.com on August 28, 2014 22:22:57

If you're right we need to figure out a way to fix it. How it works now is that before the call to super the MockGateway is invoked to decide whether or not to call the super method or call another constructor (generated by PowerMock). This is used for constructor suppression (suppress(constructor(X.class))) if I remember it correctly. All method invocations, field invocations etc works in the same way (they all ask the MockGateway if they should continue or replace the call with a mock). For constructors I'm not sure how to solve this unless we insert this if statement (which I believe is the cause of the error) before the super call in the constructor byte-code. If you have any ideas for a workaround I would be really happy.

A really ugly work-around would be to let the user somehow configure PowerMock not to byte-code manipulate constructors (if you don't need to use this functionality). That way I assume that some errors can go away but PowerMock will be left in a degraded state. Not sure if I want to go down this route.. However I've been thinking about implementing something like this before to speed up the byte-code manipulation (such as turing off field interception which is quite slow and not used very often afaik).

Status: Accepted

@johanhaleby
Copy link
Collaborator Author

From jam...@gmail.com on September 16, 2014 03:41:59

Hey guys, any progress on this?
It is affecting us too.

Thanks.

@johanhaleby
Copy link
Collaborator Author

From BinisBe...@gmail.com on September 19, 2014 05:25:47

ctClass.addConstructor(CtNewConstructor.make(new CtClass[0], new CtClass[0], "{if (1 != 2){ super();}}", ctClass));

Looks like this line makes new constructor with code. Right?

{if (1 != 2){ super();}}". Not sure why 1 != 2 check is needed but this is what is causing the problem. the first thing you have to invoke in the constructor is the super constructor. So probably it should be something like this {super(); if (1 != 2) {}}

@johanhaleby
Copy link
Collaborator Author

From f...@noidea.de on September 19, 2014 05:29:50

This might be the simplified version you could use to reproduce the error..
The original code is:

code.append("if(value == ").append(MockGateway.class.getName()).append(".PROCEED) {");
code.append(" $_ = $proceed($$);");
code.append("} else {");
code.append(" $_ = ").append(getCorrectReturnValueType(returnTypeAsCtClass)).append(";");
code.append("}}");

It is there to decide if another constructor should be called.. that code must be changed to call super() first. YOu would loose the ability of on demand constructor mocking.. or you would have to replace the mocked constructors during mocking.

@johanhaleby
Copy link
Collaborator Author

From matt.mil...@gmail.com on September 23, 2014 18:30:00

So I had a chat to some of of the developers here and I've learnt that the Oracle JDK is built on top of OpenJDK so any fixes made in OpenJDK will find their way through to the Oracle JDK. Therefore this "feature" has been reverted as per this issue https://bugs.openjdk.java.net/browse/JDK-8051012 and we just need to wait for the relevant version to be released. For java 8 it looks like 8u20 b31 has it fixed, the latest public release is for 8u20 is b26 so the fix hasn't been released yet. I couldn't find a release date for build 31 anywhere.

@johanhaleby
Copy link
Collaborator Author

From johan.ha...@gmail.com on September 23, 2014 22:10:50

Thanks a lot for sharing this.

@johanhaleby
Copy link
Collaborator Author

From jrh...@gmail.com on October 14, 2014 13:48:02

As an FYI: this appears to no longer be an issue on Oracle JDK7u72.

@johanhaleby
Copy link
Collaborator Author

From johan.ha...@gmail.com on October 14, 2014 22:12:09

Thanks, good to know

@johanhaleby
Copy link
Collaborator Author

From jeff.pa...@gmail.com on October 15, 2014 15:43:35

I'm still getting it with Oracle MacOS, java full version "1.7.0_72-b14"

@johanhaleby
Copy link
Collaborator Author

From jrh...@gmail.com on October 16, 2014 06:13:04

That's weird - same OS and same build and update version here. I'm not sure what the difference is there.

@johanhaleby
Copy link
Collaborator Author

From johan.ha...@gmail.com on October 16, 2014 06:40:35

Perhaps you have different test scenarios? It works in some cases but fails in others?! But then it could be another issue altogether?

@johanhaleby
Copy link
Collaborator Author

From emla...@gmail.com on October 16, 2014 15:09:31

Oracle released 8U25 on October 14th and this jdk fixed this error for me.

@johanhaleby
Copy link
Collaborator Author

From Cameron...@gmail.com on October 23, 2014 14:21:26

Simply to give another voice, installing jdk1.7.0_72 fixed this for me as well.

@johanhaleby
Copy link
Collaborator Author

From japear...@agiledigital.com.au on November 06, 2014 22:07:34

For reference, the bug that is apparently fixed is: http://bugs.java.com/view_bug.do?bug_id=8051012 It is referenced from this page: http://www.oracle.com/technetwork/java/javase/2col/7u72-bugfixes-2298229.html I presume the bug isn't marked as resolved, because update 72, is some weird sort of halfway release, where Oracle recommends you use update 71 unless you need fixes from 72: http://www.oracle.com/technetwork/java/javase/7u72-relnotes-2296190.html

@johanhaleby
Copy link
Collaborator Author

From rubenale...@gmail.com on November 17, 2014 16:02:48

This issue is present for me I tried 72.
It works with the UseSplitVerifier option. But, that will be deprecated: https://code.google.com/p/powermock/issues/detail?id=504 So, unless this is fixed, will have to migrate to a different framework. I'll take a look to the code later on to see if there is something I can help with.

@johanhaleby
Copy link
Collaborator Author

From iamascr...@gmail.com on January 04, 2015 15:41:14

fwiw - I was experiencing the issue on 7u71, but it is ok on 7u72.

@johanhaleby
Copy link
Collaborator Author

From kguel...@gmail.com on January 12, 2015 03:37:31

7u72 fixed this for me.

@johanhaleby
Copy link
Collaborator Author

From q...@cyngn.com on January 20, 2015 10:41:18

for Java SE 8u20
java version "1.8.0_20"
Java(TM) SE Runtime Environment (build 1.8.0_20-b26)

add the following to pom.xml

org.apache.maven.plugins
maven-surefire-plugin
2.12.4

-noverify

It should work if you are using Java SE 8u25

java version "1.8.0_25"
Java(TM) SE Runtime Environment (build 1.8.0_25-b17)
Java HotSpot(TM) 64-Bit Server VM (build 25.25-b02, mixed mode)

@johanhaleby
Copy link
Collaborator Author

From chirag.o...@gmail.com on February 23, 2015 23:14:33

For Java SE 8u25, is it working other except option -noverify ?

@johanhaleby
Copy link
Collaborator Author

From f...@noidea.de on May 08, 2015 00:47:57

I would close this issue as it is either fixed with jdk 7u72, jdk 8u25 or can be circumvented with -noverify.

@johanhaleby
Copy link
Collaborator Author

From johan.ha...@gmail.com on May 08, 2015 02:26:01

Ok I'm closing it for now.

Status: WontFix

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant