Examining bytecode, I've noticed javac seems to duplicate checkcast instructions when casting to array types.
Cast.java:
class Cast {
void test(Object a) {
Object[] b = (Object[]) a;
}
}
javap disassembly of the javac compiled version
void test(java.lang.Object);
Code:
0: aload_1
1: checkcast #2; //class "[Ljava/lang/Object;"
4: checkcast #2; //class "[Ljava/lang/Object;"
7: astore_2
8: return
Testing jikes shows the expected single cast
void test(java.lang.Object);
Code:
0: aload_1
1: checkcast #10; //class "[Ljava/lang/Object;"
4: astore_2
5: return
checkcast is supposed to raise an exception if the object can't be treated as the requested type and otherwise does nothing, so I don't see why it might help to double the cast. I haven't looked at the JDK sources to see how it's produced, and if that helps explain the why (maybe it's meant as a hint).
It is a known bug of javac. But it is mostly harmless.
Related
I have an old application which refuses to start on versions of Java that it was not tested on. Unfortunately it is an abandonware, so there is little chance for it to be updated. It is complaining that JVM is made by Oracle rather than Sun.
Back in days of MS DOS there was a setver command which allowed one to set a version of the operating system that an application saw, is there something similar to that on JVM?
I would use the asmtools from the OpenJDK project to disassemble the files to a bytecode assembly format.
So for example a helloworld looks like this (jdis NameOfClass.class>NameOfClass.j):
super public class A
version 59:0
{
public Method "<init>":"()V"
stack 1 locals 1
{
aload_0;
invokespecial Method java/lang/Object."<init>":"()V";
return;
}
public static Method main:"([Ljava/lang/String;)V"
stack 2 locals 1
{
getstatic Field java/lang/System.out:"Ljava/io/PrintStream;";
ldc String "Hello World!";
invokevirtual Method java/io/PrintStream.println:"(Ljava/lang/String;)V";
return;
}
} // end Class A
After that you edit the file:
super public class A
version 59:0
{
public Method "<init>":"()V"
stack 1 locals 1
{
aload_0;
invokespecial Method java/lang/Object."<init>":"()V";
return;
}
public static Method main:"([Ljava/lang/String;)V"
stack 2 locals 1
{
getstatic Field java/lang/System.out:"Ljava/io/PrintStream;";
ldc String "Hello Stackoverflow!";
invokevirtual Method java/io/PrintStream.println:"(Ljava/lang/String;)V";
return;
}
} // end Class A
And then you can compile it to .class again:
jasm NameOfClass.j
and then you can run it normally with Java.
This was just an example.
You would just have to find the class with the method that checks for the version. For example you could unzip the jar files and if for example the message for a non-matching version is, for example:
"Bad version detected: "
You can just grep for it (grep -R Bad.version) and then you get the class.
There you will have to change the method responsible for checking the Java version.
An example:
A.java:
public class A{
static boolean hasMatchingJavaVersion() {
return System.getProperty("java.version").matches("1.4.*");//Just Java 1.4
}
public static void main(String[] args) {
if(hasMatchingJavaVersion()) {
System.out.println("Matches");
} else {
System.out.println("Bad version");
System.exit(-1);
}
}
}
Run it: false (On Java 15, e.g.)
As assembly.
super public class A
version 59:0
{
public Method "<init>":"()V"
stack 1 locals 1
{
aload_0;
invokespecial Method java/lang/Object."<init>":"()V";
return;
}
static Method hasMatchingJavaVersion:"()Z"
stack 2 locals 0
{
ldc String "java.version";
invokestatic Method java/lang/System.getProperty:"(Ljava/lang/String;)Ljava/lang/String;";
ldc String "1.4.*";
invokevirtual Method java/lang/String.matches:"(Ljava/lang/String;)Z";
ireturn;
}
public static Method main:"([Ljava/lang/String;)V"
stack 2 locals 1
{
invokestatic Method hasMatchingJavaVersion:"()Z";
ifeq L17;
getstatic Field java/lang/System.out:"Ljava/io/PrintStream;";
ldc String "Matches";
invokevirtual Method java/io/PrintStream.println:"(Ljava/lang/String;)V";
goto L29;
L17: stack_frame_type same;
getstatic Field java/lang/System.out:"Ljava/io/PrintStream;";
ldc String "Bad version";
invokevirtual Method java/io/PrintStream.println:"(Ljava/lang/String;)V";
iconst_m1;
invokestatic Method java/lang/System.exit:"(I)V";
L29: stack_frame_type same;
return;
}
} // end Class A
This method checks for the version:
static Method hasMatchingJavaVersion:"()Z"
stack 2 locals 0
{
ldc String "java.version";
invokestatic Method java/lang/System.getProperty:"(Ljava/lang/String;)Ljava/lang/String;";
ldc String "1.4.*";
invokevirtual Method java/lang/String.matches:"(Ljava/lang/String;)Z";
ireturn;
}
So you could for example change it to:
static Method hasMatchingJavaVersion:"()Z"
stack 2 locals 0
{
iconst_1;//Load true, always return true
ireturn;
}
And then compile it again with jasm.
Edit:
that JVM is made by Oracle rather than Sun.
I overread this, but it works the same way as described above, just another system property and some other minor changes,
JUnit 5 masks checked exceptions with this code:
public static RuntimeException throwAsUncheckedException(Throwable t) {
Preconditions.notNull(t, "Throwable must not be null");
ExceptionUtils.throwAs(t);
// Appeasing the compiler: the following line will never be executed.
return null;
}
#SuppressWarnings("unchecked")
private static <T extends Throwable> void throwAs(Throwable t) throws T {
throw (T) t;
}
In the call to throwAs, how does Java decide on the value of the type variable T?
More importantly, how does this code mask a checked exception?
I believe that T is inferred to be RuntimeException. I'm inferring that from making the following change to the code of throwAsUncheckedException:
var o = ExceptionUtils.throwAs(t);
... and changing the declaration of throwAs to:
private static <T extends Throwable> T throwAs(Throwable t) throws T
(Note that I'm using var from Java 10 to let the compiler infer the type without any further information being provided.)
After compiling and then using javap -c you can see that there's a checkcast to RuntimeException:
invokestatic #2 // Method throwAs:(Ljava/lang/Throwable;)Ljava/lang/Throwable;
checkcast #3 // class java/lang/RuntimeException
astore_1
That makes it fine for throwAs not to declare that it throws anything else - it's only calling a method that declares that it throws T, so RuntimeException in this case.
Further somewhat specious evidence for this is in JLS section 18, which includes this line:
Otherwise, if the bound set contains throws αi, and each proper upper bound of αi is a supertype of RuntimeException, then Ti = RuntimeException.
No other concrete exception types, or Throwable, are mentioned in that section. Unfortunately I find section 18 pretty much impenetrable, so this is really more of a "yes, that vaguely supports my theory" rather than good evidence.
In this particular case, I believe it would actually be fine (and simpler in terms of understanding) for the throwAsUncheckedException method to just specify the type argument explicitly:
ExceptionUtils.<RuntimeException>throwAs(t);
So that's how the compiler is molified. It thinks that only RuntimeException will be thrown. The actual value thrown is whatever's passed in though. The cast to T is ignored for all the normal type erasure reasons... if you change the code to actually cast to RuntimeException, it will fail for any checked exception. That's why it needs to be a generic method: to include a cast that satisfies the compiler without really casting at execution time.
The JVM allows this because as far as I'm aware, checked exceptions are purely a compiler aspect, and there's no validation for them in the JVM itself. It just knows about throwing exceptions.
Here it says:
Since 2.1 :
[..]
added the invokedynamic instruction
Thus I suppose that it is possible to write instruction code containing invokedynamics with jasmin. However I could not find any documentation on the jasmin syntax and I just figured out how to use invokedynamic to get VerifyErrors with Jasmin, but not how to create a working example.
How is this instruction correctly used in Jasmin?
Each invokedynamic bytecode should refer to a corresponding call site specifier (JVMS 6.5) which is actually a constant pool entry of CONSTANT_InvokeDynamic type (JVMS 4.4.10).
Jasmin (http://jasmin.sourceforge.net) does not support CONSTANT_InvokeDynamic, but Sable/jasmin does. Though using invokedynamic in hand-written assembly is ungrateful job.
Here is an example of dynamic method that returns a reference to System.out:
.class public HelloWorld
.super java/lang/Object
.method public <init>()V
aload_0
invokespecial java/lang/Object/<init>()V
return
.end method
.method public static main([Ljava/lang/String;)V
.limit stack 2
.limit locals 1
invokedynamic "getPrintStream" ()Ljava/io/PrintStream; HelloWorld/bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;()
ldc "Hello, world"
invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V
return
.end method
.method private static bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
.limit stack 6
.limit locals 3
new java/lang/invoke/ConstantCallSite
dup
aload_0
ldc java/lang/System
ldc "out"
ldc java/io/PrintStream
invokevirtual java/lang/invoke/MethodHandles$Lookup/findStaticGetter(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/invoke/MethodHandle;
invokespecial java/lang/invoke/ConstantCallSite/<init>(Ljava/lang/invoke/MethodHandle;)V
areturn
.end method
I assume it's in winhttp.dll somewhere, but I can't find any reference to it by dumping the DLL using bindump. Anyone have any suggestions on how I can find the vtable index of a method?
The information is in the IDL file, httprequest.idl.
interface IWinHttpRequest : IDispatch
{
[id(DISPID_HTTPREQUEST_SETPROXY), helpstring("Specify proxy configuration")]
HRESULT SetProxy([in] HTTPREQUEST_PROXY_SETTING ProxySetting,
[in, optional] VARIANT ProxyServer,
[in, optional] VARIANT BypassList);
[id(DISPID_HTTPREQUEST_SETCREDENTIALS), helpstring("Specify authentication credentials")]
HRESULT SetCredentials([in] BSTR UserName,
[in] BSTR Password,
[in] HTTPREQUEST_SETCREDENTIALS_FLAGS Flags);
....
From this you can read off the method indices. It's a bit tricky because you first have to count the method indices of the base interface IDispatch.
// IUnknown
0: QueryInterface
1: AddRef
2: Release
// IDispatch
3: GetTypeInfoCount
4: GetTypeInfo
5: GetIDsOfNames
6: Invoke
// IWinHttpRequest
7: SetProxy
8: SetCredentials
... etc. ...
You can remove the tedium by using theoffsetof macro.
I managed to isolate my problem in this test case:
.bytecode 50.0
.class public test
.super java/lang/Object
.field public static final foo1 J = 1
.method public <init>()V
.limit stack 1
.limit locals 1
.var 0 is this Ltest; from init_start to init_end
init_start:
aload_0
invokespecial java/lang/Object/<init>()V
init_end:
return
.end method
.method public static main([Ljava/lang/String;)V
.limit stack 1
.limit locals 1
main_start:
new test
invokespecial test/<init>()V
main_end:
return
.end method
When I try to run this, I get this:
$ jasmin test.j
$ java test
Exception in thread "main" java.lang.ClassFormatError: Inconsistent constant value type in class file test
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:634)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:277)
at java.net.URLClassLoader.access$000(URLClassLoader.java:73)
at java.net.URLClassLoader$1.run(URLClassLoader.java:212)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:205)
at java.lang.ClassLoader.loadClass(ClassLoader.java:321)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:294)
at java.lang.ClassLoader.loadClass(ClassLoader.java:266)
Could not find the main class: test. Program will exit.
Some investigation(with javap) reveals this:
public static final long foo1;
Constant value: int 1
In other words, the value of the long constant is being stored in the class file as an integer.
Is there some way to force Jasmin to store the constant in the pool as a long?
I've tried 1L but it doesn't work.
Setting the value of foo1 to be a number greater than INT_MAX (such as 2147483648) does fix the error, but I was hoping for a solution that wouldn't require me to change the constant values.
Does Jasmin provide any way to do this or will this require me to change the source code of jasmin?
I've released a modified version of Jasmin that allows me to do this. It is available on https://github.com/luiscubal/jasmin
To use long constants on this modified version, do this:
.field public static foo J = 1l
same issue with exists with public static final double constants:
.field public static PHASE_1 D = 5.0
also seems to crash with the same Java runtime error.
I worked around it by removing the 'final' flag and moving the initialization to the constructor ;-)