【发布时间】:2014-07-13 22:56:52
【问题描述】:
从规格中我们知道
每个进程的虚拟地址空间被分割成多个分区。在 x86 32 位 Windows 上,0x00000000 - 0x0000FFFF(含)的分区称为 NULL-Pointer Assignment Partition。这个分区被留出来帮助程序员捕捉 NULL 指针赋值。如果您的进程中的线程尝试读取或写入此分区中的内存地址,则会引发访问冲突。
如果我们要创建一个具有 64*1024+1 字节字段的假设对象,例如
struct Foo {
byte field1;
byte field2;
...
byte field65536;
byte SomeUnexpectedData;
}* Bar = 0;
Bar->SomeUnexpectedData = 0;
所以这里我们使用了未初始化的空指针,那么环境如何避免它呢?我们不能创建大于 64K 的对象还是什么?
C# 测试
using System;
using System.Reflection;
using System.Reflection.Emit;
namespace BigObjTest
{
class Program
{
static void Main()
{
var type = GetObjType();
var obj = Activator.CreateInstance(type);
Console.WriteLine(obj);
}
private static Type GetObjType()
{
var typebuilder = GetTypeBuilder();
for (int i = 0; i <= 65535; i++)
{
typebuilder.DefineField("_" + ("b" + i), typeof (byte), FieldAttributes.Private);
}
return typebuilder.CreateType();
}
private static TypeBuilder GetTypeBuilder()
{
const string typeSignature = "MyDynamicType";
var an = new AssemblyName(typeSignature);
AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(an, AssemblyBuilderAccess.Run);
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("MainModule");
TypeBuilder tb = moduleBuilder.DefineType(typeSignature
, TypeAttributes.Public |
TypeAttributes.Class |
TypeAttributes.AutoClass |
TypeAttributes.AnsiClass |
TypeAttributes.BeforeFieldInit |
TypeAttributes.AutoLayout
, null);
return tb;
}
}
}
奇怪的是,如果对象大于 64K,CLR 会抛出异常,但如果写入 65534 而不是 65535,它会正常工作。所以我猜,在具有强类型系统的托管语言中这是不可能的。
【问题讨论】:
-
这种机制并非万无一失,只是为了在大多数情况下提供帮助。
-
不,它只是意味着指针值本身(地址)总是大于64K。
-
这也不是一个未初始化的指针。您显然将其初始化为
0。一个真正的 indeterminate 指针将万无一失,无论您的对象有多大/多小,NULL 指针分配分区的目的都是完全不可靠的。
标签: c# c++ windows pointers memory