File: Emit\ManagedAddressTests.cs
Web Access
Project: src\src\Compilers\CSharp\Test\Emit2\Microsoft.CodeAnalysis.CSharp.Emit2.UnitTests.csproj (Microsoft.CodeAnalysis.CSharp.Emit2.UnitTests)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.Test.Utilities;
using Xunit;
 
namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Emit
{
    public class ManagedAddressTests : CSharpTestBase
    {
        [Fact]
        public void TestPointerToArray()
        {
            var source = """
                using System;
 
                unsafe
                {
                    var x = new[] { 0, 1, 2 };
                    int[]* xp = &x;
                    var c = new C(xp);
                    c.Print();
                }
 
                public unsafe class C
                {
                    private int[]* _x;
 
                    public C(int[]* x)
                    {
                        _x = x;
                    }
 
                    public void Print()
                    {
                        int[] x = *_x;
                        for (int i = 0; i < x.Length; i++)
                        {
                            Console.Write(x[i]);
                        }
                    }
                }
                """;
 
            var comp = CreateCompilation(source, options: TestOptions.UnsafeDebugExe).VerifyDiagnostics(
                // (6,5): warning CS8500: This takes the address of, gets the size of, or declares a pointer to a managed type ('int[]')
                //     int[]* xp = &x;
                Diagnostic(ErrorCode.WRN_ManagedAddr, "int[]*").WithArguments("int[]").WithLocation(6, 5),
                // (6,17): warning CS8500: This takes the address of, gets the size of, or declares a pointer to a managed type ('int[]')
                //     int[]* xp = &x;
                Diagnostic(ErrorCode.WRN_ManagedAddr, "&x").WithArguments("int[]").WithLocation(6, 17),
                // (13,20): warning CS8500: This takes the address of, gets the size of, or declares a pointer to a managed type ('int[]')
                //     private int[]* _x;
                Diagnostic(ErrorCode.WRN_ManagedAddr, "_x").WithArguments("int[]").WithLocation(13, 20),
                // (15,21): warning CS8500: This takes the address of, gets the size of, or declares a pointer to a managed type ('int[]')
                //     public C(int[]* x)
                Diagnostic(ErrorCode.WRN_ManagedAddr, "x").WithArguments("int[]").WithLocation(15, 21)
                );
            var verifier = CompileAndVerify(comp, expectedOutput: "012", verify: Verification.Fails with
            {
                ILVerifyMessage = """
                [<Main>$]: Expected numeric type on the stack. { Offset = 0x12, Found = address of 'int32[]' }
                [.ctor]: Unmanaged pointers are not a verifiable type. { Offset = 0x9 }
                [Print]: Expected ByRef on the stack. { Offset = 0x7, Found = Native Int }
                """,
                PEVerifyMessage = """
                [ : Program::<Main>$][offset 0x00000012][found address of ref ] Expected numeric type on the stack.
                [ : C::.ctor][offset 0x00000009] Unmanaged pointers are not a verifiable type.
                [ : C::Print][offset 0x00000007][found unmanaged pointer] Expected ByRef on the stack.
                """,
            });
 
            verifier.VerifyMethodBody("<top-level-statements-entry-point>", """
                {
                  // Code size       36 (0x24)
                  .maxstack  4
                  .locals init (int[] V_0, //x
                                int[]* V_1, //xp
                                C V_2) //c
                  // sequence point: {
                  IL_0000:  nop
                  // sequence point: var x = new[] { 0, 1, 2 };
                  IL_0001:  ldc.i4.3
                  IL_0002:  newarr     "int"
                  IL_0007:  dup
                  IL_0008:  ldc.i4.1
                  IL_0009:  ldc.i4.1
                  IL_000a:  stelem.i4
                  IL_000b:  dup
                  IL_000c:  ldc.i4.2
                  IL_000d:  ldc.i4.2
                  IL_000e:  stelem.i4
                  IL_000f:  stloc.0
                  // sequence point: int[]* xp = &x;
                  IL_0010:  ldloca.s   V_0
                  IL_0012:  conv.u
                  IL_0013:  stloc.1
                  // sequence point: var c = new C(xp);
                  IL_0014:  ldloc.1
                  IL_0015:  newobj     "C..ctor(int[]*)"
                  IL_001a:  stloc.2
                  // sequence point: c.Print();
                  IL_001b:  ldloc.2
                  IL_001c:  callvirt   "void C.Print()"
                  IL_0021:  nop
                  // sequence point: }
                  IL_0022:  nop
                  IL_0023:  ret
                }
                """);
 
            verifier.VerifyMethodBody("C..ctor", """
                {
                  // Code size       16 (0x10)
                  .maxstack  2
                  // sequence point: public C(int[]* x)
                  IL_0000:  ldarg.0
                  IL_0001:  call       "object..ctor()"
                  IL_0006:  nop
                  // sequence point: {
                  IL_0007:  nop
                  // sequence point: _x = x;
                  IL_0008:  ldarg.0
                  IL_0009:  ldarg.1
                  IL_000a:  stfld      "int[]* C._x"
                  // sequence point: }
                  IL_000f:  ret
                }
                """);
 
            verifier.VerifyMethodBody("C.Print", """
                {
                  // Code size       39 (0x27)
                  .maxstack  2
                  .locals init (int[] V_0, //x
                                int V_1, //i
                                bool V_2)
                  // sequence point: {
                  IL_0000:  nop
                  // sequence point: int[] x = *_x;
                  IL_0001:  ldarg.0
                  IL_0002:  ldfld      "int[]* C._x"
                  IL_0007:  ldind.ref
                  IL_0008:  stloc.0
                  // sequence point: int i = 0
                  IL_0009:  ldc.i4.0
                  IL_000a:  stloc.1
                  // sequence point: <hidden>
                  IL_000b:  br.s       IL_001c
                  // sequence point: {
                  IL_000d:  nop
                  // sequence point: Console.Write(x[i]);
                  IL_000e:  ldloc.0
                  IL_000f:  ldloc.1
                  IL_0010:  ldelem.i4
                  IL_0011:  call       "void System.Console.Write(int)"
                  IL_0016:  nop
                  // sequence point: }
                  IL_0017:  nop
                  // sequence point: i++
                  IL_0018:  ldloc.1
                  IL_0019:  ldc.i4.1
                  IL_001a:  add
                  IL_001b:  stloc.1
                  // sequence point: i < x.Length
                  IL_001c:  ldloc.1
                  IL_001d:  ldloc.0
                  IL_001e:  ldlen
                  IL_001f:  conv.i4
                  IL_0020:  clt
                  IL_0022:  stloc.2
                  // sequence point: <hidden>
                  IL_0023:  ldloc.2
                  IL_0024:  brtrue.s   IL_000d
                  // sequence point: }
                  IL_0026:  ret
                }
                """);
        }
    }
}