以下代码对于指向不同事物的指针是否正确? [英] Can the following code be true for pointers to different things

查看:77
本文介绍了以下代码对于指向不同事物的指针是否正确?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在守护"着一段记忆,定义为

I have a piece of memory I am "guarding", defined by

typedef unsigned char byte;

byte * guardArea;
size_t guardSize;

byte * guardArea = getGuardArea();
size_t guardSize = getGuardSize();

为此可以接受的实现方式是:

An acceptable implementation for the sake of this would be:

size_t glGuardSize = 1024; /* protect an area of 1kb */
byte * getGuardArea()
{
     return malloc( glGuardSize );
}
size_t getGuardSize()
{
     return glGuardSize;
}

以下代码片段是否可以对任何指针(来自不同的malloc,来自堆栈等)返回true?

Can the following snippet return true for any pointer (from a different malloc, from the stack etc)?

if ( ptr >= guardArea && ptr < (guardArea + guardSize)) {
     return true;
}

标准规定:

    区域内的
  • 值将返回true. (当ptr成为成员时,所有行为均正确.)

  • values within the area will return true. (When ptr was a member, all acts correctly.)

指针将是不同的(仅当它们相同时,a == b).

pointers will be distinct (a == b only if they are the same).

因此,我无法理解来自不同对象的任何指针的结果如何正确(因为这会破坏该区域内指针之一的独特规则).

So I can't understand how the result could be true for any pointer from a different object (as it would break the distinct rule for one of the pointers within the area).

检测指针是否在区域内的能力非常重要,在某些时候编写了代码

The ability to detect whether a pointer is within a region is really important, at some point code is written

if (  isInMyAreaOfInterest( unknownPointer ) ) {
    doMySpecialThing( unknownPointer );
} else {
    doSomethingElse( unknownPointer );
}

我认为该语言需要通过使这种构造简单明了来支持开发人员,而我们对标准的解释是开发人员需要转换为int.由于不同对象的指针比较具有未定义的行为".

I think the language needs to support the developer by making such constructs simple and obvious, and our interpretation of the standard, is that the developer needs to cast to int. Due to the "undefined behavior" of pointer comparisons of distinct objects.

我一直希望能弄清楚为什么我不能做自己想做的事情(我的摘录),因为我发现所有关于SO的帖子都说该标准声明了未定义的行为,没有任何解释,也没有说明为什么这样做的例子.标准比我希望它的工作方式更好.

I was hoping for some clarity of why I can't do what I would like (my snippet), as all the posts on SO I found say that the standard claims undefined behavior, without any explanation, or examples of why the standard is better than how I would like it to work.

目前,我们有一条规则,我们既不了解该规则为什么存在,也不在质疑该规则是否对我们有帮助

At the moment, we have a rule, we are neither understanding why the rule exists, or questioning if the rule is helping us

示例帖子:

SO:检查指针是否在已分配区域中

SO:C比较指针

推荐答案

尽管指针未指向该区域,但分配仍可能生成满足条件的指针.例如,这会在保护模式下的80286上发生,Windows 3.x在标准模式下和OS/2 1.x上都会使用它.

It is still possible for an allocation to generate a pointer that satisfies the condition despite the pointer not pointing into the region. This will happen, for example, on an 80286 in protected mode, which is used by Windows 3.x in Standard mode and OS/2 1.x.

在此系统中,指针是32位值,分为两个16位部分,通常写为XXXX:YYYY.第一个16位部分(XXXX)是选择器",它选择64KB的存储体.第二个16位部分(YYYY)是偏移量",它在该64KB存储区中选择一个字节. (这比这要复杂得多,但是为了讨论的目的,让我们把它留在那儿.)

In this system, pointers are 32-bit values, split into two 16-bit parts, traditionally written as XXXX:YYYY. The first 16-bit part (XXXX) is the "selector", which chooses a bank of 64KB. The second 16-bit part (YYYY) is the "offset", which chooses a byte within that 64KB bank. (It's more complicated than this, but let's just leave it at that for the purpose of this discussion.)

大于64KB的内存块被分成64KB的块.要从一个大块移到另一个大块,请在选择器中添加8.例如,0101:FFFF之后的字节是0109:0000.

Memory blocks larger than 64KB are broken up into 64KB chunks. To move from one chunk to the next, you add 8 to the selector. For example, the byte after 0101:FFFF is 0109:0000.

