Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 在x86和x64上读取同一页中的缓冲区末尾是否安全?_C_Performance_Assembly_Optimization_X86 - Fatal编程技术网

C 在x86和x64上读取同一页中的缓冲区末尾是否安全?

C 在x86和x64上读取同一页中的缓冲区末尾是否安全?,c,performance,assembly,optimization,x86,C,Performance,Assembly,Optimization,X86,如果允许在输入缓冲区末尾读取少量数据,那么高性能算法中的许多方法都可以简化。这里,“小数量”通常指超过末尾的最多W-1字节,其中W是算法的字大小(以字节为单位)(例如,对于以64位块处理输入的算法,最多7个字节) 很明显,一般来说,在输入缓冲区结束后写入数据是不安全的,因为您可能会将数据删除到缓冲区1之外。同样清楚的是,从缓冲区的末尾读入另一页可能会触发分段错误/访问冲突,因为下一页可能不可读 然而,在读取对齐值的特殊情况下,页面错误似乎是不可能的,至少在x86上是这样。在该平台上,页面(以及内

如果允许在输入缓冲区末尾读取少量数据,那么高性能算法中的许多方法都可以简化。这里,“小数量”通常指超过末尾的最多
W-1
字节,其中
W
是算法的字大小(以字节为单位)(例如,对于以64位块处理输入的算法,最多7个字节)

很明显,一般来说,在输入缓冲区结束后写入数据是不安全的,因为您可能会将数据删除到缓冲区1之外。同样清楚的是,从缓冲区的末尾读入另一页可能会触发分段错误/访问冲突,因为下一页可能不可读

然而,在读取对齐值的特殊情况下,页面错误似乎是不可能的,至少在x86上是这样。在该平台上,页面(以及内存保护标志)具有4K粒度(可以使用更大的页面,例如2MiB或1GiB,但这些页面是4K的倍数),因此对齐读取将仅访问与缓冲区有效部分相同页面中的字节

下面是一个典型的循环示例,该循环将其输入对齐,并读取超过缓冲区末尾7个字节的数据:

int processBytes(uint8_t *input, size_t size) {

    uint64_t *input64 = (uint64_t *)input, end64 = (uint64_t *)(input + size);
    int res;

    if (size < 8) {
        // special case for short inputs that we aren't concerned with here
        return shortMethod();
    }

    // check the first 8 bytes
    if ((res = match(*input)) >= 0) {
        return input + res;
    }

    // align pointer to the next 8-byte boundary
    input64 = (ptrdiff_t)(input64 + 1) & ~0x7;

    for (; input64 < end64; input64++) {
        if ((res = match(*input64)) > 0) {
            return input + res < input + size ? input + res : -1;
        }
    }

    return -1;
}
int processBytes(uint8\u t*input,size\u t size){
uint64_t*输入64=(uint64_t*)输入,end64=(uint64_t*)(输入+大小);
国际关系;
如果(尺寸<8){
//我们这里不关心的短输入的特殊情况
返回shortMethod();
}
//检查前8个字节
如果((res=match(*input))>=0){
返回输入+res;
}
//将指针与下一个8字节边界对齐
input64=(ptrdiff_t)(input64+1)和~0x7;
对于(;input640){
返回input+res
内部函数
int match(uint64\u t bytes)
未显示,但它查找与特定模式匹配的字节,如果找到,则返回该位置的最低值(0-7),否则返回-1

首先,大小小于8的案例被典当到另一个函数,以简化说明。然后对前8个字节(未对齐字节)执行一次检查。然后对剩余的
楼层((大小-7)/8)
块8字节2执行循环。此循环最多可以读取超过缓冲区末尾的7个字节(当
输入&0xF==1
时会出现7个字节的情况)。但是,return调用有一个检查,它排除了缓冲区末尾以外发生的任何虚假匹配

实际上,这样的函数在x86和x86-64上安全吗?

这些类型的超读在高性能代码中很常见。避免这种过度阅读的特殊尾部代码也很常见。有时,您会看到后一种类型取代了前一种类型,使valgrind等工具静音。有时,您会看到这样一个替代方案,但由于习惯用法是安全的,并且工具出错(或者过于保守)而被拒绝

语言律师须知:

绝对不允许读取超出其分配大小的指针 在标准中。我欣赏律师回答的语言,甚至偶尔写信 我自己写的,当有人翻阅这一章时,我甚至会很高兴 显示上述代码的诗句是未定义的行为,因此 严格意义上讲不安全(我将在这里复制细节)。但归根结底,这不是问题所在 我在找你。实际上,许多涉及指针的常用习惯用法 转换、通过此类指针进行结构访问等等 技术上未定义,但在高质量和高性能方面广泛存在 性能代码。通常没有替代品,或者替代品 以半速或更低的速度运行

如果你愿意,考虑这个问题的修改版本,即:

在上述代码已编译为x86/x86-64程序集,且用户已验证其以预期方式编译后(即。, 编译器没有使用可证明的部分越界访问 做点什么, 执行编译后的程序安全吗

在这方面,这个问题既是一个C问题,也是一个x86汇编问题。我所看到的大多数使用这种技巧的代码都是用C编写的,而C仍然是高性能库的主导语言,很容易超越像asm这样的低级语言和像asm这样的高级语言。至少在核心数字领域之外FORTRAN仍在发挥作用,所以我对这个问题的C-compiler-and-down视图感兴趣,这就是为什么我没有将它表述为一个纯粹的x86汇编问题

尽管如此,我对链接到 标准显示这是环球开发商,我非常感兴趣的任何细节 可以使用此特定UD生成 意外的代码。现在我认为如果没有一些深层次的 非常深入的跨过程分析,但是gcc溢出的东西 也让很多人感到惊讶


1即使在明显无害的情况下,例如,在回写相同值的情况下,它也可以

2注意:要使此重叠工作,需要此函数和
match()
函数以特定的幂等方式工作,特别是返回值支持重叠检查。因此,“查找第一个字节匹配模式”工作,因为所有
match()
调用仍然有序。“计数字节匹配模式”但是,方法不起作用,因为有些字节可能会被重复计数。顺便说一下:有些函数,例如“returntheminimumbyte”调用,即使没有顺序限制也可以工作,但需要检查所有字节

3这里值得注意的是,对于valgrind的Memcheck,
--部分加载ok
,它控制这样的读取是否实际上被报告为错误。默认值为yes,这意味着一般情况下,这样的加载不会被视为立即错误,而是