3

While trying to understand a behavior of TestNG I found my self disassembling the .class files. During that, I accidentally noticed that the official binary differs from the one built manually from source and from the source itself.

The reason I disassembled the binaries was just to prove that the binary really lacks local variable tables (and for fun), since I was unable inspecting local variables.

I built the source from the project repository at Tag 6.11. using Gradle.

In the first place I inspected both using javap -l -p TestNG.class, writing the output into two separate files and diffing the resulting descriptions. So far so good.

Then, for fun, I disassembled both class files using these commands:

javap -c -p /tmp/TestNG.mvn.class > /tmp/TestNG.mvn.java
javap -c -p /tmp/TestNG.mine.class > /tmp/TestNG.mine.java

Then I diffed both and accidently found the private field m_executionListeners to be missing.

--- /tmp/TestNG.mvn.java      2017-06-03 23:12:16.005211337 +0200
+++ /tmp/TestNG.mine.java     2017-06-03 23:12:08.245208191 +0200
@@ -92,6 +92,8 @@

   protected long m_start;

+  private final java.util.Map<java.lang.Class<? extends org.testng.IExecutionListener>, org.testng.IExecutionListener> m_executionListeners;
+

(No, its declaration did not just move around, it's gone.)

So I thought it could be some kind of compiler optimization. But it is actually referenced and accessed two times. This is one access:

public void addListener(ITestNGListener listener) {
   if (listener == null) {
     return;
   }
   if (listener instanceof ISuiteListener) {
     ISuiteListener suite = (ISuiteListener) listener;
     maybeAddListener(m_suiteListeners, suite.getClass(),  suite);
   }
   // ...
   if (listener instanceof IExecutionListener) {
     IExecutionListener execution = (IExecutionListener) listener;
     maybeAddListener(m_executionListeners, execution.getClass(), execution);
   }
   // ...
 }

See the source

All other fields that run through the instanceof check, type cast and maybeAddListener() call are still present.

Am I right, with my conclusion, that the binary has not been built from the (supposed-to-be) related source? Or what it going on here?

5

You are correct that the binary does not match the tagged source. It does, however, match the changes made in commit 6cfc6b4a403f8487d9fa96aa3d42db7848c8755a, which was made on February 25, one day after the most recent commit tagged 6.11 and before the most recent merge commit in 6.11.

I can only speculate, but it seems likely that their local version of 6.11 includes an extra commit or two that they accidentally left out of the tag on Github.

Your Answer

By clicking "Post Your Answer", you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.