C#不安全代码指针的使用——vscode

链接: link

您编写的大多数 C# 代码都是“可验证的安全代码”。可验证的安全代码意味着 .NET 工具可以验证代码是否安全。通常,安全代码不会使用指针直接访问内存。它也不分配原始内存。它改为创建托管对象。

C# 支持不安全的上下文,您可以在其中编写无法验证的代码。在上下文中,代码可以使用指针、分配和释放内存块,以及使用函数指针调用方法。C# 中的不安全代码不一定是危险的;它只是无法验证安全性的代码。unsafe

不安全代码具有以下属性:

方法可以将方法、类型和代码块定义为不安全的。
1.在某些情况下,不安全的代码可能会通过删除数组边界检查来提高应用程序的性能。
2.调用需要指针的本机函数时,需要不安全的代码。
3.使用不安全的代码会带来安全性和稳定性风险。
4.必须使用 AllowUnsafeBlocks 编译器选项编译包含不安全块的代码。

vscode Unsafe code, pointer types, and function pointers
这个错误信息通常出现在使用Visual Studio Code编辑C#代码时。它表示你的代码正在使用不安全的代码特性,比如指针类型或者函数指针。在C#中,默认情况下,项目被设置为“安全”模式,这意味着默认情况下不允许使用指针等不安全特性。

解释:

Unsafe code: 指的是C#中使用 unsafe 关键字修饰的代码块,它允许你在C#中使用指针等低级操作。

pointer types: 指的是C#中的指针类型,允许直接操作内存地址。

function pointers: 指的是C#中的委托(Delegate)类型,可以指向函数的指针。

解决方法:

1.如果你确实需要使用这些不安全特性,你可以在项目的 .csproj 文件中添加一个属性来允许不安全代码。例如:

<PropertyGroup>
  <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>

2.将 unsafe 关键字添加到你的方法或者代码块前面。


unsafe static void MyUnsafeMethod()
{
    // 你的不安全代码
}

3.如果你不需要使用不安全特性,考虑重写你的代码,避免使用指针和不安全操作。
请记住,在允许不安全代码的情况下,你需要确保不会因直接内存操作而引入安全漏洞。

示例1,官方pinter.cs:

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

using System.Diagnostics;
using System.Runtime.Serialization;
using System.Diagnostics.CodeAnalysis;

//[CLSCompliant(false)]
public sealed unsafe class Pointer : ISerializable
{
    // CoreCLR: Do not add or remove fields without updating the ReflectionPointer class in runtimehandles.h
    private readonly void* _ptr;
    private readonly Object _ptrType;

    private Pointer(void* ptr, Object ptrType)
    {
        _ptr = ptr;
        _ptrType = ptrType;
    }

    public static object Box(void* ptr, Type type)
    {
        ArgumentNullException.ThrowIfNull(type);

        if (!type.IsPointer)
            Console.WriteLine("此类型不是指针");
            throw new ArgumentException("s11111");
        if (type is not Object rtType)
            Console.WriteLine("此类型不是Object");
            throw new ArgumentException("s");
        return new Pointer(ptr, type);
    }

    public static void* Unbox(object ptr)
    {
        if (!(ptr is Pointer))
            Console.WriteLine("此类型不是Pointer指针");
        return ((Pointer)ptr)._ptr;
    }

    public override unsafe bool Equals([NotNullWhen(true)] object? obj)
    {
        if (obj is Pointer pointer)
        {
            return _ptr == pointer._ptr;
        }

        return false;
    }

    public override unsafe int GetHashCode() => ((nuint)_ptr).GetHashCode();


    void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
    {
        
    }
}

示例2,A.cs:

using System.Runtime.InteropServices;
//1.注意这里的CharSet,它由c中wchar_t决定的,如果c程序编译时使用Unicode,这里就用CharSet.Unicode,否则使用CharSet.Ansi。
//2.一般默认情况下,内存的分配是4byte的整数倍(注意Pack的值
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 4)]

public struct A 
{
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]

    public string osdbuffer;       

    public ushort ix;                       //显示坐标x

    public ushort iy;                       //显示坐标y

}

main方法:

A s_a = new A();
int lenght = Marshal.SizeOf(s_a);
IntPtr pA = Marshal.AllocHGlobal(lenght);
Marshal.StructureToPtr(s_a, pA, true);
int type = 1;
int ret = SetConfig(type, pA);
Console.WriteLine("结果1:" + ret);
Marshal.FreeHGlobal(pA);
Console.WriteLine("结果2:" + ret);

int SetConfig(int type, IntPtr p)
{
    Console.WriteLine("结果IntPtr:" + p.ToString());
    return IntPtr.Size;
}

示例3,
A.cs:

using System.Runtime.InteropServices;
//1.注意这里的CharSet,它由c中wchar_t决定的,如果c程序编译时使用Unicode,这里就用CharSet.Unicode,否则使用CharSet.Ansi。
//2.一般默认情况下,内存的分配是4byte的整数倍(注意Pack的值
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 4)]

public struct A 
{

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]

    public string osdbuffer;       

    public ushort ix;                       //显示坐标x

    public ushort iy;                       //显示坐标y

    public IntPtr pB;

}

