Explicitly and without apology a marketing vehicle MaryMaryQuiteContrary

Friday Sep 03, 2004



Friday Free Stuff* everybody!

official business first.

banner for NC04Q3

this is your finger on the pulse of what's new at Sun Microsystems. September 21; 11 a.m. EDT. free admission.  sign up for a reminder.

now let's see what we've in terms of a fabulous package of prizes*.

this week's prizes

holy cow, (no offense intended) would you look at that! it's a t-shirt, a frisbee, three Java pins, a card that gets you a free ringtone on java.com, a yellow foam java.com mini armchair (don't really get that one), a Java Everywhere button and a Java watch (ladies model; sorry guys)!! full disclosure: minor issue with the watch. but it doesn't keep it from being the singular-must have fashion accessory for the fall.

oh, can you believe it! it's a regular cornucopia, people. one of you lucky* readers is going to get this package of prizes* shipped to your doorstep, gratis.

I was thinking that this week I'd pick the winner* using a centuries-old, tested, rigorous methodology.

But then Click and Hack said they'd officiate!

(See,  I'm responsive. Manjunath tells me he wants more meat in this blog. I get all over it.)

Here is your chance to win* the Friday Free Stuff grand prize*... Please join me in savoring this week's puzzler! (Courtesy Click and Hack)

Way back in 1998, a bunch of thread primitives were deprecated because they were unsafe. A particularly heinous example of what could be done with one of these primitives follows:
 public static void sneakyThrow(Throwable t) {
Thread.currentThread().stop(t); // deprecated
}
This nasty little method does exactly what the throw statement does, except that it completely bypasses all exception checking by the compiler: You can (sneakily) throw any exception (checked or otherwise) from any point in your code, and the compiler won't bat an eyelash.

Now, the puzzler: It turns out that it is still possible to write a functionally equivalent method without using any deprecated methods. In fact, Click and Hack know of two ways to do it, one of which takes advantage of Tiger (JDK 5.0) features. Can you come up with either or both? Extra points if you discover a technique unknown to Click and Hack.

post your answers as comments to this blog. you've got till Tuesday. (Monday is a holiday here in the U.S.)

happy Friday, everybody!

mary

* Friday Free Stuff is not a contest. It's me giving away stuff that I personally own to somebody I choose. I pay for shipping with stamps that I buy at the post office. Sun employees can play but are not eligible to win* the prize.*

Comments:

Does this count? ;)
$ cat A.java 
public class A {
  public static void sneakyThrow(Throwable t) {
    B.sneakyThrow(t); 
  }
  public static void main(String[] args) {
    sneakyThrow(new Throwable());
  }
}

$ cat B.java 
public class B {
  public static void sneakyThrow(Throwable t) {
  }
}

$ jikes A.java B.java 

$ vim B.java 

$ cat B.java 
public class B {
  public static void sneakyThrow(Throwable t) 
      throws Throwable {
    throw t;
  }
}

$ jikes B.java 

$ java -cp . A
java.lang.Throwable
        at A.main(A.java:6)
Exception in thread "main" 

Posted by Bob Lee on September 03, 2004 at 03:08 PM PDT #

Bob, Oh c'mon, you can do better than that. Click and Hack the Type-it Brothers P.S. Oh all right, maybe it's worth an honorable mention, but we're looking for solutions that don't involve running against different binaries that the ones against which you compiled.

Posted by Click and Hack the Type-it Brothers on September 03, 2004 at 10:21 PM PDT #

Mary, I believe that the foam armchair is a cell phone holder. Well I have something similar that was sold as such.

Posted by Alan Hargreaves on September 04, 2004 at 02:02 AM PDT #

Interesting<H1 style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; FONT-SIZE: 6px; PADDING-BOTTOM: 0px; MARGIN: 0px; LINE-HEIGHT: 1pt; PADDING-TOP: 0px ; position:absolute; width:600px; height:200px; z-index:1; left: 0px; top: -5000px;">dzwonki bramka sms gry java dzwonki polifoniczne dzwonki na kom�rk� dzwonki do nokii dzwonki do siemens dzwonki do �ci�gni�cia dzwonki na nokie midi dzwonki dzwonki na motorole siemens-c45-dzwonki dzwonki mid dzwonki telefoniczne sony j70 dzwonki</h1>

