隐藏的不确定内存读取 [英] Hidden read of indeterminate memory

查看:57
本文介绍了隐藏的不确定内存读取的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

[附件J.2未定义的行为]

- 使用malloc函数分配的对象的值

(7.20.3.3)。

- 使用超出旧对象大小的realloc

函数分配的新对象中的任何字节值(7.20.3.4)。


这样的东西(包含和检查省略):


p = malloc(sizeof(* p)* 5);

p [0] = 1; p [1] = 1; p [2] = 1;


a = p [4];


显然未定义,因为p [4]未初始化。但是对于隐藏而言,发生了什么?b $ b重新分配内存时读取权限:


p = malloc(sizeof(* p)* 5);

p [0] = 1; p [1] = 1; p [2] = 1;


p = realloc(p,sizeof(* p)* 10);


其中p [3]并且p [4]被移动到新的存储位置,当然它是一个

的新位置,当然?这同样适用于memmove和memcpy。


我的假设是:


- 字节的值不是使用的。就上述

定义的未定义行为而言。


- 库函数在字节数组上工作,这是

总是很好地为任何对象类型定义,即使对于不确定的值。

OTOH,上面定义中没有例外:任何值的价值
字节[。 ..]使用。


- 考虑到它,同样适用于结构内部的填充

只能通过访问结构来初始化作为
字节的数组。 OTOH,可能有更深层次的理由存在

calloc()......


你的意思是什么?

Holger

解决方案

文章< d7 ********************** ****@posting.google.com>

Holger Hasselbach< ha ******** @ galad.com>写道:

[一些snippage和垂直压缩]

这样的东西(包含和检查省略):

p = malloc(sizeof(* p)* 5);
p [0] = 1; p [1] = 1; p [2] = 1;
a = p [4];

显然未定义,因为p [4]未初始化。但是对于隐藏的是什么呢?重新分配内存时的读取权限:

p = malloc(sizeof(* p)* 5);
p [0] = 1; p [1] = 1; p [2] = 1;
p = realloc(p,sizeof(* p)* 10);

其中p [3]和p [4]被移动到新的记忆位置,当它是一个新的位置,当然?这同样适用于memmove和memcpy。




C标准在某种程度上是两个思想。关于

未初始化内存中的位模式,包括来自malloc()的内存。 (未初始化的

自动对象有同样的问题,以及 - 在你初始化的struct对象中提到你的b $ b) - 阅读

它们产生未定义的行为,但memcpy()必须是

才能复制它们。


这种困境的解决方案在于unsigned的属性

char"。 unsigned char中没有陷阱表示,

是unsigned char的字节 - 即使这超过了

8位长 - 覆盖任何子对象中的所有位。这意味着,即使标准没有完全说明(并且我还没有检查确定它是否为
),即使是一个未初始化的对象,也是b $ b。 />
未定义 - 行为值只需将对象分解为其组件即可以定义行为

方式检查

" unsigned char"字节。每个这样的字节中的位模式永远不会产生未定义的行为。


然后,只要mempcy()和朋友 - 包括realloc() -

处理这些未初始化的位置好像通过使用unsigned

char来复制位模式,不会发生任何未定义的行为。

当然,没有什么可以说对象的'未定义的值

在这些副本中保持不变。在这个特殊的意义上,他们

是Schroedinger的Cats of values:如果他们在memcpy()中保持不变,那么找到

的唯一方法就是检查他们,

并检查它们会给出未定义的行为,这样你就不会再知道一个未经检查的副本是否会改变它们。

(在这里我们认为没有量子物理涉及C

编程......!:-))

-

In-Real-Life:风河系统Chris Torek

美国犹他州盐湖城(40°39.22''N,111°50.29''W)+1 801 277 2603

电子邮件:忘了它 http:// web .torek.net / torek / index.html

由于垃圾邮件发送者,阅读电子邮件就像在垃圾中搜索食物一样。


< blockquote>

" Holger Hasselbach" <公顷******** @ galad.com>在消息中写道

库函数在字节数组上工作,即使对于不确定的值,它总是为任何对象类型定义良好。
OTOH,没有例外在上面的定义中:使用任何
字节的值[...]。



这就是答案。如果你在C中编写memcpy(),那么必须使用

