8029106: JVM crashes in Metachunk::Metachunk during parallel class redefinition (PrivateMLetController, anonymous-simple_copy_1)
authorstefank
Mon, 09 Dec 2013 10:03:39 +0100
changeset 22222 45a293a4b895
parent 22221 444e4457cfc7
child 22223 82e95c562133
8029106: JVM crashes in Metachunk::Metachunk during parallel class redefinition (PrivateMLetController, anonymous-simple_copy_1) Summary: Fixed overflow bug in VirtualSpaceNode::is_available Reviewed-by: mgerdin, brutisso, coleenp, jmasa
hotspot/src/share/vm/memory/metaspace.cpp
--- a/hotspot/src/share/vm/memory/metaspace.cpp	Tue Dec 10 10:31:00 2013 +0100
+++ b/hotspot/src/share/vm/memory/metaspace.cpp	Mon Dec 09 10:03:39 2013 +0100
@@ -287,7 +287,7 @@
   VirtualSpace* virtual_space() const { return (VirtualSpace*) &_virtual_space; }
 
   // Returns true if "word_size" is available in the VirtualSpace
-  bool is_available(size_t word_size) { return _top + word_size <= end(); }
+  bool is_available(size_t word_size) { return word_size <= pointer_delta(end(), _top, sizeof(MetaWord)); }
 
   MetaWord* top() const { return _top; }
   void inc_top(size_t word_size) { _top += word_size; }
@@ -3641,10 +3641,82 @@
     }
 
   }
+
+#define assert_is_available_positive(word_size) \
+  assert(vsn.is_available(word_size), \
+    err_msg(#word_size ": " PTR_FORMAT " bytes were not available in " \
+            "VirtualSpaceNode [" PTR_FORMAT ", " PTR_FORMAT ")", \
+            (uintptr_t)(word_size * BytesPerWord), vsn.bottom(), vsn.end()));
+
+#define assert_is_available_negative(word_size) \
+  assert(!vsn.is_available(word_size), \
+    err_msg(#word_size ": " PTR_FORMAT " bytes should not be available in " \
+            "VirtualSpaceNode [" PTR_FORMAT ", " PTR_FORMAT ")", \
+            (uintptr_t)(word_size * BytesPerWord), vsn.bottom(), vsn.end()));
+
+  static void test_is_available_positive() {
+    // Reserve some memory.
+    VirtualSpaceNode vsn(os::vm_allocation_granularity());
+    assert(vsn.initialize(), "Failed to setup VirtualSpaceNode");
+
+    // Commit some memory.
+    size_t commit_word_size = os::vm_allocation_granularity() / BytesPerWord;
+    bool expanded = vsn.expand_by(commit_word_size, commit_word_size);
+    assert(expanded, "Failed to commit");
+
+    // Check that is_available accepts the committed size.
+    assert_is_available_positive(commit_word_size);
+
+    // Check that is_available accepts half the committed size.
+    size_t expand_word_size = commit_word_size / 2;
+    assert_is_available_positive(expand_word_size);
+  }
+
+  static void test_is_available_negative() {
+    // Reserve some memory.
+    VirtualSpaceNode vsn(os::vm_allocation_granularity());
+    assert(vsn.initialize(), "Failed to setup VirtualSpaceNode");
+
+    // Commit some memory.
+    size_t commit_word_size = os::vm_allocation_granularity() / BytesPerWord;
+    bool expanded = vsn.expand_by(commit_word_size, commit_word_size);
+    assert(expanded, "Failed to commit");
+
+    // Check that is_available doesn't accept a too large size.
+    size_t two_times_commit_word_size = commit_word_size * 2;
+    assert_is_available_negative(two_times_commit_word_size);
+  }
+
+  static void test_is_available_overflow() {
+    // Reserve some memory.
+    VirtualSpaceNode vsn(os::vm_allocation_granularity());
+    assert(vsn.initialize(), "Failed to setup VirtualSpaceNode");
+
+    // Commit some memory.
+    size_t commit_word_size = os::vm_allocation_granularity() / BytesPerWord;
+    bool expanded = vsn.expand_by(commit_word_size, commit_word_size);
+    assert(expanded, "Failed to commit");
+
+    // Calculate a size that will overflow the virtual space size.
+    void* virtual_space_max = (void*)(uintptr_t)-1;
+    size_t bottom_to_max = pointer_delta(virtual_space_max, vsn.bottom(), 1);
+    size_t overflow_size = bottom_to_max + BytesPerWord;
+    size_t overflow_word_size = overflow_size / BytesPerWord;
+
+    // Check that is_available can handle the overflow.
+    assert_is_available_negative(overflow_word_size);
+  }
+
+  static void test_is_available() {
+    TestVirtualSpaceNodeTest::test_is_available_positive();
+    TestVirtualSpaceNodeTest::test_is_available_negative();
+    TestVirtualSpaceNodeTest::test_is_available_overflow();
+  }
 };
 
 void TestVirtualSpaceNode_test() {
   TestVirtualSpaceNodeTest::test();
+  TestVirtualSpaceNodeTest::test_is_available();
 }
 
 #endif