1

According to this in the old java versions there was a less restrictive version of invokespecial called invokenonvirtual. This instruction would let you invoke instance methods without virtual lookup and ,if I got that right, those methods could belong to non-assignable classes to the current one. With invokespecial this changed as it is used to only invoke super, private or initializing methods.

My questions is: Is there a way with java 8 (or higher) to bypass those structural constraints [4.9.2] of the invokespecial instruction and call without virtual lookup a method of a different class (i.e a class that is not assignment compatible with the current class)

I could use the no-verify flag to disable the verification process, but is there a more elegant way?

Manos Ntoulias
  • 513
  • 1
  • 4
  • 21

1 Answers1

4

You are conflating two different issues. invokenonvirtual and inokespecial are the same and always have been. They are just two different names for the same opcode.

The question you linked is talking about a separate feature ACC_SUPER, which has a long and complicated history of its own.

Basically, in very early versions of Java, compilation of super calls was broken. When compiling a superclass call, it would insert an invokespecial to the superclass method at time of compilation. If the class hierarchy was later changed, it would still attempt to call the method it was compiled to call, even if a new override was inserted at an intermediate point in the hierarchy.

Note that this still didn't let you invoke methods in unrelated classes - the issue only related to different overrides of the same method being added in the same inheritance change after compilation.

After the Java authors realized their mistake, they updated the JVM's handling of invokespecial to handle super calls correctly. Now, no matter which method is specified in the instruction, it will walk the superclass hierachy at link/runtime and call the appropriate method.

However, they were worried that code compiled under old versions of Java was relying on the broken behavior, so for backwards compatibility, they added a new classfile flag, ACC_SUPER. If the flag is set on a class, it has the new (correct) behavior, if it doesn't, it uses the old behavior. Since old classfiles were compiled before the flag existed, they won't have it set. Meanwhile, the compiler was updated to set ACC_SUPER on all new classes and everyone was happy...

Up until 2011 that is. It turns out that java.lang.Thread has a security sensitive method that users are not supposed to be able to call. To prevent people from calling it from subclasses of Thread, they overrode it to throw an exception. However, someone realized that hackers could define a subclass of Thread without the ACC_SUPER flag, and thus skip the security check and call the dangerous version of the method and break out of the Java sandbox.

Unfortunately, the only way to fix this security vulnerability was to remove the ACC_SUPER feature entirely - that is to treat every class as if it has the flag set, whether it actually does or not. It was hurriedly fixed in Java 7 update 13, and in Java 8, the spec itself was changed to document that ACC_SUPER no longer had any effect.

So the answer is no, there is no way to get the old behavior of super calls in any version of Java after 7u13, or whatever update it was that implemented the security fix.

Antimony
  • 37,781
  • 10
  • 100
  • 107
  • 1
    I’m not sure about the “unfortunately”. Java maintained a compatibility switch for a quarter century just for software created before version 1.0.2, *the first official release*. It’s not clear whether such software even exist, not to speak of whether it would actually run on a modern JRE. Besides that, a class file with a version number higher than 45 can not be dependent on such compatibility anyway. It’s really strange that this flag was kept in the spec for so long. Or that it has been created in the first place. – Holger Dec 17 '18 at 09:59
  • 1
    So in jvm there is no way to invoke non virtually a method of an unrelated class, except from the noverify flag. Correct? – Manos Ntoulias Dec 17 '18 at 13:08
  • 1
    You can invoke methods of other classes if you a) pass arguments of the correct time, including the hidden `this` parameter, and b) the method is visible in the class you are calling it from. – Antimony Dec 18 '18 at 06:05
  • 3
    @user3161227 `invokestatic` is non-virtual per se. Further, you can link an `invokedynamic` instruction to a non-virtual invocation if the code doing the linkage has sufficient access rights. Starting with Java 11, classes may invoke private methods of other classes if they belong to the same nest, which, of course, is far away from being unrelated. But anyway, when you’re not just asking for historical interest, it’s not clear which actual problem you want to solve. This looks much like an [xy problem](http://meta.stackexchange.com/a/66378/166789). – Holger Dec 18 '18 at 10:45