【问题标题】:Use of a deleted pointer address使用已删除的指针地址
【发布时间】:2017-04-20 01:41:10
【问题描述】:

(*) 据我所知,标准允许实现修改delete 运算符的操作数,但是大多数实现都不会这样做。

int* ptr = new int(0);
delete ptr; //delete is allowed to modify ptr, for example set it to 0
std::cout << ptr; // UB?

确认(*),ptr(以打印形式)的阅读是否明确?

如果delete确实修改了ptr,是否允许设置一个陷阱值,这会导致读取ptr UB?

【问题讨论】:

  • 注意delete的操作数可以是prvalue,根本不能“修改”。
  • @aschepler 它可能只修改左值参数。例如。我可以想象一个调试工具,它将释放的指针设置为一些已知的位模式,以帮助识别无效使用

标签: c++ undefined-behavior


【解决方案1】:

在 C++14 中,这是实现定义的行为,[basic.stc.dynamic.deallocation]/4:

如果标准库中释放函数的参数是一个非空指针值的指针,则释放函数将释放指针引用的存储空间,使所有引用释放存储空间的指针无效.

通过无效指针值的间接传递以及将无效指针值传递给释放函数具有未定义的行为。任何其他对无效指针值的使用都具有实现定义的行为

有一个脚注:

某些实现可能会定义复制无效指针值会导致系统生成的运行时错误。

自 C++11 以来,这种情况发生了变化,其中粗体文本表示“未定义的行为”并且没有脚注。


因此,为了回答您的问题,delete ptr; 被允许设置一个陷阱值,该值会导致std::cout &lt;&lt; ptr 出现运行时错误。编译器文档必须指定行为。这是比 UB 更窄的限制,在这种情况下,任何不稳定的行为都是允许的。

【讨论】:

  • 脚注很有趣,即使复制已删除的指针也可能导致运行时失败。
  • @PoweredByRice 即使做一个无用的语句ptr;(如(1+2);)也是I-DB。我想我曾经读过这曾经是 UB,因为过去的某些架构具有特殊的“指针寄存器”,并且使用无效指针加载其中一个可能已经触发异常,即使指针尚未取消引用。我不知道更多。
  • @chi 这就是理由;现在编译器文档必须记录目标上是否可能出现此类异常
  • @chi (1+2); 是什么?那 I-DB 怎么样?
  • @chi 在 C++ 中被称为 discarded-value 表达式 并且不进行左值到右值的转换(参见this answer 的最后一部分以了解相关信息讨论)
【解决方案2】:

在这个例子中,std::cout &lt;&lt; ptr 默认不是未定义的行为,因为ptr 根本没有被取消引用,所以它的值实际设置为什么并不重要。

默认情况下,STL 不为int* 指针定义operator&lt;&lt;。它定义:

  • operator&lt;&lt; 用于 (signed|unsignd) char*,用于打印以空字符结尾的文本。

  • void* 的通用 operator&lt;&lt;,它只打印指针设置到的内存地址本身,而不是被指向的数据。

由于int* 可以隐式转换为void*,因此调用std::cin &lt;&lt; ptr 实际上就是调用operator&lt;&lt;(std::cin, (void*)ptr),因此会按原样打印ptr 持有的内存地址。

仅当您的应用为int* 定义了自己的operator&lt;&lt; 并在指针被删除后尝试取消引用该指针时,该代码才会有未定义的行为。

【讨论】:

  • 指针是什么有点重要。例如,void* ptr; std::cout &lt;&lt; ptr; 是未定义的行为,因为评估了一个不确定的值。
  • operator&lt;&lt; 生成的 输出 将是未定义的,因为 ptr 未初始化,但 operator&lt;&lt;行为 本身对于 @987654340 @ 输入是明确定义的(按原样打印void* 持有的任何地址值)。
  • 首先,您可以放心地假设没有疯狂的运算符重载或宏,否则所有赌注都将失败。其次,当我们谈论未定义的行为时,未定义的是行为,而不是输出。第三,@aschepler 所说的。
  • aschepeler 的代码是 UB,参见 C++14 [dcl.init]/12。请注意,在 C++ 中,未初始化变量的使用与使用释放指针的部分不同,尽管在 C 中两者都包含在同一部分中
  • @RemyLebeau 两个字:Trap Representations。
猜你喜欢
  • 2011-10-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-29
  • 2020-12-30
  • 1970-01-01
  • 2016-07-13
  • 1970-01-01
相关资源
最近更新 更多