来转换为unsigned char数组以避免陷阱表示。


当然,通常memcpy()不会在C中实现,并且在没有

问题的情况下,一次移动内存的数量可能超过一个字节。
br />


Chris Torek写道:


在文章< d7 *********** ***************@posting.google.com>
Holger Hasselbach< ha ******** @ galad.com>写道:
[一些snippage和垂直压缩]

这样的东西(包括和检查省略):

p = malloc(sizeof(* p)* 5 );
p [0] = 1; p [1] = 1; p [2] = 1;
a = p [4];

显然未定义,因为p [4]未初始化。但是对于隐藏的是什么呢?重新分配内存时的读取权限:

p = malloc(sizeof(* p)* 5);
p [0] = 1; p [1] = 1; p [2] = 1;
p = realloc(p,sizeof(* p)* 10);

其中p [3]和p [4]被移动到新的记忆位置,当它是一个新的位置,当然?这同样适用于memmove和memcpy。



C标准在某种程度上是两个思想。关于未初始化内存中的位模式,包括来自malloc()的内存。 (未初始化的
自动对象具有相同的问题,以及 - 正如您提到的 - 在初始化的struct对象中填充。)读取它们会产生未定义的行为,但memcpy()必须是
能够复制它们。

这种困境的解决方案在于unsigned
char的属性。 unsigned char中没有陷阱表示,并且unsigned char的字节是 - 即使这超过8位长 - 覆盖任何位中的所有位子对象。这意味着,即使标准没有完全说明(并且我没有检查它是否确实如此),即使是未初始化的对象的未定义行为值也可以仅通过将对象分解为其组件来以定义行为的方式进行检查
unsigned char字节。每个这样的字节中的位模式永远不会产生未定义的行为。




我不认为陷阱与它有任何关系。


如果标准委员会在你试图检查未初始化的物体时并不关心会发生什么,那么这就是所有那些尝试检查未初始化的对象需要调用未定义的行为



涉及其他更为常见的
类型的未定义行为的机制,是不需要。


N869

6.7.8初始化

[#10]如果具有自动存储持续时间的对象是

没有明确初始化,它的值是不确定的。


new.c是未定义的行为,对吧?


/ * BEGIN new.c * /


#include< stdio.h>


int main(无效)

$

unsigned char byte;


printf("%u \ n",(unsi) gned)byte);

返回0;

}


/ * END new.c * /
< br $> b $ b -

pete


[Annex J.2 Undefined behavior]
- The value of the object allocated by the malloc function is used
(7.20.3.3).
- The value of any bytes in a new object allocated by the realloc
function beyond the size of the old object are used (7.20.3.4).

Something like this (include and checkings omitted):

p = malloc(sizeof(*p) * 5);
p[0] = 1; p[1] = 1; p[2] = 1;

a = p[4];

is obviously undefined, because p[4] was not initialised. But what
happens for the "hidden" read access when realloc''ing the memory:

p = malloc(sizeof(*p) * 5);
p[0] = 1; p[1] = 1; p[2] = 1;

p = realloc(p, sizeof(*p) * 10);

where p[3] and p[4] are moved to the new memory location, when it is a
new location, of course? The same applies for memmove and memcpy.

My assumptions are:

- The values of the bytes are not "used" in the sense of the above
definition for undefined behavior.

- The library functions do their work on arrays of bytes, which is
always well defined for any object type even for indeterminate values.
OTOH, there is no exception in the above definition: "value of any
bytes [...] are used".

- Thinking of it, the same would apply for the padding inside structs
that could only be initialised by accessing the struct as an array of
bytes. OTOH, there could be a deeper reason for the existence of
calloc()...

What do you mean?
Holger

解决方案

In article <d7**************************@posting.google.com >
Holger Hasselbach <ha********@galad.com> writes:
[some snippage and vertical compression]

Something like this (include and checkings omitted):

p = malloc(sizeof(*p) * 5);
p[0] = 1; p[1] = 1; p[2] = 1;
a = p[4];

is obviously undefined, because p[4] was not initialised. But what
happens for the "hidden" read access when realloc''ing the memory:

p = malloc(sizeof(*p) * 5);
p[0] = 1; p[1] = 1; p[2] = 1;
p = realloc(p, sizeof(*p) * 10);

