【问题标题】:read before write is undefined with malloced memory?写前读未定义分配内存?
【发布时间】:2012-02-09 22:36:34
【问题描述】:

根据this reddit comment thread,如果在写入内存之前尝试读取内存,则未定义。我指的是正常的堆内存,它已经成功malloced。

...请注意,这不是严格有效的 C:允许编译器/运行时系统使用所谓的陷阱表示来初始化未初始化的内存,这会导致访问时出现未定义的行为。

我觉得这很难相信。有标准报价吗?

当然,我知道无法保证内存已清零。此未初始化内存中的值本质上是伪随机或任意的。但我真的不敢相信标准会将此称为未定义的行为(从某种意义上说,它可能会出现段错误,或删除所有文件,或其他任何东西)。那里的其他 reddit 线程没有进一步说明这个问题。

【问题讨论】:

  • 呃,你认为未定义的行为是什么意思? (是的,在初始化之前使用分配的内存会产生未定义的行为)
  • @Brian 我假设他在问整个行为(即这个段错误)是否未定义,或者只是读取结果的值。
  • @Owen,没错,我已经相应地更新了问题。
  • 你不能有未定义的子集。这意味着行为未定义。会出现段错误吗?谁知道;行为是未定义。这并不意味着它会出现段错误或删除您的文件,事实上,它可能不会做任何坏事......但你不能依赖它,因为没有什么可以说它不会' t.
  • 内存是不确定的,这在非规范附件 J(可移植性)中被列为未定义行为,但我找不到任何规范明确说明访问不确定内存是 UB

标签: c undefined-behavior language-lawyer initialization


【解决方案1】:

如果通过char* 访问,则已定义。但除此之外,这是未定义的行为。

(C99, 7.20.3.3) "malloc 函数为大小由 size 指定且值不确定的对象分配空间。"

关于不确定值:

(C99, 3.17.2p1) "不确定值:未指定值或陷阱表示"

关于通过非字符类型读取的陷阱表示是未定义的行为:

(C99, 6.2.6.1p5) “某些对象表示不需要表示对象类型的值。如果对象的存储值具有这样的表示并且由不具有字符类型的左值表达式读取,行为未定义。[...] 这种表示称为陷阱表示。”

【讨论】:

  • 添加一个标准引用,说明访问陷阱表示会导致未定义的行为,并且您将拥有完整的链。 (但是,截至此评论,您仍然缺少那个。)
  • @BrooksMoses,这是个大问题。 “陷阱表示”是什么意思?
  • @ouah,所以如果使用char*,它是明确定义的(但任意/不确定)?
  • @AaronMcDaid 如果你取消引用 char * 是:标准明确表明字符类型没有陷阱表示。
  • 是否还有其他类型的明确定义?肯定是像int 这样简单的东西?有没有一个很好的例子来说明它没有定义良好的类型?也许有一些位集不代表有效的double,或者类似的东西?
【解决方案2】:

它合理地必须是未定义的。否则,在 Valgrind 之类的东西下运行的 C 程序的必要行为,它诊断未初始化内存的读取并在发生错误时抛出适当的错误,在标准下将是非法的。

阅读标准,关键问题是 malloc 内存的值是“未指定值”(必须是一些可读值)还是“不确定值”(可能包含陷阱表示;参见定义 3.17.2 .)

根据其他答案中引用的 7.20.3.3,malloc 返回一个包含不确定值的内存块,因此可能包含陷阱表示。陷阱表示的相关讨论是 6.2.6.1,第 5 部分:

某些对象表示不需要表示对象类型的值。如果对象的存储值具有这样的表示形式并且由不具有字符类型的左值表达式读取,则行为未定义。 ...这种表示称为陷阱表示

那么,就这样吧。基本上,允许 C 实现检测(即“陷阱”)对不确定值的引用,并以它选择的方式处理该错误,包括以未定义的方式。

【讨论】:

  • 为什么像 Valgrind 这样的工具必须表现得像完全符合 C 的实现?我建议在许多情况下,将它们配置为捕获各种被标准视为完全定义但程序员知道除非偶然发生否则永远不会发生的事情会更有用。
【解决方案3】:

ISO/IEC 9899:1999, 7.20.3.3 malloc函数:

malloc 函数为大小由 size 指定的对象分配空间, 其值是不确定的。

6.2.6.1 类型的表示,§5:

某些对象表示不需要表示对象类型的值。如果存储 对象的值具有这样的表示,并由左值表达式读取 没有字符类型,行为未定义。

脚注 41 使它更加明确(至少对于自动变量):

因此,可以将自动变量初始化为陷阱表示,而不会导致未定义的行为,但只有在其中存储了适当的值之后才能使用该变量的值。

【讨论】:

  • 我对“不确定值”没有任何问题。这在答案中很清楚。问题是行为是否完全未定义(段错误等)。
  • 所以通过char* 可以吗?你能举一个这样的物体的例子吗?我试图记住doubles 是如何表示的——也许并非所有位配置都映射到有效的double。这是这里提到的类型吗?
  • NaN(“不是一个数字”)值是 double 标准表示的一部分,但它们仍然是“有效的”。
  • 我刚刚注意到我说的是“不确定的价值”,而我应该说的是“未指定的价值”。对我来说,它们似乎都是同一个意思,但在 C 标准语言中它们似乎有不同的含义!
  • @AaronMcDaid:未定义!= 段错误。例如,表达式a++ + a++ 会调用未定义的行为,但您将很难找到一个实际上会在此发生段错误的平台(如果您这样做,eek)。尽管公平地说,我们正在在这里讨论trap表示。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-09-10
  • 2012-02-22
  • 2017-01-27
  • 2012-07-08
  • 2012-05-29
  • 2018-01-10
  • 1970-01-01
相关资源
最近更新 更多