-
Couldn't load subscription status.
- Fork 78
Description
After retaining and scanning SoftReference, it generates ProcessEdgesWork work packets to trace the children of retained SoftReference instances. During this time, more SoftReference instances will be discovered, but they will not be traced. That will cause those transitively discovered SoftReference to contain un-updated reference to the children in the from-space, or crash MarkCompact due to those object not having forwarding pointers.
This bug was originally discovered when running CI tests for the PR removing ObjectReference::NULL when running fop in DaCapo 2006 using MarkCompact. See: https://github.com/mmtk/mmtk-openjdk/actions/runs/8750247972/job/24016142656?pr=265
The program
import java.lang.ref.*;
class StrongNode {
public WeakNode next;
public StrongNode(WeakNode next) {
this.next = next;
}
}
class WeakNode extends SoftReference<StrongNode> {
public WeakNode(StrongNode next) {
super(next);
}
}
public class TwoLevelDeadWeak {
public static WeakNode mkWeak(Object object) {
StrongNode strong1 = new StrongNode(null);
WeakNode weak1 = new WeakNode(strong1);
StrongNode strong2 = new StrongNode(weak1);
WeakNode weak2 = new WeakNode(strong2);
return weak2;
}
public static void main(String[] args) {
Object obj = new Object();
System.out.println("Making objects");
WeakNode rooted = mkWeak(obj);
System.out.println("Triggering GC...");
System.gc();
System.out.format("Rooted: %s%n", rooted);
StrongNode myStrong = rooted.get().next.get();
System.out.format("myStrong: %s%n", myStrong);
System.out.println("Done.");
}
}How to crash SemiSpace?
Run it with MMTK_NO_REFERENCE_TYPE=true, preferrably with stack trace and logs enabled.
export RUST_LOG=info,mmtk::util::reference_processor=trace
export RUST_BACKTRACE=1
MMTK_THREADS=1 MMTK_NO_REFERENCE_TYPES=false MMTK_PLAN=SemiSpace /path/to/openjdk/build/linux-x86_64-normal-server-slowdebug/jdk/bin/java -XX:+UseThirdPartyHeap -cp /path/to/the/program TwoLevelDeadWeak
It will print:
...
[2024-04-19T12:08:53Z TRACE mmtk::util::reference_processor] Process reference: 0x400aef68
[2024-04-19T12:08:53Z TRACE mmtk::util::reference_processor] ~> 0x400e0410
[2024-04-19T12:08:53Z TRACE mmtk::util::reference_processor] => 0x40473250
[2024-04-19T12:08:53Z TRACE mmtk::util::reference_processor] ~> 0x404853d0
[2024-04-19T12:08:53Z DEBUG mmtk::util::reference_processor] SOFT reference table from 151 to 100 (0 enqueued)
[2024-04-19T12:08:53Z DEBUG mmtk::util::reference_processor] Ending ReferenceProcessor.scan(SOFT)
[2024-04-19T12:08:53Z TRACE mmtk::util::reference_processor] Add soft candidate: 0x404e8480
[2024-04-19T12:08:53Z DEBUG mmtk::util::reference_processor] Starting ReferenceProcessor.scan(WEAK)
[2024-04-19T12:08:53Z TRACE mmtk::util::reference_processor] WEAK Reference table is {0x40477d30, 0x400b14f8, ...
...
[2024-04-19T12:08:53Z TRACE mmtk::util::reference_processor] Process reference: 0x4046f870
[2024-04-19T12:08:53Z TRACE mmtk::util::reference_processor] ~> 0x0
[2024-04-19T12:08:53Z TRACE mmtk::util::reference_processor] (cleared referent)
[2024-04-19T12:08:53Z DEBUG mmtk::util::reference_processor] PHANTOM reference table from 42 to 3 (10 enqueued)
[2024-04-19T12:08:53Z DEBUG mmtk::util::reference_processor] Ending ReferenceProcessor.scan(PHANTOM)
thread '<unnamed>' panicked at /home/wks/projects/mmtk-github/mmtk-core/src/util/reference_processor.rs:252:21:
Referent 0x401ebf18 (of reference 0x404e8480) is not in any space
stack backtrace:
0: rust_begin_unwind
at /rustc/aedd173a2c086e558c2b66d3743b344f977621a7/library/std/src/panicking.rs:647:5
1: core::panicking::panic_fmt
at /rustc/aedd173a2c086e558c2b66d3743b344f977621a7/library/core/src/panicking.rs:72:14
2: mmtk::util::reference_processor::ReferenceProcessor::enqueue::{{closure}}
at /home/wks/projects/mmtk-github/mmtk-core/src/util/reference_processor.rs:252:21
3: core::iter::traits::iterator::Iterator::for_each::call::{{closure}}
at /rustc/aedd173a2c086e558c2b66d3743b344f977621a7/library/core/src/iter/traits/iterator.rs:855:29
4: <hashbrown::map::Keys<K,V> as core::iter::traits::iterator::Iterator>::fold::{{closure}}
at /rust/deps/hashbrown-0.14.3/src/map.rs:4865:45
5: <hashbrown::map::Iter<K,V> as core::iter::traits::iterator::Iterator>::fold::{{closure}}
at /rust/deps/hashbrown-0.14.3/src/map.rs:4749:13
6: hashbrown::raw::RawIterRange<T>::fold_impl
at /rust/deps/hashbrown-0.14.3/src/raw/mod.rs:3885:23
7: <hashbrown::raw::RawIter<T> as core::iter::traits::iterator::Iterator>::fold
at /rust/deps/hashbrown-0.14.3/src/raw/mod.rs:4156:18
8: <hashbrown::map::Iter<K,V> as core::iter::traits::iterator::Iterator>::fold
at /rust/deps/hashbrown-0.14.3/src/map.rs:4747:20
9: <hashbrown::map::Keys<K,V> as core::iter::traits::iterator::Iterator>::fold
at /rust/deps/hashbrown-0.14.3/src/map.rs:4865:9
10: <hashbrown::set::Iter<K> as core::iter::traits::iterator::Iterator>::fold
at /rust/deps/hashbrown-0.14.3/src/set.rs:1705:9
11: <std::collections::hash::set::Iter<K> as core::iter::traits::iterator::Iterator>::fold
at /rustc/aedd173a2c086e558c2b66d3743b344f977621a7/library/std/src/collections/hash/set.rs:1513:19
12: core::iter::traits::iterator::Iterator::for_each
at /rustc/aedd173a2c086e558c2b66d3743b344f977621a7/library/core/src/iter/traits/iterator.rs:858:9
13: mmtk::util::reference_processor::ReferenceProcessor::enqueue
at /home/wks/projects/mmtk-github/mmtk-core/src/util/reference_processor.rs:247:13
14: mmtk::util::reference_processor::ReferenceProcessors::enqueue_refs
at /home/wks/projects/mmtk-github/mmtk-core/src/util/reference_processor.rs:60:9
15: <mmtk::util::reference_processor::RefEnqueue<VM> as mmtk::scheduler::work::GCWork<VM>>::do_work
at /home/wks/projects/mmtk-github/mmtk-core/src/util/reference_processor.rs:559:9
16: mmtk::scheduler::work::GCWork::do_work_with_stat
at /home/wks/projects/mmtk-github/mmtk-core/src/scheduler/work.rs:45:9
17: mmtk::scheduler::worker::GCWorker<VM>::run
at /home/wks/projects/mmtk-github/mmtk-core/src/scheduler/worker.rs:244:13
18: mmtk::memory_manager::start_worker
at /home/wks/projects/mmtk-github/mmtk-core/src/memory_manager.rs:470:5
19: start_worker
at /home/wks/projects/mmtk-github/mmtk-openjdk/mmtk/src/api.rs:214:9
20: _ZN19MMTkCollectorThread3runEv
at /home/wks/projects/mmtk-github/openjdk/../mmtk-openjdk/openjdk/mmtkCollectorThread.cpp:36:15
21: _ZN6Thread8call_runEv
at /home/wks/projects/mmtk-github/openjdk/src/hotspot/share/runtime/thread.cpp:402:12
22: thread_native_entry
at /home/wks/projects/mmtk-github/openjdk/src/hotspot/os/linux/os_linux.cpp:826:19
23: <unknown>
24: <unknown>
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
fatal runtime error: failed to initiate panic, error 5
fish: Job 1, 'MMTK_THREADS=1 MMTK_NO_REFERENC…' terminated by signal SIGABRT (Abort)
How to crash MarkCompact
We first patch mmtk-core so that MarkCompactSpace::trace_forward_object asserts the object has forwarding pointer. If an object is reachable during the SecondRoot stage or the RefForwarding stage, it must be live, and its forwarding pointer must have been computed during the CalculateForwarding stage.
diff --git a/src/policy/markcompactspace.rs b/src/policy/markcompactspace.rs
index e6d332919..533d7fa8c 100644
--- a/src/policy/markcompactspace.rs
+++ b/src/policy/markcompactspace.rs
@@ -251,7 +251,9 @@ impl<VM: VMBinding> MarkCompactSpace<VM> {
queue.enqueue(object);
}
- Self::get_header_forwarding_pointer(object)
+ let result = Self::get_header_forwarding_pointer(object);
+ assert!(!result.is_null(), "Object {object} does not have a forwarding pointer");
+ result
}
pub fn test_and_mark(object: ObjectReference) -> bool {Then run the same program with the same env vars except using MarkCompact. It will crash with the following log:
...
[2024-04-19T12:15:46Z DEBUG mmtk::util::reference_processor] SOFT reference table from 101 to 100 (0 enqueued)
[2024-04-19T12:15:46Z DEBUG mmtk::util::reference_processor] Ending ReferenceProcessor.scan(SOFT)
[2024-04-19T12:15:46Z TRACE mmtk::util::reference_processor] Add soft candidate: 0x4066bf28
[2024-04-19T12:15:46Z DEBUG mmtk::util::reference_processor] Starting ReferenceProcessor.scan(WEAK)
...
[2024-04-19T12:15:46Z TRACE mmtk::util::reference_processor] Forwarding reference: 0x4066bf28 (size: 40)
thread '<unnamed>' panicked at /home/wks/projects/mmtk-github/mmtk-core/src/policy/markcompactspace.rs:255:9:
Object 0x4066bf10 does not have a forwarding pointer
stack backtrace:
0: rust_begin_unwind
at /rustc/aedd173a2c086e558c2b66d3743b344f977621a7/library/std/src/panicking.rs:647:5
1: core::panicking::panic_fmt
at /rustc/aedd173a2c086e558c2b66d3743b344f977621a7/library/core/src/panicking.rs:72:14
2: mmtk::policy::markcompactspace::MarkCompactSpace<VM>::trace_forward_object
at /home/wks/projects/mmtk-github/mmtk-core/src/policy/markcompactspace.rs:255:9
3: <mmtk::policy::markcompactspace::MarkCompactSpace<VM> as mmtk::policy::gc_work::PolicyTraceObject<VM>>::trace_object
at /home/wks/projects/mmtk-github/mmtk-core/src/policy/markcompactspace.rs:141:13
4: <mmtk::plan::markcompact::global::MarkCompact<VM> as mmtk::plan::global::PlanTraceObject<VM>>::trace_object
at /home/wks/projects/mmtk-github/mmtk-core/src/plan/markcompact/global.rs:30:21
5: <mmtk::scheduler::gc_work::PlanProcessEdges<VM,P,_> as mmtk::scheduler::gc_work::ProcessEdgesWork>::trace_object
at /home/wks/projects/mmtk-github/mmtk-core/src/scheduler/gc_work.rs:931:9
6: mmtk::util::reference_processor::ReferenceProcessor::get_forwarded_referent
at /home/wks/projects/mmtk-github/mmtk-core/src/util/reference_processor.rs:220:9
7: mmtk::util::reference_processor::ReferenceProcessor::forward::forward_reference
at /home/wks/projects/mmtk-github/mmtk-core/src/util/reference_processor.rs:301:36
8: mmtk::util::reference_processor::ReferenceProcessor::forward::{{closure}}
at /home/wks/projects/mmtk-github/mmtk-core/src/util/reference_processor.rs:325:25
9: core::iter::adapters::map::map_fold::{{closure}}
at /rustc/aedd173a2c086e558c2b66d3743b344f977621a7/library/core/src/iter/adapters/map.rs:89:28
10: <hashbrown::map::Keys<K,V> as core::iter::traits::iterator::Iterator>::fold::{{closure}}
at /rust/deps/hashbrown-0.14.3/src/map.rs:4865:45
11: <hashbrown::map::Iter<K,V> as core::iter::traits::iterator::Iterator>::fold::{{closure}}
at /rust/deps/hashbrown-0.14.3/src/map.rs:4749:13
12: hashbrown::raw::RawIterRange<T>::fold_impl
at /rust/deps/hashbrown-0.14.3/src/raw/mod.rs:3885:23
13: <hashbrown::raw::RawIter<T> as core::iter::traits::iterator::Iterator>::fold
at /rust/deps/hashbrown-0.14.3/src/raw/mod.rs:4156:18
14: <hashbrown::map::Iter<K,V> as core::iter::traits::iterator::Iterator>::fold
at /rust/deps/hashbrown-0.14.3/src/map.rs:4747:20
15: <hashbrown::map::Keys<K,V> as core::iter::traits::iterator::Iterator>::fold
at /rust/deps/hashbrown-0.14.3/src/map.rs:4865:9
16: <hashbrown::set::Iter<K> as core::iter::traits::iterator::Iterator>::fold
at /rust/deps/hashbrown-0.14.3/src/set.rs:1705:9
17: <std::collections::hash::set::Iter<K> as core::iter::traits::iterator::Iterator>::fold
at /rustc/aedd173a2c086e558c2b66d3743b344f977621a7/library/std/src/collections/hash/set.rs:1513:19
18: <core::iter::adapters::map::Map<I,F> as core::iter::traits::iterator::Iterator>::fold
at /rustc/aedd173a2c086e558c2b66d3743b344f977621a7/library/core/src/iter/adapters/map.rs:129:9
19: <core::iter::adapters::map::Map<I,F> as core::iter::traits::iterator::Iterator>::fold
at /rustc/aedd173a2c086e558c2b66d3743b344f977621a7/library/core/src/iter/adapters/map.rs:129:9
20: core::iter::traits::iterator::Iterator::for_each
at /rustc/aedd173a2c086e558c2b66d3743b344f977621a7/library/core/src/iter/traits/iterator.rs:858:9
21: <hashbrown::map::HashMap<K,V,S,A> as core::iter::traits::collect::Extend<(K,V)>>::extend
at /rust/deps/hashbrown-0.14.3/src/map.rs:6511:9
22: <hashbrown::set::HashSet<T,S,A> as core::iter::traits::collect::Extend<T>>::extend
at /rust/deps/hashbrown-0.14.3/src/set.rs:1355:9
23: <std::collections::hash::set::HashSet<T,S> as core::iter::traits::collect::Extend<T>>::extend
at /rustc/aedd173a2c086e558c2b66d3743b344f977621a7/library/std/src/collections/hash/set.rs:1070:9
24: <std::collections::hash::set::HashSet<T,S> as core::iter::traits::collect::FromIterator<T>>::from_iter
at /rustc/aedd173a2c086e558c2b66d3743b344f977621a7/library/std/src/collections/hash/set.rs:1026:13
25: core::iter::traits::iterator::Iterator::collect
at /rustc/aedd173a2c086e558c2b66d3743b344f977621a7/library/core/src/iter/traits/iterator.rs:2054:9
26: mmtk::util::reference_processor::ReferenceProcessor::forward
at /home/wks/projects/mmtk-github/mmtk-core/src/util/reference_processor.rs:322:27
27: mmtk::util::reference_processor::ReferenceProcessors::forward_refs
at /home/wks/projects/mmtk-github/mmtk-core/src/util/reference_processor.rs:74:9
28: <mmtk::util::reference_processor::RefForwarding<E> as mmtk::scheduler::work::GCWork<<E as mmtk::scheduler::gc_work::ProcessEdgesWork>::VM>>::do_work
at /home/wks/projects/mmtk-github/mmtk-core/src/util/reference_processor.rs:545:9
29: mmtk::scheduler::work::GCWork::do_work_with_stat
at /home/wks/projects/mmtk-github/mmtk-core/src/scheduler/work.rs:45:9
30: mmtk::scheduler::worker::GCWorker<VM>::run
at /home/wks/projects/mmtk-github/mmtk-core/src/scheduler/worker.rs:244:13
31: mmtk::memory_manager::start_worker
at /home/wks/projects/mmtk-github/mmtk-core/src/memory_manager.rs:470:5
32: start_worker
at /home/wks/projects/mmtk-github/mmtk-openjdk/mmtk/src/api.rs:214:9
33: _ZN19MMTkCollectorThread3runEv
at /home/wks/projects/mmtk-github/openjdk/../mmtk-openjdk/openjdk/mmtkCollectorThread.cpp:36:15
34: _ZN6Thread8call_runEv
at /home/wks/projects/mmtk-github/openjdk/src/hotspot/share/runtime/thread.cpp:402:12
35: thread_native_entry
at /home/wks/projects/mmtk-github/openjdk/src/hotspot/os/linux/os_linux.cpp:826:19
36: <unknown>
37: <unknown>
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
fatal runtime error: failed to initiate panic, error 5
fish: Job 1, 'MMTK_THREADS=1 MMTK_NO_REFERENC…' terminated by signal SIGABRT (Abort)
What went wrong?
This portion of the log reveals the cause:
[2024-04-19T12:15:46Z DEBUG mmtk::util::reference_processor] Ending ReferenceProcessor.scan(SOFT)
[2024-04-19T12:15:46Z TRACE mmtk::util::reference_processor] Add soft candidate: 0x4066bf28
[2024-04-19T12:15:46Z DEBUG mmtk::util::reference_processor] Starting ReferenceProcessor.scan(WEAK)
A new soft candidate is discovered after processing all soft references. The OpenJDK binding discovers soft/weak/phantom references gradually during tracing. The new soft candidate 0x4066bf28 was added. Itself was traced. But when it was scanned, it added itself to the reference processor using add_soft_candidate. However, it never gets processed, and its referent is not traced, either.
In SemiSpace, the referent pointer still pointed to the from-space. During the Release stage, it tried to find references to enqueue, and the debug assertion discovered that some SoftReference still pointed to the from space.
In MarkCompact, things were a bit complicated. During CalculateForwarding, the GC computeed the forwarded addresses of all live objects. However, since the referent of the newly discovered SoftReference was not marked, it was considered dead, and was not assigned a forwarding pointer. However, during SecondRoot, the GC computed another transitive closure and found the SoftReference to be live. It then attempted to forward the referent (which is dead), and found it did not have a forwarding pointer. The error would have silently slipped away without checking, but after I removed ObjectReference::NULL, it started to require an explicit NULL check against the forwarding pointer, and caught the bug.