但是为什么要加8来移动到下一个选择器?为什么不只是增加选择器呢?因为选择器的后三位用于其他用途.

But why do you add 8 to move to the next selector? Why not just increment the selector? Because the bottom three bits of the selector are used for other things.

特别是,选择器的低位用于选择选择器表. (由于它们与讨论无关,所以忽略它们的位1和2.为方便起见,它们始终为零.)

In particular, the bottom bit of the selector is used to choose the selector table. (Let's ignore bits 1 and 2 since they are not relevant to the discussion. Assume for convenience that they are always zero.)

有两个选择器表,全局选择器表(用于所有进程共享的内存)和本地选择器表(用于单个进程专用的内存).因此,可用于进程专用存储器的选择器是0001000900110019等.同时,可用于全局存储器的选择器是0008001000180020等.(选择器0000保留.)

There are two selector tables, the Global Selector Table (for memory shared across all processes) and the Local Selector Table (for memory private to a single process). Therefore, the selectors available for process private memory are 0001, 0009, 0011, 0019, etc. Meanwhile, the selectors available for global memory are 0008, 0010, 0018, 0020, etc. (Selector 0000 is reserved.)

好的,现在我们可以建立我们的反例了.假设guardArea = 0101:0000guardSize = 0x00020000.这意味着受保护的地址是0101:00000101:FFFF0109:00000109:FFFF.此外,guardArea + guardSize = 0111:0000.

Okay, now we can set up our counter-example. Suppose guardArea = 0101:0000 and guardSize = 0x00020000. This means that the guarded addresses are 0101:0000 through 0101:FFFF and 0109:0000 through 0109:FFFF. Furthermore, guardArea + guardSize = 0111:0000.

同时,假设在0108:0000恰好分配了一些全局内存.这是全局内存分配,因为选择器是偶数.

Meanwhile, suppose there is some global memory that happens to be allocated at 0108:0000. This is a global memory allocation because the selector is an even number.

观察到全局内存分配不是受保护区域的一部分,但是其指针值确实满足数字不等式0101:0000 <= 0108:0000 < 0111:0000.

Observe that the global memory allocation is not part of the guarded region, but its pointer value does satisfy the numeric inequality 0101:0000 <= 0108:0000 < 0111:0000.

额外的奖励:即使在具有扁平内存模型的CPU体系结构上,测试也可能失败.现代的编译器利用未定义的行为并进行相应的优化.如果他们看到了指针之间的关系比较,则可以假定指针指向同一数组(或指向该数组最后一个元素的指针).具体来说,可以合法地与guardArea进行比较的唯一指针是格式为guardAreaguardArea+1guardArea+2,...,guardArea + guardSize的那些指针.对于所有这些指针,条件ptr >= guardArea为真,因此可以进行优化,从而将测试减少到

Bonus chatter: Even on CPU architectures with a flat memory model, the test can fail. Modern compilers take advantage of undefined behavior and optimize accordingly. If they see a relational comparison between pointers, they are permitted to assume that the pointers point into the same array (or one past the last element of that array). Specifically, the only pointers that can legally be compared with guardArea are the ones of the form guardArea, guardArea+1, guardArea+2, ..., guardArea + guardSize. For all of these pointers, the condition ptr >= guardArea is true and can therefore be optimized out, reducing your test to

if (ptr < (guardArea + guardSize))

现在对于数值小于guardArea的指针将得到满足.

which will now be satisfied for pointers that are numerically less than guardArea.

故事的寓意:此代码并不安全,即使在平面架构上也是如此.

Moral of the story: This code is not safe, not even on flat architectures.

但是一切都不会丢失:指针到整数的转换是实现定义的,这意味着您的实现必须记录其工作方式.如果您的实现将指针到整数的转换定义为产生指针的数值,并且您知道自己在平面体系结构上,那么您可以做的是比较 integers 而不是指针.整数比较不受指针比较的限制.

But all is not lost: The pointer-to-integer conversion is implementation-defined, which means that your implementation must document how it works. If your implementation defines the pointer-to-integer conversion as producing the numeric value of the pointer, and you know that you are on a flat architecture, then what you can do is compare integers rather than pointers. Integer comparisons are not constrained in the same way that pointer comparisons are.

if ((uintptr_t)ptr >= (uintptr_t)guardArea &&
    (uintptr_t)ptr < (uintptr_t)guardArea + (uintptr_t)guardSize)

这篇关于以下代码对于指向不同事物的指针是否正确?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