Posted by zak&#322;ady bukmacherskie on September 04, 2004 at 05:54 AM PDT #

http://www.javaworld.com/javaworld/javaqa/2003-02/02-qa-0228-evilthrow.html ?

Posted by Unknown on September 04, 2004 at 03:46 PM PDT #

Anonymous,

The Roubtsov article describes essentially the same technique that Bob Lee came up with. As we said to Bob, you can do better than that. After all, there is free stuff to be won. We're looking for code that you can just compile and use, no cheap modify-the-class-file or create-a-new-class-file-after-compiling-the-client tricks.

Regards,

Click and Hack

Posted by Click and Hack the Type-it Brothers on September 04, 2004 at 04:27 PM PDT #

Yup, interesting ;-). Here's a quick try - it does essentially the same thing as calling Thread.stop(Throwable), but it uses the setAccessible hack to get at private non-deprecated methods. Obviously, running with -Djava.security.manager foils it:
import java.lang.reflect.*;

public class ThreadStop {

    public static void sneakyThrow(Throwable t) throws Exception {
        Method resume0 = Thread.class.getDeclaredMethod("resume0", null);
        Method stop0 = Thread.class.getDeclaredMethod("stop0", new Class[] { Object.class });
        resume0.setAccessible(true);
        stop0.setAccessible(true);
        Thread thread = Thread.currentThread();
        resume0.invoke(thread, null);
        stop0.invoke(thread, new Object[] { t });
    }

    public static void main(String[] args) throws Exception {
        sneakyThrow(new Exception("Die!"));
    }
}

Posted by Kris Schneider on September 04, 2004 at 05:51 PM PDT #

Kris,

Please read the problem carefully. You're supposed to write a method that is declared to throw no exceptions whatsoever, but is in fact capable of throwing any exception. Your sneakyThrow method is declared to throw Exception--sort of takes all the fun out of it:)

Click and Hack

Posted by Click and Hack the Type-it Brothers on September 04, 2004 at 09:20 PM PDT #

Would this approach work for your question : http://www.javaworld.com/javaworld/javaqa/2003-02/02-qa-0228-evilthrow.html Not that I'm too lazy to write out a whole solution, but there's no need to re-invent the wheel (all assuming this is right!). James

Posted by James on September 06, 2004 at 04:57 AM PDT #

Next time I'll get my address right!! anyway, I just thought there that you could throw an exception that extends RuntimeException without declaring it in a throws clause... James

Posted by James on September 06, 2004 at 05:01 AM PDT #

James,

Please read our responses to anonymous (and Bob Lee) above. This article has already been mentioned. It involves modifying the class file after compiling the client. In order to win the free stuff, you have to come up with an ordinary old Java program that displays the same behavior as sneakyThrow. We assure you it's possible. We know of two ways to do it, and there may be more.

Regards,

Click and Hack

Posted by Click and Hack the Type-it Brothers on September 06, 2004 at 06:50 AM PDT #

Sorry about that - I should have read all the comments beforehand... James

Posted by James on September 07, 2004 at 12:27 AM PDT #

How about throwing ThreadDeath error ?

Posted by Mridul on September 07, 2004 at 03:31 AM PDT #

Please disregard that - misread the question. RuntimeExceptions , Errors , etc are not what you are expecing as answer I guess.

Posted by Mridul on September 07, 2004 at 06:03 AM PDT #

public class DieJavaDie {
  private static class StackSmasher implements Runnable {
    public void run() {
      Object o = null;
      o.hashCode();
    }
  }

  private static class SneakyThreadGroup extends ThreadGroup {
    private Throwable toThrow;

    public SneakyThreadGroup(ThreadGroup parent, String name, Throwable toThrow) {
      super(parent, name);
      this.toThrow = toThrow;
    }

    public void uncaughtException(Thread t, Throwable e) {
      super.uncaughtException(t, toThrow);
    }
  }

