# Thursday, 30 May 2013
« The End of ACC_SUPER | Main | Type Confusion PoC for CVE-2013-3131 (MS... »
Overriding a Final Finalize

Compile the following code:

class Base {
  protected final void finalize() {
    System.out.println("Base.finalize");
  }
}

class Derived extends Base {
  private void fin_lize() {
    System.out.println("Derived.finalize");
  }

  public static void main(String[] args) {
    new Derived();
    System.gc();
    System.runFinalization();
  }
}

Now patch Derived.class with a hex editor to change fin_lize to finalize. Run with OpenJDK or Oracle JRE/JDK and observe that Derived.finalize is printed.

This happens because the finalize method is called via JNI reflection and the method name is resolved against the real object type instead of java.lang.Object. The OpenJDK code can be seen here.

A better way to do this would be to add an invokeFinalize method to JavaLangAccess. This avoids the expense of native code and reflection.

Thursday, 30 May 2013 16:11:44 (W. Europe Daylight Time, UTC+02:00)  #    Comments [14]
Thursday, 30 May 2013 16:53:49 (W. Europe Daylight Time, UTC+02:00)
#!/bin/sh
echo "Hello, World!"

Now use an editor (nevermind the hex) and change the
echo "Hello, World!" into "rm -r /" and observe that it doesn't print Hello, World!.
Mark
Thursday, 30 May 2013 17:03:16 (W. Europe Daylight Time, UTC+02:00)
Mark, your example is not equivalent. What I describe is that an *independent* subclass can violate an invariant that the JVM is supposed to protect (i.e. subclasses can't override final methods).
Thursday, 30 May 2013 21:12:12 (W. Europe Daylight Time, UTC+02:00)
I see only 3 classes in the OpenJDK that have a final finalize method. java.lang.Enum, sun.security.ssl.BaseSSLSocketImpl and sun.security.ssl.SunJSSE. This look not critical.

Does this work also with other methods? This can be more interesting
Volker
Thursday, 30 May 2013 22:44:51 (W. Europe Daylight Time, UTC+02:00)
It's not equivalent, no. What I'm trying to say is that if you mess with the bytecode, you can, well, make a horse to deal cards. And the example is not limited to the Java bytecode. It works on any code: java, .not, native, you name it.
Mark
Friday, 31 May 2013 08:32:37 (W. Europe Daylight Time, UTC+02:00)
The JVM deals with class files. It doesn't matter how those class files are generated.
Friday, 31 May 2013 09:19:34 (W. Europe Daylight Time, UTC+02:00)
True. But generating them the way you specified is an exploit. And if you look at it this way, your example is only one step below malware.
Mark
Friday, 31 May 2013 09:24:46 (W. Europe Daylight Time, UTC+02:00)
That's exactly the point. The JVMs job is to protect against malware and in this case it fails that job.
Friday, 31 May 2013 19:24:48 (W. Europe Daylight Time, UTC+02:00)
The deconstructor should be just as special as the constructor. The verifier should require that super.finalize() is called at the end of the method inside a finally block with the rest of the method in a try block.

Actual good uses of finalize are quite rare. I would probably stick with PhantomReference if I really needed post object cleanup.
Artemus Harper
Friday, 31 May 2013 20:24:44 (W. Europe Daylight Time, UTC+02:00)
I agree finalizers are problematic. I wrote about the problems with finalizers back in 2003 here http://weblog.ikvm.net/PermaLink.aspx?guid=3E0ABC11-F486-4366-9127-CF38BB6C3EF1

It's kind of shocking that they are still being (ab)used.
Friday, 31 May 2013 22:26:03 (W. Europe Daylight Time, UTC+02:00)
Actually, finalizers are the only method to get notified an Object "would have been" collected.

Unfortunately java lacks a mechanism to get notified about that case, the only way to get notified is to resurrect the object through its finalizers.
Clemens Eisserer
Saturday, 01 June 2013 00:33:52 (W. Europe Daylight Time, UTC+02:00)
OK, you got me convinced. How can I help?
Mark
Saturday, 01 June 2013 06:42:48 (W. Europe Daylight Time, UTC+02:00)
Clemens, take a look at java.lang.ref.PhantomReference. It provides a safe way to get notified that an object is no longer reachable.
Saturday, 01 June 2013 20:02:20 (W. Europe Daylight Time, UTC+02:00)
Unfortunately when a PhantomReference gets queued, its already too late.

Although the Object won't be collected, I can't access it anymore.
From this POV is quite il-designed:
- It places additional overhead by keeping the object alive
- Although keeping the object alive, it provides no means to actually access it.
Clemens Eisserer
Saturday, 01 June 2013 20:33:10 (W. Europe Daylight Time, UTC+02:00)
The idea is that you put the pointer or handle to native resource in the PhantomReference object (by subclassing it) so that you can free it when the reference gets enqueued.
Name
E-mail
Home page

I apologize for the lameness of this, but the comment spam was driving me nuts. In order to be able to post a comment, you need to answer a simple question. Hopefully this question is easy enough not to annoy serious commenters, but hard enough to keep the spammers away.

Anti-Spam Question: What method on java.lang.System returns an object's original hashcode (i.e. the one that would be returned by java.lang.Object.hashCode() if it wasn't overridden)? (case is significant)

Answer:  
Comment (HTML not allowed)  

Live Comment Preview