Browse Source

Protect IsInst against multi-step inlining -- we can only allow `Box` as the top-level argument, not anywhere within the argument tree.

null-coalescing-assignment
Daniel Grunwald 4 months ago
parent
commit
f826037acc
  1. 4
      ICSharpCode.Decompiler/IL/Instructions/ILInstruction.cs
  2. 10
      ICSharpCode.Decompiler/IL/Instructions/IsInst.cs

4
ICSharpCode.Decompiler/IL/Instructions/ILInstruction.cs

@ -958,6 +958,10 @@ namespace ICSharpCode.Decompiler.IL @@ -958,6 +958,10 @@ namespace ICSharpCode.Decompiler.IL
/// Unlike `CanInlineIntoSlot`, this is not about descendants of the slot, only about
/// whether SetChild(childIndex, newChild) is valid.
/// (i.e. this controls whether FindLoadInNext may return the specified slot as a final result)
///
/// Warning: after newChild is inlined, other nodes may be inlined into newChild's sub-instructions
/// without asking this function again. This means this function is not suitable for protecting
/// a slot from having side effects, use `CanInlineIntoSlot` for that.
/// </summary>
internal virtual bool SatisfiesSlotRestrictionForInlining(int childIndex, ILInstruction newChild)
{

10
ICSharpCode.Decompiler/IL/Instructions/IsInst.cs

@ -25,10 +25,10 @@ namespace ICSharpCode.Decompiler.IL; @@ -25,10 +25,10 @@ namespace ICSharpCode.Decompiler.IL;
partial class IsInst
{
internal override bool SatisfiesSlotRestrictionForInlining(int childIndex, ILInstruction newChild)
internal override bool CanInlineIntoSlot(int childIndex, ILInstruction newChild)
{
Debug.Assert(childIndex == 0);
Debug.Assert(base.SatisfiesSlotRestrictionForInlining(childIndex, newChild));
Debug.Assert(base.CanInlineIntoSlot(childIndex, newChild));
if (this.Type.IsReferenceType == true)
{
return true; // reference-type isinst is always supported
@ -37,12 +37,16 @@ partial class IsInst @@ -37,12 +37,16 @@ partial class IsInst
{
return true; // emulated via "expr is T ? (T)expr : null"
}
else if (newChild is Box box && SemanticHelper.IsPure(box.Argument.Flags))
else if (newChild is Box box && SemanticHelper.IsPure(box.Argument.Flags) && this.Argument.Children.Count == 0)
{
// Also emulated via "expr is T ? (T)expr : null".
// This duplicates the boxing side-effect, but that's harmless as one of the boxes is only
// used in the `expr is T` type test where the object identity can never be observed.
// This appears as part of C# pattern matching, inlining early makes those code patterns easier to detect.
// We can only do this if the Box appears directly top-level in the IsInst, we cannot inline Box instructions
// deeper into our Argument subtree. So restricts to the case were the previous argument has no children
// (which means inlining can only replace the argument, not insert within it).
return true;
}
if (this.Parent is UnboxAny unboxAny && ExpressionBuilder.IsUnboxAnyWithIsInst(unboxAny, this.Type))

Loading…
Cancel
Save