Consider the following class:
class Foo {
public static final boolean CLINIT_RUN;
static {
System.err.println("Here we are!");
CLINIT_RUN = true;
}
}
As soon as the class would be used, it should have CLINIT_RUN to true such as:
class Test implements Runnable {
// This is the frame that will get PopFrame'd and it should re-execute.
public void loadAndRun() {
System.err.println("Start Load And Run");
System.err.println("CLINIT_RUN " + Foo.CLINIT_RUN);
}
@Override
public void run() {
loadAndRun();
}
}
Now consider a main such as:
public class Main {
public static native void popFrame(Thread t);
public static void main(String[] args) throws Exception {
System.err.println("Starting main, going to start the target thread\n");
Thread t = new Thread(new Test());
t.start();
// Wait a second, enough for the Test thread to suspend itself.
Thread.sleep(1000);
// Uncomment this line and there is a bug.
// popFrame(t);
Thread.sleep(3000);
t.resume();
t.join();
System.err.println("Foo.CLINIT_RUN " + Foo.CLINIT_RUN);
}
}
Expected behavior is:
$ java Main
Starting main, going to start the target thread
Start Load And Run
Here we are!
CLINIT_RUN true
Foo.CLINIT_RUN true
But adding an agent that:
- Suspends the thread during class prepare
- And then pops the frame
- At resume, the class is no longer initialized
$ java -agentpath:/tmp/class_prepare/testagent.so Main
Starting main, going to start the target thread
Start Load And Run
Preparing class LFoo; and suspending 0
Suspended
Popping a thread 0
CLINIT_RUN false
Foo.CLINIT_RUN false
(Notice the false in the print-outs)
When talking with Serguei, I believe this is a duplicate of another issue he was talking about but I have the reproducer so thought it could help.
class Foo {
public static final boolean CLINIT_RUN;
static {
System.err.println("Here we are!");
CLINIT_RUN = true;
}
}
As soon as the class would be used, it should have CLINIT_RUN to true such as:
class Test implements Runnable {
// This is the frame that will get PopFrame'd and it should re-execute.
public void loadAndRun() {
System.err.println("Start Load And Run");
System.err.println("CLINIT_RUN " + Foo.CLINIT_RUN);
}
@Override
public void run() {
loadAndRun();
}
}
Now consider a main such as:
public class Main {
public static native void popFrame(Thread t);
public static void main(String[] args) throws Exception {
System.err.println("Starting main, going to start the target thread\n");
Thread t = new Thread(new Test());
t.start();
// Wait a second, enough for the Test thread to suspend itself.
Thread.sleep(1000);
// Uncomment this line and there is a bug.
// popFrame(t);
Thread.sleep(3000);
t.resume();
t.join();
System.err.println("Foo.CLINIT_RUN " + Foo.CLINIT_RUN);
}
}
Expected behavior is:
$ java Main
Starting main, going to start the target thread
Start Load And Run
Here we are!
CLINIT_RUN true
Foo.CLINIT_RUN true
But adding an agent that:
- Suspends the thread during class prepare
- And then pops the frame
- At resume, the class is no longer initialized
$ java -agentpath:/tmp/class_prepare/testagent.so Main
Starting main, going to start the target thread
Start Load And Run
Preparing class LFoo; and suspending 0
Suspended
Popping a thread 0
CLINIT_RUN false
Foo.CLINIT_RUN false
(Notice the false in the print-outs)
When talking with Serguei, I believe this is a duplicate of another issue he was talking about but I have the reproducer so thought it could help.