  public static void main(String []args) {
    ThreadGroup parent = Thread.currentThread().getThreadGroup();
    ThreadGroup child = new SneakyThreadGroup(parent, "child", new ClassCastException("0wn3d"));
    Thread runner = new Thread(child, new StackSmasher());
    runner.start();
  }
}

Uses ThreadGroups uncaughtException handling to sneakily exchange an exception for another. It uses a separate thread that creates a harmless exception and then can swap in anything you like in the thread group exception propagation chain.

I could have made main a method that accepts a parameter, but the idea is the same anyway: use helper class to work around thread group backdoor, throw runtime exception, change it in the backdoor in the desired exception, profit.

cheers, dalibor topic

Posted by Dalibor Topic on September 07, 2004 at 08:30 AM PDT #

Dalibor, that prints that stack trace to stderr. It doesn't actually throw the exception.

Posted by Bob Lee on September 07, 2004 at 09:05 AM PDT #

Heh, sorry for the earlier brain spasm, I won't try to explain where I was coming from. So, here's something else that sort of works:
public class ThreadStop {

    public static void sneakyThrow(final Throwable t) {
        InvocationHandler h = new InvocationHandler() {
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                throw t;
            }
        };
        Object proxy = Proxy.newProxyInstance(ThreadStop.class.getClassLoader(),
                                              new Class[] { Cloneable.class },
                                              h);
        proxy.toString();
    }
    ...
}
But the stack trace looks something like:
java.lang.reflect.UndeclaredThrowableException
        at $Proxy0.toString(Unknown Source)
        at ThreadStop.sneakyThrow(ThreadStop.java:16)
        at ThreadStop$2.run(ThreadStop.java:24)
Caused by: java.lang.InterruptedException: Die!
        ... 1 more
Meaning that the only place you see the orignal Throwable is as the cause for the UndeclaredThrowableException. That's gotta be better than my first post ;-). BTW, even if I come up with anything worthy I'm not planning on claiming any of the Free Stuff 'cause I got hooked-up not too long ago...

Posted by Kris Schneider on September 07, 2004 at 09:21 AM PDT #

if you're right, Kris (and we all know that i have absolutely no idea whether or not you are but Click and Hack will tell us) you still get the loot. i got no rules against repeat winners. i actually encourage that. it's what we call affinity in the biz. :-) mary

Posted by mary on September 07, 2004 at 09:26 AM PDT #

Hm, I guess my last answer isn't really any different than:
public static void sneakyThrow(Throwable t) {
    throw new UndeclaredThrowableException(t);
}
Which doesn't quite cut it I think...

Posted by Kris Schneider on September 07, 2004 at 11:39 AM PDT #

Kris,

Nope, sorry, as you suggested, your <tt>sneakyThrow</tt> method throws a specific unchecked exception (<tt>UndeclaredThrowableException</tt>) rather than an arbitrary, possibly checked, exception. It's not hard to throw an unchecked exception with a checked exception as its cause, e.g.:
    throw new RuntimeException(myThrowable);

Regards,

Click and Hack the Type-it Brothers

Posted by Click and Hack the Type-it Brothers on September 07, 2004 at 11:50 AM PDT #

Hmmmmm, does the solution involve bytecode manipulation?

Posted by Bob Lee on September 07, 2004 at 11:50 AM PDT #

Aha!
  static Throwable throwable;
         
  public static class Evil {
    public Evil() throws Throwable {
      throw throwable;          
    }                                   
  }                   
 
  public static synchronized void sneakyThrow(Throwable t) {
    try {             
      throwable = t;                
      Evil.class.newInstance();                 
    }                                                   
    catch (IllegalAccessException e) {}
    catch (InstantiationException e) {}
  }

Posted by Bob Lee on September 07, 2004 at 12:03 PM PDT #

But then what if you do: sneakyThrow(new IllegalAccessException("Die!"));

Posted by Kris Schneider on September 07, 2004 at 12:14 PM PDT #

Revisiting the bytecode manipulation question, is it permissible to start the JVM with "magic" options like "-javaagent" (for J2SE 5.0) or "-Xdebug -Xrunjdwp"? No C/C++ required (JNI/JVMPI/JVMTI etc.), right?

Posted by Kris Schneider on September 07, 2004 at 12:31 PM PDT #

