Fix fragile List::binarySearch() usage#10047
Fix fragile List::binarySearch() usage#10047cmarcelo wants to merge 1 commit intoshader-slang:masterfrom
Conversation
|
No actionable comments were generated in the recent review. 🎉 📝 WalkthroughWalkthroughReplaced Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~8 minutes Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Comment |
|
This patch was motivated by #10048. |
There was a problem hiding this comment.
Pull request overview
This PR fixes fragile usage of List::binarySearch() in the semantic checking of generic type equality constraints. The old code incorrectly used binarySearch() with pointer comparison on a member list ordered by declaration position, which only worked by chance because the allocator happened to produce pointers in declaration order. This is replaced with the existing helper function _compareDeclsInCommonParentByOrderOfDeclaration() that properly compares declarations by their position in the parent container, following the guidance from PR #7242 to use mediated access to ContainerDecl members.
Changes:
- Replaced fragile
binarySearch()usage with proper declaration order comparison helper function - Added forward declaration for
_compareDeclsInCommonParentByOrderOfDeclaration()
ecc4e7a to
a9dd060
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@source/slang/slang-check-decl.cpp`:
- Around line 3581-3582: The subtraction using auto subIndex =
ancestor->getMembers().indexOf(subAncestor) and auto supIndex =
ancestor->getMembers().indexOf(supAncestor) must guard against indexOf returning
-1; if either subIndex or supIndex is -1, avoid using int(supIndex - subIndex)
and instead fall back to the existing compareDecls(...) logic (or assert/handle
error) to determine ordering. Update the code around where subIndex/supIndex are
computed so you check (subIndex < 0 || supIndex < 0) and call compareDecls(…)
when invalid, otherwise keep the current subtraction path.
| auto subIndex = ancestor->getMembers().indexOf(subAncestor); | ||
| auto supIndex = ancestor->getMembers().indexOf(supAncestor); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, locate and examine the List class definition and indexOf method
rg -B2 -A10 'indexOf\(' --type cpp --type hpp | head -100Repository: shader-slang/slang
Length of output: 89
🏁 Script executed:
# Check Index type definition
rg 'typedef.*Index|using.*Index' --type hpp | head -30Repository: shader-slang/slang
Length of output: 89
🏁 Script executed:
# Examine the context at lines 3581-3582
sed -n '3570,3600p' source/slang/slang-check-decl.cppRepository: shader-slang/slang
Length of output: 1031
🏁 Script executed:
# Search for GenericDecl definition and its member structure
rg -B2 -A15 'class GenericDecl' --type hpp | head -80Repository: shader-slang/slang
Length of output: 89
🏁 Script executed:
# Check ContainerDecl::getMembers implementation
rg -B2 -A10 'getMembers\(\)' --type hpp --type cpp | head -100Repository: shader-slang/slang
Length of output: 89
🏁 Script executed:
# Search for List class and indexOf method definition
rg 'indexOf' -A5 -B2 --type c --type h | head -150Repository: shader-slang/slang
Length of output: 7585
🏁 Script executed:
# Check Index type definition
rg 'typedef.*Index|using.*Index' --type h | head -50Repository: shader-slang/slang
Length of output: 3685
🏁 Script executed:
# Search for GenericDecl class definition
rg -A20 'class GenericDecl' --type h | head -100Repository: shader-slang/slang
Length of output: 5103
🏁 Script executed:
# Check ContainerDecl implementation
rg -A10 'class ContainerDecl' --type h | head -150Repository: shader-slang/slang
Length of output: 2891
🏁 Script executed:
# Search for getMembers in headers
rg -B2 -A8 'getMembers\(' --type h --type c | head -100Repository: shader-slang/slang
Length of output: 1361
🏁 Script executed:
# Get complete indexOf implementation from slang-list.h
sed -n '1,/template.*indexOf/p' source/core/slang-list.h | tail -40Repository: shader-slang/slang
Length of output: 891
🏁 Script executed:
# Find the full indexOf method with return statement
rg -B2 -A15 'template.*indexOf\(const T2' source/core/slang-list.hRepository: shader-slang/slang
Length of output: 44
🏁 Script executed:
# Search for getDirectMemberDecls implementation
rg -B2 -A15 'getDirectMemberDecls' --type c --type h | head -150Repository: shader-slang/slang
Length of output: 9271
🏁 Script executed:
# Check if FIDDLE() marked fields are included in member lists
rg -B5 -A10 'FIDDLE.*inner' source/slang/slang-ast-decl.hRepository: shader-slang/slang
Length of output: 532
🏁 Script executed:
# Look for how GenericDecl members are enumerated
rg -B10 -A10 'class GenericDecl' source/slang/slang-ast-decl.hRepository: shader-slang/slang
Length of output: 602
🏁 Script executed:
# Find getDirectMemberDecls implementation in cpp files
rg -B2 -A20 'getDirectMemberDecls\(\)' --type c | head -100Repository: shader-slang/slang
Length of output: 6349
🏁 Script executed:
# Search for how GenericDecl members are handled in the codebase
rg 'GenericDecl.*inner' --type c --type h | head -50Repository: shader-slang/slang
Length of output: 44
🏁 Script executed:
# Find the complete indexOf implementation with return statement
rg -B2 -A8 'Index indexOf' source/core/slang-list.hRepository: shader-slang/slang
Length of output: 284
🏁 Script executed:
# Search for getDirectMemberDecls implementation in cpp
rg -B3 -A15 'List<Decl\*> const& ContainerDecl::getDirectMemberDecls' --type cRepository: shader-slang/slang
Length of output: 44
🏁 Script executed:
# Also check slang-ast-decl.cpp for implementation
grep -n 'getDirectMemberDecls' source/slang/slang-ast-decl.cpp | head -20Repository: shader-slang/slang
Length of output: 196
🏁 Script executed:
# Look at what fields are included for GenericDecl member enumeration
rg -B5 -A20 'class GenericDecl' source/slang/slang-ast-decl.cppRepository: shader-slang/slang
Length of output: 44
🏁 Script executed:
# Check how FIDDLE macro works - does it include fields in member lists?
rg -B2 -A5 'FIDDLE\(\)' source/slang/slang-ast-decl.h | grep -A5 'GenericDecl'Repository: shader-slang/slang
Length of output: 385
🏁 Script executed:
# Read the implementation at line 304
sed -n '300,330p' source/slang/slang-ast-decl.cppRepository: shader-slang/slang
Length of output: 687
🏁 Script executed:
# Look for how _directMemberDecls is populated for GenericDecl
rg '_directMemberDecls' --type c --type h | grep -i genericRepository: shader-slang/slang
Length of output: 44
🏁 Script executed:
# Search for how GenericDecl handles its inner decl in member operations
rg -B5 -A10 'GenericDecl.*addMember\|addDirectMemberDecl.*GenericDecl' --type cRepository: shader-slang/slang
Length of output: 44
🏁 Script executed:
# Check if there's special handling for GenericDecl's inner in the context of checkGenericTypeEqualityConstraintSubType
sed -n '3550,3600p' source/slang/slang-check-decl.cppRepository: shader-slang/slang
Length of output: 1938
🏁 Script executed:
# Look for tests or usages that show expected behavior when ancestor is GenericDecl
rg -B10 -A10 'findDeclsLowestCommonAncestor.*GenericDecl\|GenericDecl.*indexOf' --type cRepository: shader-slang/slang
Length of output: 44
🏁 Script executed:
# Check the actual field structure - is inner a direct member or a special field?
rg -B10 -A30 'class GenericDecl' source/slang/slang-ast-decl.h | head -60Repository: shader-slang/slang
Length of output: 1027
🏁 Script executed:
# Search for how GenericTypeConstraintDecl relates to GenericDecl
rg -B5 -A15 'class GenericTypeConstraintDecl' source/slang/slang-ast-decl.hRepository: shader-slang/slang
Length of output: 819
🏁 Script executed:
# Look for where generic parameters are added as members
rg -B5 -A10 'addMember.*GenericTypeParam\|GenericTypeParam.*addMember' --type c | head -50Repository: shader-slang/slang
Length of output: 44
🏁 Script executed:
# Check if there's defensive code elsewhere that handles indexOf returning -1
rg -B3 -A3 'indexOf.*!= -1\|indexOf.*>= 0\|indexOf.*< 0' --type c --type h | head -80Repository: shader-slang/slang
Length of output: 44
🏁 Script executed:
# Let me look at the broader context of checkGenericTypeEqualityConstraintSubType
sed -n '3550,3620p' source/slang/slang-check-decl.cppRepository: shader-slang/slang
Length of output: 2569
🏁 Script executed:
# Check findDeclsLowestCommonAncestor to understand what it returns
rg -B5 -A20 'findDeclsLowestCommonAncestor' --type c --type h | head -100Repository: shader-slang/slang
Length of output: 44
🏁 Script executed:
# Look for safeguards elsewhere in the codebase when using indexOf result
rg -B2 -A5 'indexOf.*-1' source/core/slang-list.hRepository: shader-slang/slang
Length of output: 237
🏁 Script executed:
# Search for where GenericTypeParamDecl instances are added as members
rg -B10 -A10 'GenericTypeParamDecl.*addMember\|addDirectMemberDecl.*Param' --type c | head -50Repository: shader-slang/slang
Length of output: 44
🏁 Script executed:
# Look at the broader generic decl creation flow
rg -B5 -A15 'new GenericTypeParamDecl\|GenericTypeParamDecl\(' --type c | head -80Repository: shader-slang/slang
Length of output: 44
🏁 Script executed:
# See if there's any documentation about what getMembers returns for GenericDecl
rg -B3 -A3 'GenericDecl.*getMembers\|getMembers.*GenericDecl' --type c --type hRepository: shader-slang/slang
Length of output: 44
🏁 Script executed:
# Check if there are any assertions or checks before using indexOf result elsewhere
rg -B2 -A2 'subIndex.*supIndex\|supIndex.*subIndex' --type cRepository: shader-slang/slang
Length of output: 44
🏁 Script executed:
# Final check: confirm Index(-1) is the standard sentinel by looking at contains patterns
rg 'indexOf.*!= -1\|indexOf.*== -1\|!= Index\(-1\)' source/core/slang-list.h source/core/slang-array.hRepository: shader-slang/slang
Length of output: 44
Add guards against indexOf returning -1 to prevent incorrect index subtraction.
At lines 3581-3582, indexOf can return -1 if subAncestor or supAncestor is not present in ancestor->getMembers(). The direct subtraction int(supIndex - subIndex) then produces incorrect ordering: (-1 - 0 = -1), (0 - (-1) = 1), or (-1 - (-1) = 0), with the zero case silently triggering the diagnostic at line 3593. Check both indices and either assert they are valid or fall back to compareDecls.
Suggested guard
auto subIndex = ancestor->getMembers().indexOf(subAncestor);
auto supIndex = ancestor->getMembers().indexOf(supAncestor);
+ if (subIndex == Index(-1) || supIndex == Index(-1))
+ return compareDecls(subAncestor, supAncestor);
return int(supIndex - subIndex);📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| auto subIndex = ancestor->getMembers().indexOf(subAncestor); | |
| auto supIndex = ancestor->getMembers().indexOf(supAncestor); | |
| auto subIndex = ancestor->getMembers().indexOf(subAncestor); | |
| auto supIndex = ancestor->getMembers().indexOf(supAncestor); | |
| if (subIndex == Index(-1) || supIndex == Index(-1)) | |
| return compareDecls(subAncestor, supAncestor); | |
| return int(supIndex - subIndex); |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@source/slang/slang-check-decl.cpp` around lines 3581 - 3582, The subtraction
using auto subIndex = ancestor->getMembers().indexOf(subAncestor) and auto
supIndex = ancestor->getMembers().indexOf(supAncestor) must guard against
indexOf returning -1; if either subIndex or supIndex is -1, avoid using
int(supIndex - subIndex) and instead fall back to the existing compareDecls(...)
logic (or assert/handle error) to determine ordering. Update the code around
where subIndex/supIndex are computed so you check (subIndex < 0 || supIndex < 0)
and call compareDecls(…) when invalid, otherwise keep the current subtraction
path.
There was a problem hiding this comment.
Would someone help verify if it is applicable, is it a valid concern? My own understanding here is that we expect both to be found.
|
@coderabbitai summary |
✅ Actions performedSummary regeneration triggered. |
The binarySearch() was comparing pointer addresses on the member list that is ordered by the declaration position. That may not necessarily work unless is guaranteed that the allocator produces pointers in declaration order and they are not reordered. Use indexOf() instead. See bfae49d ("Mediate access to ContainerDecl members (shader-slang#7242)") for context.
a9dd060 to
c707bf4
Compare
The binarySearch() was comparing pointer addresses on the member list
that is ordered by the declaration position. That may not necessarily
work unless is guaranteed that the allocator produces pointers in
declaration order and they are not reordered. Use indexOf() instead.
See bfae49d ("Mediate access to ContainerDecl members (#7242)") for context.