byte-buddy icon indicating copy to clipboard operation
byte-buddy copied to clipboard

VerifyError: Bad access to protected data in invokevirtual

Open perlun opened this issue 2 years ago • 3 comments

Hi,

Similarly as in https://github.com/raphw/byte-buddy/issues/539, we are seeing <subj> when trying to use ByteBuddy in our code base. More specifically, this exception (note that the bytecode is different to the one in that issue):

java.lang.VerifyError: Bad access to protected data in invokevirtual
Exception Details:
  Location:
    fi/hibox/centre/domain/service/PackageService$ByteBuddy$XKOo4HgE.clone()Ljava/lang/Object; @3: invokevirtual
  Reason:
    Type 'fi/hibox/centre/domain/service/PackageService' (current frame, stack[0]) is not assignable to 'fi/hibox/centre/domain/service/PackageService$ByteBuddy$XKOo4HgE'
  Current Frame:
    bci: @3
    flags: { }
    locals: { 'fi/hibox/centre/domain/service/PackageService$ByteBuddy$XKOo4HgE' }
    stack: { 'fi/hibox/centre/domain/service/PackageService' }
  Bytecode:
    0x0000000: b200 0cb6 000e b0                      


	at java.lang.Class.getDeclaredFields0(Native Method)
	at java.lang.Class.privateGetDeclaredFields(Class.java:2583)
	at java.lang.Class.getDeclaredField(Class.java:2068)
	at net.bytebuddy.implementation.LoadedTypeInitializer$ForStaticField.onLoad(LoadedTypeInitializer.java:163)
	at net.bytebuddy.implementation.LoadedTypeInitializer$Compound.onLoad(LoadedTypeInitializer.java:234)
	at net.bytebuddy.dynamic.TypeResolutionStrategy$Passive.initialize(TypeResolutionStrategy.java:103)
	at net.bytebuddy.dynamic.DynamicType$Default$Unloaded.load(DynamicType.java:6325)
	at net.bytebuddy.dynamic.DynamicType$Default$Unloaded.load(DynamicType.java:6313)
	at fi.hibox.centre.domain.immutable.AbstractIdentifiableEntityBuilder.buildTemporaryInstance(AbstractIdentifiableEntityBuilder.java:121)
	at fi.hibox.centre.server.internalbilling.billingrules.NextIntervalSubscriptionBill.calculateBill(NextIntervalSubscriptionBill.java:59)
	at fi.hibox.centre.server.internalbilling.billingrules.AbstractPriceSourceAwareBillingRule.calculateBill(AbstractPriceSourceAwareBillingRule.java:47)
	at fi.hibox.centre.server.internalbilling.billingrules.AbstractBillingRule.createServiceBill(AbstractBillingRule.java:34)
	at fi.hibox.centre.server.internalbilling.DefaultBillingRuleSet.createServiceBill(DefaultBillingRuleSet.java:78)
	at fi.hibox.centre.server.commerce.ServiceBillTestUtil.createServiceBill(ServiceBillTestUtil.java:61)
	at fi.hibox.centre.client.services.RegistrationServiceTest$1.answer(RegistrationServiceTest.java:168)
	at fi.hibox.centre.client.services.RegistrationServiceTest$1.answer(RegistrationServiceTest.java:165)
	at org.mockito.internal.stubbing.StubbedInvocationMatcher.answer(StubbedInvocationMatcher.java:42)
	at org.mockito.internal.handler.MockHandlerImpl.handle(MockHandlerImpl.java:103)
	at org.mockito.internal.handler.NullResultGuardian.handle(NullResultGuardian.java:29)
	at org.mockito.internal.handler.InvocationNotifierHandler.handle(InvocationNotifierHandler.java:34)
	at org.mockito.internal.creation.bytebuddy.MockMethodInterceptor.doIntercept(MockMethodInterceptor.java:82)
	at org.mockito.internal.creation.bytebuddy.MockMethodInterceptor.doIntercept(MockMethodInterceptor.java:56)
	at org.mockito.internal.creation.bytebuddy.MockMethodInterceptor$DispatcherDefaultingToRealMethod.interceptAbstract(MockMethodInterceptor.java:161)
	at fi.hibox.centre.protocol.CentreServer$MockitoMock$nfiFyNVm.getCalculatedServiceBill(Unknown Source)
	at fi.hibox.centre.client.services.RegistrationService.getAccountSubscriptionServiceBill(RegistrationService.java:292)
	at fi.hibox.centre.client.services.RegistrationService.applyAccountSubscriptionVoucher(RegistrationService.java:460)
	at fi.hibox.centre.client.services.RegistrationServiceTest.testApplyAccountSubscriptionVoucher(RegistrationServiceTest.java:216)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at java.util.ArrayList.forEach(ArrayList.java:1259)
	at java.util.ArrayList.forEach(ArrayList.java:1259)

The calling code (where we try to create the ByteBuddy-based instance) looks like this. It's the load( getClass().getClassLoader() ) call that fails.

    public final T buildTemporaryInstance() {
        T instance = create();

        try {
            return (T)new ByteBuddy()
                    .subclass( this.instance.getClass() )
                    .method( named( "builder" ) ).intercept( throwing( IllegalStateException.class, "can't create builder from temporary " + instance.getClass().getSimpleName() + " instance" ) )
                    .method( any() ).intercept( MethodCall.invokeSelf().on( instance ).withAllArguments() )
                    .make()
                    .load( getClass().getClassLoader() )
                    .getLoaded()
                    .newInstance();
        }
        catch ( InstantiationException | IllegalAccessException e ) {
            throw new RuntimeException( e );
        }
    }

I looked at this in the debugger and I get the feeling that ByteBuddy somehow fails to get the fields from the type it has defined itself. :thinking: But I am clearly not an expert on the ByteBuddy internals so this may clearly be an incorrect understanding of the problem at hand.

image

I realize that this might be hard to say much about without a MCVE, but do you have any obvious ideas of what could go wrong here, or where we could/should look next? If so, much appreciated. :bow:

(ByteBuddy version: 1.14.11. JDK versions: reproduced on JDK 8, 17 and 21)

perlun avatar Dec 28 '23 14:12 perlun

#539 gave some good hints of what the problem was: the superclass constructor was package-protected but needs to be at least protected for this to work (with the default class loading strategy).

slovdahl avatar Dec 29 '23 09:12 slovdahl

Yep, thanks for noting this down for the sake of other people. :bow: I'll leave this open for now in case @raphw or anyone else wants to improve the UX here, to make it easier for people running into this to know how they need to modify their code.

perlun avatar Dec 29 '23 11:12 perlun

That's a tricky thing because the class loading will actually implicate a visibility here. This cannot be decided during compilation, and might be legal when loading, this is why it is not failing the class creation.

raphw avatar Jan 04 '24 21:01 raphw