where p[3] and p[4] are moved to the new memory location, when it is a
new location, of course? The same applies for memmove and memcpy.



The C standard is, in a way, "of two minds" about bit-patterns in
uninitialized memory, including memory from malloc(). (Uninitialized
automatic objects have the same problem, along with -- as you
mention -- padding inside initialized struct objects.) Reading
them produces undefined behavior, yet memcpy() must necessarily be
able to copy them.

The solution to this dilemma lies in the properties of "unsigned
char". There are no trap representations in "unsigned char", and
the bytes that "unsigned char"s are -- even if this is more than
8 bits long -- cover all the bits in any sub-object. This implies,
even if the standard does not say outright (and I have not checked
to see whether it does), that even an uninitialized object''s
undefined-behavior values can be inspected in a defined-behavior
manner simply by breaking the object down into its component
"unsigned char" bytes. The bit patterns in each such byte never
produce undefined behavior.

Then, as long as mempcy() and friends -- including realloc() --
deal with these unintialized locations "as if" by using unsigned
char to copy the bit patterns, no undefined behavior occurs. Of
course, nothing can be said about the objects'' undefined values
staying the same across such copies. In this particular sense they
are sort of Schroedinger''s Cats of values: the only way to find
out if they are unchanged across a memcpy() is to inspect them,
and inspecting them gives undefined behavior, so that you no longer
know if an uninspected-copy might have changed them after all.

(And here we thought there was no quantum physics involved in C
programming...! :-) )
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (40°39.22''N, 111°50.29''W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.



"Holger Hasselbach" <ha********@galad.com> wrote in message

The library functions do their work on arrays of bytes, which is
always well defined for any object type even for indeterminate values.
OTOH, there is no exception in the above definition: "value of any
bytes [...] are used".


This is the answer. If you are writing memcpy() in C, then it is necessary
to cast to an array of unsigned char to avoid trap representations.

Of course, normally memcpy() won''t be implemented in C, and it will be
possible to move memory in greater quanties than one byte at a time without
problems.


Chris Torek wrote:


In article <d7**************************@posting.google.com >
Holger Hasselbach <ha********@galad.com> writes:
[some snippage and vertical compression]

Something like this (include and checkings omitted):

p = malloc(sizeof(*p) * 5);
p[0] = 1; p[1] = 1; p[2] = 1;
a = p[4];

is obviously undefined, because p[4] was not initialised. But what
happens for the "hidden" read access when realloc''ing the memory:

p = malloc(sizeof(*p) * 5);
p[0] = 1; p[1] = 1; p[2] = 1;
p = realloc(p, sizeof(*p) * 10);

where p[3] and p[4] are moved to the new memory location, when it is a
new location, of course? The same applies for memmove and memcpy.



The C standard is, in a way, "of two minds" about bit-patterns in
uninitialized memory, including memory from malloc(). (Uninitialized
automatic objects have the same problem, along with -- as you
mention -- padding inside initialized struct objects.) Reading
them produces undefined behavior, yet memcpy() must necessarily be
able to copy them.

The solution to this dilemma lies in the properties of "unsigned
char". There are no trap representations in "unsigned char", and
the bytes that "unsigned char"s are -- even if this is more than
8 bits long -- cover all the bits in any sub-object. This implies,
even if the standard does not say outright (and I have not checked
to see whether it does), that even an uninitialized object''s
undefined-behavior values can be inspected in a defined-behavior
manner simply by breaking the object down into its component
"unsigned char" bytes. The bit patterns in each such byte never
produce undefined behavior.



I don''t think traps have anything to with it.

If the standard committee doesn''t care about what happens
when you try to inspect uninitialized objects,
then that''s all that it takes to invoke undefined behavior
from trying to inspect an uninitialized object.
A mechanism involving other more familiar
types of undefined behavior, is not required.

N869
6.7.8 Initialization
[#10] If an object that has automatic storage duration is
not initialized explicitly, its value is indeterminate.

new.c is undefined behavior, right ?

/* BEGIN new.c */

#include <stdio.h>

int main(void)
{
unsigned char byte;

printf("%u\n", (unsigned)byte);
return 0;
}

/* END new.c */

--
pete


这篇关于隐藏的不确定内存读取的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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