B.cs:

using System.Runtime.InteropServices;

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 4)]

public struct B
{

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]

    public string osdbuffer;       
}

main方法:

B s_b = new B();
//赋值省略
int lenght1 = Marshal.SizeOf(s_b);
IntPtr pB = Marshal.AllocHGlobal(lenght1);
Marshal.StructureToPtr(s_b, pB, true);
A s_a = new A();
s_a.pB = pB;
//其他赋值
int lenght2 = Marshal.SizeOf(s_a);
IntPtr pA = Marshal.AllocHGlobal(lenght2);
Marshal.StructureToPtr(s_a, pA, true);
int type = 1; 
int ret = SetConfig(type, pA);
Marshal.FreeHGlobal(pB);
Marshal.FreeHGlobal(pA);
Console.WriteLine("结果3:" + ret);

int SetConfig(int type, IntPtr p)
{
    Console.WriteLine("结果IntPtr:" + p.ToString());
    return IntPtr.Size;
}

示例4:

// Normal pointer to an object.
int[] a = new int []{10, 20, 30, 40, 50};
// Must be in unsafe code to use interior pointers.
unsafe
{
    // Must pin object on heap so that it doesn't move while using interior pointers.
    fixed (int* p = &a[0])
    {
        // p is pinned as well as object, so create another pointer to show incrementing it.
        int* p2 = p;
        Console.WriteLine(*p2);
        // Incrementing p2 bumps the pointer by four bytes due to its type ...
        p2 += 1;
        Console.WriteLine(*p2);
        p2 += 1;
        Console.WriteLine(*p2);
        Console.WriteLine("--------");
        Console.WriteLine(*p);
        // Dereferencing p and incrementing changes the value of a[0] ...
        *p += 1;
        Console.WriteLine(*p);
        *p += 1;
        Console.WriteLine(*p);
    }
}

Console.WriteLine("--------");
Console.WriteLine(a[0]);

/*
Output:
10
20
30
--------
10
11
12
--------
12
*/

示例5.如何使用指针复制字节数组

static unsafe void Copy(byte[] source, int sourceOffset, byte[] target,
    int targetOffset, int count)
{
    // If either array is not instantiated, you cannot complete the copy.
    if ((source == null) || (target == null))
    {
        throw new System.ArgumentException("source or target is null");
    }

    // If either offset, or the number of bytes to copy, is negative, you
    // cannot complete the copy.
    if ((sourceOffset < 0) || (targetOffset < 0) || (count < 0))
    {
        throw new System.ArgumentException("offset or bytes to copy is negative");
    }

    // If the number of bytes from the offset to the end of the array is
    // less than the number of bytes you want to copy, you cannot complete
    // the copy.
    if ((source.Length - sourceOffset < count) ||
        (target.Length - targetOffset < count))
    {
        throw new System.ArgumentException("offset to end of array is less than bytes to be copied");
    }

    // The following fixed statement pins the location of the source and
    // target objects in memory so that they will not be moved by garbage
    // collection.
    fixed (byte* pSource = source, pTarget = target)
    {
        // Copy the specified number of bytes from source to target.
        for (int i = 0; i < count; i++)
        {
            pTarget[targetOffset + i] = pSource[sourceOffset + i];
        }
    }
}

static void UnsafeCopyArrays()
{
    // Create two arrays of the same length.
    int length = 100;
    byte[] byteArray1 = new byte[length];
    byte[] byteArray2 = new byte[length];

    // Fill byteArray1 with 0 - 99.
    for (int i = 0; i < length; ++i)
    {
        byteArray1[i] = (byte)i;
    }

    // Display the first 10 elements in byteArray1.
    System.Console.WriteLine("The first 10 elements of the original are:");
    for (int i = 0; i < 10; ++i)
    {
        System.Console.Write(byteArray1[i] + " ");
    }
    System.Console.WriteLine("\n");

    // Copy the contents of byteArray1 to byteArray2.
    Copy(byteArray1, 0, byteArray2, 0, length);

    // Display the first 10 elements in the copy, byteArray2.
    System.Console.WriteLine("The first 10 elements of the copy are:");
    for (int i = 0; i < 10; ++i)
    {
        System.Console.Write(byteArray2[i] + " ");
    }
    System.Console.WriteLine("\n");

    // Copy the contents of the last 10 elements of byteArray1 to the
    // beginning of byteArray2.
    // The offset specifies where the copying begins in the source array.
    int offset = length - 10;
    Copy(byteArray1, offset, byteArray2, 0, length - offset);

    // Display the first 10 elements in the copy, byteArray2.
    System.Console.WriteLine("The first 10 elements of the copy are:");
    for (int i = 0; i < 10; ++i)
    {
        System.Console.Write(byteArray2[i] + " ");
    }
    System.Console.WriteLine("\n");
    /* Output:
        The first 10 elements of the original are:
        0 1 2 3 4 5 6 7 8 9

        The first 10 elements of the copy are:
        0 1 2 3 4 5 6 7 8 9

        The first 10 elements of the copy are:
        90 91 92 93 94 95 96 97 98 99
    */
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值