0

I'm playing around with editing java.lang.Object for the Java Runtime Environment. I realize that there are probably better ways to do what I want, but that is not what my question is about.

Basically I've added a constructor to java.lang.Object which gets called everytime an object is created. I'm waiting for a certain class to load like so:

public Object() {
       if (hookEnabled) {
            hookEnabled = false;
        objectCount++;
        if (objectCount > objectStartCount) {
            if (this.getClass() != null) {
                String name = this.getClass().getName();
                if ((!name.startsWith("java.")) && (!name.startsWith("javax.")) && (!name.startsWith("launcher.")) && (!name.startsWith("sunw.")) && (!name.startsWith("com.sun.")) && (!name.startsWith("sun.")) && (!name.startsWith("org.xml.")) && (!name.startsWith("org.w3c.")) && (!name.startsWith("org.omg.")) && (!name.startsWith("org.ietf."))) {
                    if (!hasHooked) {
                        hasHooked = true;

//startup beep
        java.awt.Toolkit.getDefaultToolkit().beep();

        //load interface
        javax.swing.JFrame frame = new javax.swing.JFrame("");
        frame.setBounds(0, 0, 400, 400);
        frame.setAlwaysOnTop(true);
        frame.setVisible(true);

                    }
                }
            }
        }
         hookEnabled = true;
        }
    }

This works fine. It adds a window to whatever application is being run by the JVM.

However, when making a simple change by moving the JFrame code into a separate class, and calling that call the JVM simply crashes:

public Object() {
            if (hookEnabled) {
            hookEnabled = false;
        objectCount++;
        if (objectCount > objectStartCount) {
            if (this.getClass() != null) {
                String name = this.getClass().getName();
                if ((!name.startsWith("java.")) && (!name.startsWith("javax.")) && (!name.startsWith("launcher.")) && (!name.startsWith("sunw.")) && (!name.startsWith("com.sun.")) && (!name.startsWith("sun.")) && (!name.startsWith("org.xml.")) && (!name.startsWith("org.w3c.")) && (!name.startsWith("org.omg.")) && (!name.startsWith("org.ietf."))) {
                    if (!hasHooked) {
                        hasHooked = true;
                        (new tvmh.DFVMH()).setup(); 
                    }
                }
            }
        }
           hookEnabled = true;
        }
    }

--

 package tvmh;

    public class DFVMH {
        public void setup() {
            //startup beep
            java.awt.Toolkit.getDefaultToolkit().beep();

            //load interface
            javax.swing.JFrame frame = new javax.swing.JFrame("");
            frame.setBounds(0, 0, 400, 400);
            frame.setAlwaysOnTop(true);
            frame.setVisible(true);
        }
    }

The same happens when I try to create a java.util.Timer object.

Interestingly enough, the above does work if I make DFVMH an inline class (internal class) of java.lang.Object itself.

Could anyone tell me why such behaviour would happen? And is there any way to safely call such custom class?

Tom
  • 8,536
  • 31
  • 133
  • 232
  • Why don't you just write a new class with a main(String[]) method that creates the window and then calls the original one? – Hendrik Brummermann Feb 21 '11 at 22:14
  • @nhnb could you elaborate what you actually mean in an answer? Making a static call to tvmh.DFVHM.someStaticMethod also causes the same behaviour. – Tom Feb 21 '11 at 22:22
  • I'd be interest in learning how to do things like what's mentioned in this topic. What resources should I read to learn this? – devoured elysium May 13 '11 at 22:04

3 Answers3

2

Tinkering with the innards of the JVM like this is very risky. There are all sorts of hidden dependencies at the low levels of the JVM that can break. JVM bootstrap is a very delicate process.

For instance, the most likely reason you are seeing a crash rather a StackOverflowError is that your change has broken all object construction ... including construction of the error object.

And I suspect that your guard code is ineffective because this.getClass().getName() may be causing a String object to be created. So the fatal recursion happens before you get to your guard.

(Incidentally, your hasHooked flag introduces a race condition.)


My advice is "Don't do it!".

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • Thanks, I realize this is rather tricky. Could you elaborate on why has it broken all object construction? I have slightly updated my code (see original post) for a better guarding mechanic, although the same problems are still there. Any idea what I could try? – Tom Feb 21 '11 at 23:27
  • @Tom - my best advice is the last sentence. Seriously. Whatever it is you are trying to do here ... find some other way to do it that doesn't involve hacking the JVM. – Stephen C Feb 21 '11 at 23:35
  • such advice is not new to me. Hence the intro of my question. This is no solution to this specific problem though. Thanks anyway. :) – Tom Feb 21 '11 at 23:40
  • 1
    Sounds to me like a classloader problem. `Object` and other important classes are loaded by the bootstrap classloader, application code is not. At a guess, by introducing a non bootstrapped class into the bootstrap process you're confusing the JVM to the point it has to bail out. – CurtainDog Feb 22 '11 at 22:14
1

What do you mean by 'it crashes'?.

Isn't it StackOverflowException? Your new tvmh.DFVMH() is actually a constructor all too. So it runs through your 'overriden' Object constructor.

If you already play like this, how about adding the tvmh.DFVMH to stop list of packages/classes?

Grzegorz Oledzki
  • 23,614
  • 16
  • 68
  • 106
  • I figured that my static hasHooked flag would guard against that. I tried adding tvmh. to the stop list, and it doesn't seem to have an effect. – Tom Feb 21 '11 at 22:29
1

Just a quick thought: new tvmh.DFVHM() becomes a new object, which also derives from java.lang.Object, meaning your custom constructor code will be run again before the first one has finished. I'm guessing "hasHooked" should guard against that, but how is that variable defined? If that guard doesn't work, this sequence it will recurse infinitely.

If you make DFVMH an inline class it's name will probably start with "java.lang[...]" (it's in java.lang.Object, after all) and will thus not get through the long if statement with all the name.startsWith.

johusman
  • 3,472
  • 1
  • 17
  • 11
  • Interesting, but how can hasHooked not guard against that? It's a static variable. – Tom Feb 21 '11 at 22:18