public class ObjectsWithTagsResurrectionBug { public static void main(String[] args) throws Exception { String randomString = "" + args.length; String objectToTag = "A string " + randomString; // Tag the object. This will place a weak reference to the object in the JVMTI tagmap. tagObject(objectToTag); // Build a long object chain to make the concurrent marking phase take a long time to complete. buildHolderChain(); // Allocate a lot so that the object to tag has been promoted to old gen. allocateALot(); Thread.sleep(100); // Drop the last strong reference to the objectToTag. // Now there exists only a weak reference in the JVMTI tagmap. objectToTag = null; Thread.sleep(1000); // Start a concurrent cycle. This requires -XX:+ExplicitGCInvokesConcurrent. callSystemGCInAnotherThread(); Thread.sleep(250); System.err.println("Going to fetch tagged object"); // Fetch the tagged object. This will "resurrect" it from weakly reachable (going to die) to strongly reacable. // G1 lacks a SATB barrier in this code path, so this will install an object that is going to die into holder[0]. // Note that a holder object is used instead of a static field. Object in static fields are found by the root scan // and would be marked alive. By using an indirection through holder, we prevent the marking code from finding the tagged object. holder = new Object[1]; holder[0] = getTaggedObject(); if (holder[0] == null) { System.err.println("Too late"); System.exit(-1); } System.err.println("Fetched tagged object"); // Wait long enough to allow marking to complete, and then touch the object. // -XX:+VerifyDuringGC catches this bug before we even run the code below. Thread.sleep(2000); System.err.println("Going to touch object"); System.err.println(holder[0]); } public static void callSystemGCInAnotherThread() { new Thread() { public void run() { System.gc(); } }.start(); } public static Object dummy; public static void allocateALot() { for (int i = 0; i < 1024 * 20; i++) { dummy = new byte[1024]; } } public static Object[] holder; public static Object[] chain; public static void buildHolderChain() { for (int i = 0; i < 3000000; i++) { chain = new Object[] { chain }; } } public static long tag = 0x0123456789abcdefL; public static void tagObject(Object obj) { setTag0(obj, tag); } public static Object getTaggedObject() { Object[] array = getObjectsWithTags(1, new long [] { tag }); if (array.length != 1) { throw new RuntimeException("Unexpected number of objects in array: " + array.length + " != 1"); } return array[0]; } private static native int setTag0(Object o, long tag); private static native Object[] getObjectsWithTags(int count, long array[]); }