By Sven

2018-03-13 15:00:50 8 Comments

I have two example class files, one from an example Java app and one from an example C app (compiled to bytecode using LLJVM).

Looking at their outputs, I can see through javap -c -p that for initializing the (static) fields, the Java app shows the following block:

static {};
0: sipush 1339
3: putstatic   #7     //Field SRV_ID

Which is basically the <clinit> method, if I understand. Or detected as such by a VM I am using.

The C-app however has this:

public {};
0: sipush 1339
3: putstatic   #7     //Field SRV_ID

What is this? My VM does not detect it.

Sample class files. THe first one is from a Java App that prints a message and waits 20s, repeat. The second is a C app that does roughly the same.

Apologies for doing it this way - I do not immediately know how to attach files or efficiently show .class files.


@Holger 2018-03-14 09:37:58

This seems to be a nonstandard declaration that javap did not consider. Normally, static initializers are compiled to bytecode methods named <clinit> having a static modifier. Apparently, javap decodes them by just printing the human readable form of the modifier and omitting the <clinit> name.

Here, it encountered a method named <clinit> and having the public modifier (no static modifier) and just did the same as usual, printing the modifier and omitting the <clinit> name.

The code generated by LLJVM seems to rely on an old oddity:

In a class file whose version number is 51.0 or above, the method must additionally have its ACC_STATIC flag (§4.6) set in order to be the class or interface initialization method.

This requirement was introduced in Java SE 7. In a class file whose version number is 50.0 or below, a method named <clinit> that is void and takes no arguments is considered the class or interface initialization method regardless of the setting of its ACC_STATIC flag.

To me, it was truly surprising to read that in previous versions, the ACC_STATIC modifier was not mandated and I don’t see any reason to ever exploit that oddity. It seems very natural that a class initializer (that is declared static {} in Java) should have the ACC_STATIC flag and I can’t even imagine the supposed semantics of an omitted ACC_STATIC flag. It means that one of two odd things should happen, a) it is invoked without an instance despite not have the ACC_STATIC flag (being invoked as-if having it) or b) it is invoked with an instance that must have been created “magically”.

The specification says the following about any non-standard <clinit> method:

Other methods named <clinit> in a class file are of no consequence. They are not class or interface initialization methods. They cannot be invoked by any Java Virtual Machine instruction and are never invoked by the Java Virtual Machine itself.

@apangin 2018-03-14 11:56:36

It was a JVM bug JDK-6845426 fixed in JDK 7. I don't think lljvm exploited it intentionally, probably they just forgot to add ACC_STATIC, and the problem wasn't noticed as long as JVM accepted such classes. Seems like lljvm development ceased in 2010, even before Java 7 release.

@Sven 2018-03-14 12:31:39

Thank you for the detailed explanation. For the future: A way to deal with this problem is compiling the C app to a jasmin file instead of bytecode. The Jasmin file can then be edited by replacing the above public {} with static {}. When the Jasmin is then converted to bytecode, it does seem to give the standard, detectable clinit method.

Related Questions

Sponsored Content

25 Answered Questions

[SOLVED] Java inner class and static nested class

  • 2008-09-16 08:22:35
  • Omnipotent
  • 657751 View
  • 1541 Score
  • 25 Answer
  • Tags:   java inner-classes

14 Answered Questions

[SOLVED] What's the advantage of a Java enum versus a class with public static final fields?

  • 2012-04-02 00:45:37
  • Craig W
  • 96633 View
  • 118 Score
  • 14 Answer
  • Tags:   java enums

24 Answered Questions

32 Answered Questions

[SOLVED] Difference between StringBuilder and StringBuffer

24 Answered Questions

36 Answered Questions

[SOLVED] Differences between HashMap and Hashtable?

9 Answered Questions

2 Answered Questions

[SOLVED] Using ASM for bytecode analysis

0 Answered Questions

javap and generics' type erasure

7 Answered Questions

Sponsored Content