Skip to content

Incorrect OBJ/IND/BLK removal. #39823

@sandreenko

Description

@sandreenko

@erozenfeld I was experimenting with the suspicious code from #38004 that we have discussed early today and have created a repro, run this on x64 windows checked:

// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Numerics;
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86;
using System.Runtime.CompilerServices;
using System;
using System.Diagnostics;


class Runtime_39424
{
    struct IntsWrapped
    {
        public int i1;
        public int i2;
        public int i3;
        public int i4;
    };

    [MethodImpl(MethodImplOptions.NoInlining)]
    static unsafe int TestUnusedObjCopy(IntsWrapped* ps)
    {
        IntsWrapped s = *ps;
        return 100;
    }


    public static unsafe int Main()
    {
        try
        {
            TestUnusedObjCopy((IntsWrapped*)0);
            Debug.Assert(false, "unreachable");
        }
        catch
        {
            return 100;
        }
        return -1;
    }
}

the current master will fail with assert or return -1 in release, 3.1 will correctly generate an exception.

The problems are in these two blocks:

// This is a block assignment. An indirection of the rhs is not considered to
// happen until the assignment, so we will extract the side effects from only
// the address.
if (rhsNode->OperIsIndir())
{
assert(rhsNode->OperGet() != GT_NULLCHECK);
rhsNode = rhsNode->AsIndir()->Addr();
}
}

if (data->isIndir())
{
// This is a block assignment. An indirection of the rhs is not considered
// to happen until the assignment so mark it as non-faulting.
data->gtFlags |= GTF_IND_NONFAULTING;
}

They are not checking that nodes are side-effect free and deleting null-pointer dereferencing. What is interesting, the second block is 4 years old and it what causes the issue in the repro, so I do not know how it works in 3.1.

Another strange thing is that these checks are only for OperIsIndir, I do not see reasons why they should not process OBJ/BLK.

The easiest fix is to delete both blocks and transform IND/OBJ/BLK to NULLCHECK. However, it would be very intersesting to see how it was working in the past.

Found during #39737 work.

I think we should consider implementing #10249 sooner than later with all issues that we see with these flags.

category:correctness
theme:structs
skill-level:intermediate
cost:small

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions