mks*_*eve 13 c pointers language-lawyer
我有一段记忆,我正在"守卫",定义为
typedef unsigned char byte;
byte * guardArea;
size_t guardSize;
byte * guardArea = getGuardArea();
size_t guardSize = getGuardSize();
Run Code Online (Sandbox Code Playgroud)
为此目的可接受的实现是:
size_t glGuardSize = 1024; /* protect an area of 1kb */
byte * getGuardArea()
{
return malloc( glGuardSize );
}
size_t getGuardSize()
{
return glGuardSize;
}
Run Code Online (Sandbox Code Playgroud)
以下代码段可以为任何指针(来自不同的malloc,来自堆栈等)返回true吗?
if ( ptr >= guardArea && ptr < (guardArea + guardSize)) {
return true;
}
Run Code Online (Sandbox Code Playgroud)
该标准规定:
区域内的值将返回true.(当ptr是成员时,所有行为都正确.)
指针将是不同的(a == b只有它们是相同的).
所以我无法理解结果对于来自不同对象的任何指针的结果是否正确(因为它会破坏区域内其中一个指针的不同规则).
编辑:
检测指针是否在区域内的能力非常重要,在某些时候编写代码
if ( isInMyAreaOfInterest( unknownPointer ) ) {
doMySpecialThing( unknownPointer );
} else {
doSomethingElse( unknownPointer );
}
Run Code Online (Sandbox Code Playgroud)
我认为语言需要通过使这样的结构简单明了来支持开发人员,并且我们对标准的解释是开发人员需要转换为int.由于不同对象的指针比较的"未定义行为".
我希望能清楚地知道为什么我不能做我想做的事情(我的片段),因为我发现的所有帖子都说标准声称未定义的行为,没有任何解释,或者为什么标准更好的例子比我希望它如何工作.
目前,我们有一条规则,我们既不理解规则存在的原因,也不了解规则是否有助于我们
示例帖子:
Ray*_*hen 35
尽管指针没有指向区域,但分配仍然可以生成满足条件的指针.例如,这将发生在受保护模式的80286上,Windows 3.x在标准模式和OS/2 1.x中使用该模式.
在这个系统中,指针是32位值,分为两个16位部分,传统上写为XXXX:YYYY
.第一个16位部分(XXXX
)是"选择器",它选择64KB的存储区.第二个16位部分(YYYY
)是"偏移",它在该64KB存储区中选择一个字节.(这比这更复杂,但是为了讨论的目的,我们就把它留在那里.)
大于64KB的内存块被分解为64KB块.要从一个块移动到下一个块,请将8添加到选择器.例如,之后的字节0101:FFFF
是0109:0000
.
但是为什么要添加8来移动到下一个选择器呢?为什么不只是增加选择器?因为选择器的底部三位用于其他事情.
特别是,选择器的底部位用于选择选择器表.(让我们忽略位1和2,因为它们与讨论无关.为方便起见,假设它们始终为零.)
有两个选择器表,全局选择器表(用于跨所有进程共享的内存)和本地选择器表(用于单个进程的私有内存).因此,可用于进程的私有内存的选择是0001
,0009
,0011
,0019
,等.同时,可为全球内存的选择是0008
,0010
,0018
,0020
,等(选择0000
保留.)
好的,现在我们可以设置我们的反例.假设guardArea = 0101:0000
和guardSize = 0x00020000
.这意味着守卫地址是0101:0000
通过0101:FFFF
和0109:0000
通过0109:FFFF
.而且,guardArea + guardSize = 0111:0000
.
同时,假设有一些碰巧分配的全局内存0108:0000
.这是全局内存分配,因为选择器是偶数.
观察到全局内存分配不是受保护区域的一部分,但其指针值确实满足数值不等式0101:0000 <= 0108:0000 < 0111:0000
.
Bonus chatter:即使在具有平坦内存模型的CPU架构上,测试也会失败.现代编译器利用未定义的行为并相应地进行优化.如果他们看到指针之间的关系比较,则允许他们假设指针指向同一个数组(或者超过该数组的最后一个元素).具体而言,可以合法相比的唯一指针guardArea
是形式的那些guardArea
,guardArea+1
,guardArea+2
,..., guardArea + guardSize
.对于所有这些指针,条件ptr >= guardArea
为真,因此可以优化,减少您的测试
if (ptr < (guardArea + guardSize))
Run Code Online (Sandbox Code Playgroud)
现在将满足数字小于的指针guardArea
.
故事的道德:这段代码不安全,甚至在平面架构上也是如此.
但并没有丢失:指向整数的转换是实现定义的,这意味着您的实现必须记录它的工作原理.如果您的实现将指针到整数的转换定义为生成指针的数值,并且您知道自己处于扁平体系结构中,那么您可以做的是比较整数而不是指针.整数比较的约束方式与指针比较的方式不同.
if ((uintptr_t)ptr >= (uintptr_t)guardArea &&
(uintptr_t)ptr < (uintptr_t)guardArea + (uintptr_t)guardSize)
Run Code Online (Sandbox Code Playgroud)