Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javap output: difference static {} and public {}

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 {};
Code: 
0: sipush 1339
3: putstatic   #7     //Field SRV_ID
etc

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 {};
Code: 
0: sipush 1339
3: putstatic   #7     //Field SRV_ID
etc

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.

http://www.fast-files.com/getfile.aspx?file=156962

http://www.fast-files.com/getfile.aspx?file=156961

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

like image 996
Sven Avatar asked Mar 13 '18 15:03

Sven


1 Answers

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.

like image 96
Holger Avatar answered Sep 19 '22 02:09

Holger