【问题标题】:memcpy of overlapping buffers [duplicate]重叠缓冲区的memcpy [重复]
【发布时间】:2014-10-27 02:14:21
【问题描述】:

我在使用 Aztec 线性系统求解器库时遇到了奇怪的行为。使用 valgrind,我发现这个库在重叠缓冲区上做了一个memcpy。规范表明memcpy 在重叠缓冲区上的行为未定义。

事实证明,memcpy 在许多机器上的行为与使用 for 循环执行此操作的行为相同,因此您可以安全地从较高的源复制到较低的目标:

for(int i = 0; i < len; i ++)
  dest[i] = source[i];

但是在我们的大型集群上,memcpy 的重叠缓冲区具有不同的行为,这会导致问题。

现在我想知道库中重叠的memcpy 是正常的还是只是由我的代码中的另一个错误引起的。由于该库被广泛使用,我认为memcpy 问题应该更早被发现。另一方面,绝大多数memcpy 实现仍有可能表现得像 for 循环,因此没有人遇到过这个问题。

  • 谁能告诉我他在各种机器上重叠memcpy 的经历?
  • 我的计算机系统的哪个部分实际上提供了memcpy

我想指出,这个问题是关于各种实现的实际经验,而不是规范所说的。

【问题讨论】:

  • 请提供一个最小示例,以便我们重现您的问题并让您知道错误是在库中还是在您的代码中。
  • 我从来没有理解过 memcpy 的这个问题。当然,这只是一个比较来确定您是否需要从源缓冲区的顶部或底部进行复制?
  • @Martin James 很久很久以前,大量 使用memcpy() 的优先级使其非常精简。按照当时的标准,“一个比较”是膨胀软件,通常不需要 - 进一步它阻止了某些优化。它只是减慢了系统的速度。于是memmove()诞生了。
  • @chux orite,谢谢:)

标签: c++ c memcpy


【解决方案1】:

memcpy() 不支持重叠内存。这允许在缓冲区重叠时无法进行的优化。

然而,真正需要研究的并不多,因为 C 提供了一个确实支持重叠内存的替代方案:memmove()。它的用法与memcpy() 相同。如果区域可能重叠,您应该使用它,因为它说明了这种可能性。

【讨论】:

  • 规范对此很清楚。但我想知道库是否经常这样做memcpy 并且没有人遇到过这个问题,因为绝大多数实现的行为都类似于 for 循环,或者我是否只需要假设驱动库的代码中存在错误。
  • 如果您发现库进行了这样的调用,则可能是 1) 库本身存在错误,或 2) 库使用方式存在错误,导致不应重叠的内存发生。然而,在某些情况下它确实有效,但这并不意味着它不是一个错误。
【解决方案2】:

我过去对此进行了一些研究...在 Linux 上,直到最近,memcpy() 的实现与memmove() 的工作方式非常相似,重叠内存不是问题,根据我的经验,其他 UNIX 也是一样的。这并没有改变根据标准这是未定义行为的事实,您很幸运在某些平台上它有时可以工作 - 而memmove() 是标准支持的正确答案。

然而,在 2010 年,glibc 维护者推出了一个新的优化 memcpy(),它改变了 memcpy() 的行为,适用于某些 Intel 内核类型,其中 C 标准库被编译得更快,但不再像 @ 那样工作987654329@ [1]。 (我似乎还记得这是仅针对大于 80 字节的内存段触发的新代码)。有趣的是,这导致了诸如 Adob​​e 的 Flash 播放器的 Linux 版本 [2] 以及其他几个开源软件包(早在 2010 年 Fedora Linux 成为第一个在 glibc 中采用更改后的memcpy() 时)。

【讨论】:

  • 这正是我正在寻找的答案。因此,这种行为很可能已经在该库中存在多年,从未引起问题......
  • 完全正确。将旧代码移动到带有新更改的新服务器时,我被它咬住了。
  • 进一步阅读:“The memcpy vs. memmove saga”。由于 glibc 的变化,过去和今天仍然存在一些后果。
  • 谢谢@jwd - 精彩的阅读......这只是继续给予。 叹息
【解决方案3】:

memmove() 可用于此目的。 memcpy() [ man-page ] 的定义条件是“源”不应与目标重叠。

为了更好地理解,您可以通过尝试定义您的版本来尝试理解memcpy()memmove()。 [more info]

【讨论】:

    猜你喜欢
    • 2010-12-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-14
    • 2018-05-10
    • 1970-01-01
    • 1970-01-01
    • 2013-09-09
    相关资源
    最近更新 更多