链接: 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
*/
}
190

被折叠的 条评论
为什么被折叠?



