-
Notifications
You must be signed in to change notification settings - Fork 82
fix: SCCP bug with null checks in object traversal loops #1268
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
Correct SCCP's handling of object references in loops by conservatively marking values as OverDefined when loop back-edges are present and not all predecessors are analyzed. This prevents unsafe elimination of null checks in while loops traversing linked objects. Also, add comprehensive regression tests to ensure correct SCCP behavior for various linked list traversal scenarios. Fix typo in method name ProcessInstructionsContinuously.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR fixes a critical bug in the Sparse Conditional Constant Propagation (SCCP) optimization stage where null checks in while-loops traversing linked objects were incorrectly eliminated, causing infinite loops and test crashes.
Key Changes:
- Added conservative handling for phi nodes with unanalyzed loop back-edges in SCCP to prevent premature null-check elimination
- Added 7 comprehensive unit tests targeting the specific bug pattern: object reference traversal in while loops with null checks
- Fixed spelling of method name from "Continuiously" to "Continuously"
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| Source/Mosa.Compiler.Framework/Analysis/SparseConditionalConstantPropagation.cs | Added logic to detect phi nodes with unanalyzed predecessors and mark them as OverDefined for reference types; corrected method name spelling |
| Source/Mosa.UnitTests/FlowControl/WhileTests.cs | Added LinkedNode helper class and 7 regression tests covering various linked-list traversal scenarios |
Comments suppressed due to low confidence (1)
Source/Mosa.Compiler.Framework/Analysis/SparseConditionalConstantPropagation.cs:1
- The first loop (lines 1404-1423) contains duplicate logic that can be simplified. The
executablevariable is checked at line 1410 withif (!executable) continue;, making the subsequent conditional at lines 1415-1422 unreachable for theelsebranch. The counting logic should be consolidated into a single pass without the early continue.
// Copyright (c) MOSA Project. Licensed under the New BSD License.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| for (var index = 0; index < currentBlock.PreviousBlocks.Count; index++) | ||
| { | ||
| var predecessor = sourceBlocks[index]; | ||
|
|
||
| var executable = blockStates[predecessor.Sequence]; | ||
|
|
||
| if (!executable) | ||
| continue; |
Copilot
AI
Jan 2, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This second loop (starting at line 1436) duplicates the iteration logic from the first loop (line 1404). Consider refactoring to iterate once and collect both the analysis counts and perform the subsequent processing in the same loop to reduce code duplication.
|
I’m still reviewing the conservative logic for SCCP. From what I can tell, the special handling for reference types probably isn’t needed, and it might not yield the optimal disposition state of the variable. |
SCCP Loop Back-Edge Fix
Issue Summary
The
SparseConditionalConstantPropagationStagewas incorrectly removing null checks and return statements in methods containing while-loops that traverse linked objects, causing infinite loops and test failures.Affected Tests (Before Fix)
Three unit tests in
WhileTests.cswere failing with identical symptoms:WhileTests::WhileObjectTraversalNullCheck()- Expected: 6, Result: NULL (CRASHED)WhileTests::WhileObjectTraversalLongChain()- Expected: True, Result: NULL (CRASHED)WhileTests::WhileObjectTraversalSum()- Expected: 100, Result: NULL (CRASHED)All tests involved the same pattern:
Root Cause
The Bug
In the
Phi()method ofSparseConditionalConstantPropagation.cs, when analyzing phi nodes in loops:Initial Analysis: The phi node
v42 <= v51, v36 (L_0002B, L_00000)has two sources:L_00000(entry block): executable, contributesv36(NewObject, not null)L_0002B(loop back-edge): not yet marked executable during first iterationIncorrect Assumption: SCCP only saw the executable predecessor with a non-null value (
v36) and concluded the phi result (v42) is always not nullAggressive Optimization: Based on this incorrect conclusion:
IR.BranchObject [!=] v42, nullwas removed as "always false"IR Transformation (Before Fix)
The Fix
Solution
Modified the
Phi()method to be conservative when analyzing phi nodes with unanalyzed predecessors (loop back-edges):Key Changes
Detect Partial Analysis: Track when some predecessors are analyzed but others aren't (loop back-edge scenario)
Conservative Handling: When a phi node has:
→ Mark as
OverDefinedto prevent assumptions about null statePreserve Correctness: This ensures:
Results
After Fix
Previously Failing Tests Now Pass
WhileTests::WhileObjectTraversalNullCheck()- Returns: 6WhileTests::WhileObjectTraversalLongChain()- Returns: TrueWhileTests::WhileObjectTraversalSum()- Returns: 100Additional Tests Added
To provide comprehensive coverage of the bug pattern, additional edge-case tests were added:
WhileTests::WhileObjectTraversalCount()- Returns: 5WhileTests::WhileObjectTraversalWithModification()- Returns: TrueWhileTests::WhileObjectNullCheckAtStart()- Returns: 0WhileTests::WhileObjectSingleNode()- Returns: 42Issue Category
Testing
The fix was validated by:
Test Coverage
All tests in
Mosa.UnitTests/FlowControl/WhileTests.csthat target the SCCP bug pattern:WhileObjectTraversalNullCheck()- Simple 3-node linked list traversal with null checkWhileObjectTraversalCount()- Count nodes in a 5-node chainWhileObjectTraversalLongChain()- Traverse 10-node chain and verify last valueWhileObjectTraversalSum()- Sum values from 4-node chain (10+20+30+40=100)WhileObjectTraversalWithModification()- Modify values during traversalWhileObjectNullCheckAtStart()- Edge case: null listWhileObjectSingleNode()- Edge case: single-node listThese tests specifically target the SCCP bug pattern:
.Next)All tests pass, confirming the fix prevents the bug from recurring.
Files Modified
Mosa.Compiler.Framework/Analysis/SparseConditionalConstantPropagation.csPhi()method (lines ~1060-1125)Mosa.UnitTests/FlowControl/WhileTests.csLinkedNodehelper classTechnical Notes
SCCP Algorithm
Sparse Conditional Constant Propagation is an optimizing compiler transformation that:
Phi Nodes in SSA
In Static Single Assignment (SSA) form:
Conservative vs. Aggressive Optimization
The fix applies conservative analysis to maintain correctness while still enabling optimizations where safe.