Skip to content
Advertisement

How to get arround java.lang.verrifyError

I am trying to generate a random number with the instrumented code. For that I have added following expression to generate a random number. But it is throwing a verify Error as given below.

method.addLocalVariable("instMethod_correlationId", CtClass.longType);
beforeBuilder.append("instMethod_correlationId = Long.valueOf(String.valueOf(System.nanoTime()) + String.valueOf(Math.round(Math.random())));");

I have added a long variable and assign the above generated value. But I am getting following exception during the run time. But if I run the same number generation in a normal project it doesn’t throw any exceptions.

java.lang.VerifyError: Bad type on operand stack
Exception Details:
  Location:
    org/h2/jdbc/JdbcConnection.prepareStatement(Ljava/lang/String;)Ljava/sql/PreparedStatement; @38: i2l
  Reason:
    Type 'java/lang/Long' (current frame, stack[0]) is not assignable to integer
  Current Frame:
    bci: @38
    flags: { }
    locals: { 'org/h2/jdbc/JdbcConnection', 'java/lang/String', top, long, long_2nd }
    stack: { 'java/lang/Long' }
  Bytecode:
    0000000: b803 6c42 bb03 6e59 b703 6fb8 036c b803
    0000010: 73b6 0376 b803 7cb8 0380 b803 73b6 0376
    0000020: b603 81b8 0386 8537 05b8 038b b803 8e16
    0000030: 0513 0390 b603 94bb 0396 59b7 0397 3a07
    0000040: 1907 1303 992b b903 9d03 0057 b803 8bb8
    0000050: 038e 1605 1303 9f19 07b6 03a2 2a06 b600
    0000060: 113d 2ab6 002a 9900 272a 1237 061c bb00
    0000070: 1659 b700 1712 38b6 0019 2a2b b600 1db6
    0000080: 0019 1234 b600 19b6 0020 b600 2d2a b600
    0000090: 2e2a 2bb7 0039 4cbb 003a 592a 2b1c 1103
    00000a0: ebb2 0030 03b7 003b a700 0a4d 2a2c b600
    00000b0: 28bf 3a09 bb03 9659 b703 973a 0a19 0a13
    00000c0: 03a4 1303 a6b9 039d 0300 57b8 038b b803
    00000d0: 8e16 05bb 036e 59b7 036f 1303 a8b6 0376
    00000e0: b803 6c21 65b8 0373 b603 76b6 0381 190a
    00000f0: b603 a219 09b0                         
  Exception Handler Table:
    bci [55, 168] => handler: 171
  Stackmap Table:
    full_frame(@141,{Object[#320],Object[#331],Integer,Long,Long,Object[#918]},{})
    full_frame(@171,{Object[#320],Object[#331],Top,Long,Long},{Object[#322]})
    full_frame(@178,{Object[#320],Object[#331],Integer,Long,Long,Object[#918]},{Object[#58]})

    at org.h2.Driver.connect(Driver.java:73)
    at org.apache.tomcat.jdbc.pool.PooledConnection.connectUsingDriver(PooledConnection.java:278)
    at org.apache.tomcat.jdbc.pool.PooledConnection.connect(PooledConnection.java:182)
    at org.apache.tomcat.jdbc.pool.ConnectionPool.createConnection(ConnectionPool.java:701)
    at org.apache.tomcat.jdbc.pool.ConnectionPool.borrowConnection(ConnectionPool.java:635)
    at org.apache.tomcat.jdbc.pool.ConnectionPool.getConnection(ConnectionPool.java:188)
    at org.apache.tomcat.jdbc.pool.DataSourceProxy.getConnection(DataSourceProxy.java:128)
    at org.wso2.carbon.user.core.claim.dao.ClaimDAO.getDialectCount(ClaimDAO.java:158)
    at org.wso2.carbon.user.core.common.DefaultRealm.populateProfileAndClaimMaps(DefaultRealm.java:429)
    at org.wso2.carbon.user.core.common.DefaultRealm.init(DefaultRealm.java:105)
    at org.wso2.carbon.user.core.common.DefaultRealmService.initializeRealm(DefaultRealmService.java:262)
    at org.user.core.common.DefaultRealmService.<init>(DefaultRealmService.java:99)
    at org.user.core.common.DefaultRealmService.<init>(DefaultRealmService.java:112)
    at org.user.core.internal.Activator.startDeploy(Activator.java:68)
    at org.user.core.internal.BundleCheckActivator.start(BundleCheckActivator.java:61)
    at org.eclipse.osgi.framework.internal.core.BundleContextImpl$1.run(BundleContextImpl.java:711)
    at java.security.AccessController.doPrivileged(Native Method)
    at org.eclipse.osgi.framework.internal.core.BundleContextImpl.startActivator(BundleContextImpl.java:702)
    at org.eclipse.osgi.framework.internal.core.BundleContextImpl.start(BundleContextImpl.java:683)
    at org.eclipse.osgi.framework.internal.core.BundleHost.startWorker(BundleHost.java:381)
    at org.eclipse.osgi.framework.internal.core.AbstractBundle.resume(AbstractBundle.java:390)
    at org.eclipse.osgi.framework.internal.core.Framework.resumeBundle(Framework.java:1176)
    at org.eclipse.osgi.framework.internal.core.StartLevelManager.resumeBundles(StartLevelManager.java:559)
    at org.eclipse.osgi.framework.internal.core.StartLevelManager.resumeBundles(StartLevelManager.java:544)
    at org.eclipse.osgi.framework.internal.core.StartLevelManager.incFWSL(StartLevelManager.java:457)
    at org.eclipse.osgi.framework.internal.core.StartLevelManager.doSetStartLevel(StartLevelManager.java:243)
    at org.eclipse.osgi.framework.internal.core.StartLevelManager.dispatchEvent(StartLevelManager.java:438)
    at org.eclipse.osgi.framework.internal.core.StartLevelManager.dispatchEvent(StartLevelManager.java:1)
    at org.eclipse.osgi.framework.eventmgr.EventManager.dispatchEvent(EventManager.java:230)
    at org.eclipse.osgi.framework.eventmgr.EventManager$EventThread.run(EventManager.java:340)

What should I do to overcome this? What am I doing wrong here?

Advertisement

Answer

It seems you hit a bug in Javassist’s byte code generator. Here is the disassembled code as reported from the VerifyError. Note that due to the absence of the constant pool in the exception message, the actual target methods are guessed from your source code (but it looks plausible):

  0 invokestatic    [876]
  3 lstore_3
  4 new     [878]          guess: new StringBuilder
  7 dup
  8 invokespecial   [879]  guess: StringBuilder.<init>
 11 invokestatic    [876]  guess: System.nanoTime()
 14 invokestatic    [883]  guess: String.valueOf(long)
 17 invokevirtual   [886]  guess: StringBuilder.append(String)
 20 invokestatic    [892]  guess: Math.random()
 23 invokestatic    [896]  guess: Math.round(double)
 26 invokestatic    [883]  guess: String.valueOf(long)
 29 invokevirtual   [886]  guess: StringBuilder.append(String)
 32 invokevirtual   [897]  guess: StringBuilder.toString() 
 35 invokestatic    [902]  guess: Long.valueOf(String)
 38 i2l
 39 lstore  <5>
… rest omitted

Note that the method invocations match your source code fragment (being static or virtual as expected and being the same reference where supposed to be the same), whereas the instruction at location 38, the one rejected by the verifier, is a spurious i2l instruction (a conversion from int to long). At this place, an unboxing conversion from Long to long should happen. Since the following lstore instruction will store a long value into a local variable, it seems that Javassist got your local variable declaration right.

Note that the first two instructions indicate that there is another instrumentation happening; since it’s invoking the same method as the instruction at location 11, which is supposed to be System.nanoTime, it seems the other instrumentation is intended to measure the method’s overall execution time. But that shouldn’t affect your instrumentation code.

You may contact the authors of Javassist to find out whether Long unboxing should work. At the same time, you may workaround the problem by using Long.parseLong instead of Long.valueOf to avoid the boxing/unboxing in the first place. You may also simplify the operation from the generated code’s perspective by using String.concat instead of the + operator as this eliminates the need to deal with StringBuilder internally:

Replace

method.addLocalVariable("instMethod_correlationId", CtClass.longType);
beforeBuilder.append("instMethod_correlationId = Long.valueOf(String.valueOf(System.nanoTime()) + String.valueOf(Math.round(Math.random())));");

with

method.addLocalVariable("instMethod_correlationId", CtClass.longType);
beforeBuilder.append("instMethod_correlationId = Long.parseLong(String.valueOf(System.nanoTime()).concat(String.valueOf(Math.round(Math.random()))));");

This should lower the requirements to Javassist’s compiling capabilities and workaround the bug triggered by your original code fragment.


Update: for those, interested in decoding the hex dump of a VerifyError to a readable instruction sequence: Online Decoder using tio.run

User contributions licensed under: CC BY-SA
8 People found this is helpful
Advertisement