【问题标题】:How is it possible to have a buffer overrun on one platform but not another?如何在一个平台上出现缓冲区溢出而不在另一个平台上溢出?
【发布时间】:2011-07-02 02:45:33
【问题描述】:

由于情况模糊,我很犹豫要不要问这个问题,但我想了解这怎么可能。我有一个使用 Visual Studio 2008 开发的 C++ 应用程序。当我在 Windows 7 64 位(或 Vista 32 位)上编译该应用程序时,该应用程序运行良好。当我在 32 位 Windows XP SP3 上编译应用程序时,我收到缓冲区溢出警告并且进程终止。这是使用与 Visual Studio 2008 C++ 编译器相同的版本。我在 XP 上收到缓冲区溢出,但在其他 Windows 平台上却没有,这是怎么回事?

【问题讨论】:

  • 当涉及到未定义的行为(例如鼻恶魔)时,一切都可能发生。当然,您可能会好奇为什么会发生这种情况,但您不应该感到惊讶,这就是 UB 的本质 :)
  • 可能是整数或指针大小的问题导致未定义的行为。
  • @André:XP 和 Vista 32 位之间没有整数/指针大小差异。
  • 何时编译运行
  • @DeadMG 在我的例子中,我在运行之前在给定平台上编译。

标签: c++ visual-studio buffer-overrun


【解决方案1】:

编写代码,以免缓冲区溢出,并且在任何平台上都不会出现此问题。即,确保检查您正在访问的缓冲区的边界,以确保您没有尝试在正确的边界之外进行读/写。

【讨论】:

  • @Andre:是的,谁会尝试边界检查来防止缓冲区溢出。
  • 我:“我这样做的时候很痛,医生。”医生:“好吧,那就不要那样做了。”我使用的直接分配的缓冲区非常少,而是更喜欢依赖 STL 对象。在这个特定实例中进行调试表明我在地图销毁期间收到了缓冲区溢出通知,所以这让我有点失望。
  • 如果您使用标准容器,请设置边界检查预处理器指令(我不记得它是什么)。它将导致抛出异常,因此您可以更轻松地找到错误。你的地图是什么?
  • 抱歉,我同意安德烈的观点。这没有回答问题。
  • @Marlon:调试既是艺术,又是科学。如果您忽略了提供给您的帮助您更轻松的工具(在这种情况下,边界检查),您将两者都拿走并让它只是运气。
【解决方案2】:

运气,宇宙的基本不确定性,或者(比以前更可能)在 XP 和 7 之间在 msvcrt.dll 中更改的实现细节。

底线是您的应用程序中存在错误,您应该修复它。

【讨论】:

  • -1:很抱歉,但这根本没有帮助。 OP 已经知道他有一个错误。他正在寻找如何找到它的提示。
  • @André:不,他准确而清晰地询问了行为上的差异(如果您不相信我,请再次阅读问题)。 OP 似乎足够聪明和有文化,可以用错误消息和更多细节来问像你这样的问题。您的建议是我回答“使用调试器查找溢出的位置”。
  • +1 发现 - OP 的时间最好花在发现和修复错误上,而不是无益地猜测为什么未定义的行为可能会在平台之间发生变化。
  • @rubenvb 由于我使用相同版本的 Visual Studio 构建,我的印象是我将使用相同版本的 msvcrt.dll,但我想我可能是不是。
  • @JimEvans:crt 有几个版本:msvcrt.dll、msvcrt71.dll、msvcrt80.dll、msvcrt90.dll、msvcrt100.dll。带有版本号的那些与特定的 VS 版本相关联。虽然第一个存在于标准 Windows 安装中(因此没有安装任何 Visual C++ 可再发行包),并且至少与 MinGW 一起用作默认值。我不知道编号和默认值有何不同,但我假设几个函数只是被转发到 msvcrt.dll。或者某种低级内存管理类型的东西发生了变化,这会产生宏观后果。
【解决方案3】:

在这两种情况下,您可能都有缓冲区溢出,首先它没有被检测到并且(显然)没有造成任何伤害。在第二个它被检测到。 (如果它在动态分配的内存上,您必须知道分配器分配的内存通常比要求的多,因此一个合理的解释是,在第一种情况下,溢出停留在该区域中,而在第二种情况下则不会)。

【讨论】:

    【解决方案4】:

    数据类型的大小可能会从一个编译器更改为另一个(感谢@AndreyT)。使用像sizeof(4) 这样的硬编码数字来表示代码中数据类型的大小,可能会在您的应用程序中弹出一个错误。您应该改用sizeof(int) 或您感兴趣的任何类型。

    【讨论】:

    • 数据类型的大小完全不依赖于操作系统架构。数据类型的大小由编译器决定,并且仅由编译器决定。当涉及到内置数据类型时,程序总是被编译器 100% 地与操作系统/架构隔离。我假设 OP 每次都由同一个编译器编译同一个项目。在这种情况下,数据类型大小不会有任何差异。
    • @AndreyT:“根本不依赖操作系统架构”有点强,但我觉得我误解了你的观点。 MS 规定了 x86 和 x86_64 上 Windows 中几种数据类型的大小(不同!),并且相同类型在具有相同架构的 linux 操作系统上具有不同大小。你到底是什么意思?
    • @rubenvb:编译器的数据类型与操作系统的“指令”完全无关。 OS 甚至没有数据类型的概念,或者更准确地说,OS 级别的数据类型概念与语言级别的概念没有任何关系。事实上,操作系统不能决定任何事情。语言和操作系统相遇的唯一情况是可以访问特定于操作系统的 API。但是操作系统特定的 API 通常不会以语言数据类型的形式表示。例如,Windows API 使用别名类型,如 INTLONG 等,而不是 intlong
    • 之所以这样做,是因为 Windows INT 通常与 C/C++ int 没有任何关系。我的“完全不依赖于操作系统架构”的说法是绝对准确的。我在语言规范中看不到任何暗示对操作系统有任何依赖性的内容。与底层硬件存在弱非绑定可选关系,但与操作系统无关。
    • 你的答案是一个很棒的编程技巧。如果编译器可以为您提供正确的大小,则不应使用硬编码大小。在这种特殊情况下,根据 MSDN,大小不会在 32 位和 64 位之间变化:msdn.microsoft.com/en-us/library/s3f49ktz(v=VS.90).aspx
    【解决方案5】:

    Windows-7 有一个称为容错堆的功能,正如它所说,它可以容忍一些错误的缓冲区访问。 Windows XP 没有这个功能(Vista,我不知道)。 Mark Russinovich 在 channel9.msdn.com 或 sysinternal.com 上有一段关于它的视频(忘了具体在哪里)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-11-11
      • 2013-11-06
      • 1970-01-01
      • 2015-12-16
      • 1970-01-01
      • 2014-12-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多