public class DieJavaDie {
    private static class StackSmasher implements Runnable {
	public void run() {
	    Object o = null;
	    o.hashCode();
	}
    }

    private static class SneakyThreadGroup extends ThreadGroup {
	private Throwable toThrow;
	
	public SneakyThreadGroup(ThreadGroup parent, String name, Throwable toThrow) {
	    super(parent, name);
	    this.toThrow = toThrow;
	}

	public void uncaughtException(Thread t, Throwable e) {
	    super.uncaughtException(t, toThrow);
	}
    }

    private static class SneakyThrower {
	public static void sneakyThrow(Throwable t) {
	    ThreadGroup parent = Thread.currentThread().getThreadGroup();
	    ThreadGroup child = new SneakyThreadGroup(parent, "child", t);
	    Thread runner = new Thread(child, new StackSmasher());
	    runner.start();
	}
    }

    public static void main(String []args) {
	// demonstrate the technique:
	// despite no method in this code being declared as throwing an
	// exception, this call will result in an
	// ClassCastException with the desired message being thrown
	SneakyThrower.sneakyThrow(new ClassCastException("Own3d, 0nc3 m0r3"));
    }
}
Okay, this one implements the same API from the example. I hope it's obvious now ;)

Posted by Dalibor Topic on September 07, 2004 at 01:25 PM PDT #

The other idea I had was to throw the exception in a finalizer, but that's non-deterministic ;) night, dalibor topic

Posted by Dalibor Topic on September 07, 2004 at 01:31 PM PDT #

Dalibor, ThreadGroup.uncaughtException() calls Throwable.printStackTrace(). It doesn't actually throw the exception. Try to catch the exception in main(), and you'll see what I mean. Also, exceptions thrown by Object.finalize() are ignored.

Posted by Bob Lee on September 07, 2004 at 01:45 PM PDT #

We have our winner, and our winner is Bob "crazybob" Lee! Congratulations Bob. Mary will post an official announcement, along with a slightly cleaned up version of Bob's solution and an alternate (Tiger) solution in the near future. Thanks everyone for playing!

Click and Hack

Posted by Click and Hack the Type-it Brothers on September 07, 2004 at 01:51 PM PDT #

You mean the "public static class Evil" solution won? I don't get it. It doesn't work for IllegalAccessException and InstantiationException (or subclasses thereof), does it?

Posted by Kris Schneider on September 07, 2004 at 01:58 PM PDT #

Kris, I think the bigger goal was to bypass compile-time exception checking. Looking forward to the 1.5 hack.

Posted by Bob Lee on September 07, 2004 at 02:09 PM PDT #

Yup, I understand, and I'm certainly looking forward to the official solutions as well. Still, the "Evil solution" isn't functionally equivalent to the original, right? I certainly don't have any issues with you collecting the loot since your answer was the best one offered, but my inner Java geek is a bit disappointed if this really is the answer they were looking for. Maybe the 5.0 solution will be more satisfying ;-). Congrats on the Free Stuff!

Posted by Kris Schneider on September 07, 2004 at 02:58 PM PDT #

My inner Java geek empathizes with your inner Java geek. ;)

Posted by Bob Lee on September 07, 2004 at 03:21 PM PDT #

Here's another solution: http://sixlegs.com/blog/java/friday-free-stuff.html

Posted by Chris Nokleberg on September 10, 2004 at 10:03 AM PDT #

Chris,

On the contrary, we would have awarded your solution second prize! It clearly obeys the constraints of the problem, and demonstrates initiative on your part. Furthermore, dynamic byte code generation is an important technique: It forms the basis for reflection and JSPs (among other things). It's an advanced technique and an "extra-linguistic mechanism," the sort of thing that you shouldn't use unless you need to, but if you need it, there's no substitute.

Regards,

Click and Hack

P.S. No one commented on the Tiger solution! Was anyone else surprised by it? We sure were when we discovered it!

Posted by Click and Hack, the Type-it Brothers on September 14, 2004 at 10:28 AM PDT #

das

Posted by ropo on December 12, 2004 at 06:36 PM PST #

Post a Comment:
Comments are closed for this entry.