gpt4 book ai didi

c - 矢量化 strlen 摆脱读取未分配的内存

转载 作者:太空狗 更新时间:2023-10-29 17:16:06 24 4
gpt4 key购买 nike

在研究 OSX 10.9.4 对 strlen 的实现时,我注意到它总是比较 16 字节的 block 并向前跳到下面的 16 字节,直到它遇到 '\0'。相关部分:

3de0:   48 83 c7 10             add    $0x10,%rdi
3de4: 66 0f ef c0 pxor %xmm0,%xmm0
3de8: 66 0f 74 07 pcmpeqb (%rdi),%xmm0
3dec: 66 0f d7 f0 pmovmskb %xmm0,%esi
3df0: 85 f6 test %esi,%esi
3df2: 74 ec je 3de0 <__platform_strlen+0x40>

0x10 是十六进制的 16 个字节。

当我看到它时,我在想:这 block 内存也可以不分配。如果我分配了一个 20 字节的 C 字符串并将其传递给 strlen,它将读取 36 字节的内存。为什么允许这样做?我开始寻找并找到了 How dangerous is it to access an array out of bounds?

这证实了这绝对不是一件好事,例如,未分配的内存可能未映射。然而,必须有一些东西使它起作用。我的一些假设:

  • OSX 不仅保证其分配是 16 字节对齐的,而且还保证分配的“量子”是 16 字节的 block 。换句话说,分配 5 个字节实际上将分配 16 个字节。分配 20 个字节实际上将分配 32 个字节。
  • 在编写 asm 时读取数组末尾本身并无害处,因为这不是未定义的行为,只要它在边界内(在页面内?)。

真正的原因是什么?

编辑:刚刚找到Why I'm getting read and write permission on unallocated memory? ,这似乎表明我的第一个猜测是正确的。

编辑 2:愚蠢的是,我忘记了尽管 Apple 似乎已经删除了大部分 asm 实现的源代码(Where did OSX's x86-64 assembly libc routines go?),但它留下了 strlen:http://www.opensource.apple.com/source/Libc/Libc-997.90.3/x86_64/string/strlen.s

在评论中我们发现:

//  returns the length of the string s (i.e. the distance in bytes from
// s to the first NUL byte following s). We look for NUL bytes using
// pcmpeqb on 16-byte aligned blocks. Although this may read past the
// end of the string, because all access is aligned, it will never
// read past the end of the string across a page boundary, or even
// accross a cacheline.

编辑:老实说,我认为所有回答者都应该得到一个可接受的答案,并且基本上都包含理解问题所需的信息。所以我去寻找声誉最低的人的答案。

最佳答案

我是相关例程的作者。

正如其他一些人所说,关键是读取全部对齐。虽然读取数组边界之外的内容在 C 中是未定义的行为,但我们不是在编写 C;除了 C 抽象机定义的内容之外,我们还了解很多 x86 架构的细节。

特别是,超出缓冲区末尾的读取是安全的(这意味着它们不会产生陷阱或其他可观察到的副作用)只要它们不跨越页面边界(因为内存属性和映射是在页面粒度上跟踪的) .由于支持的最小页面大小为 4096 字节,因此对齐的 16 字节加载不能跨越页面边界。

关于c - 矢量化 strlen 摆脱读取未分配的内存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25566302/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com