Address sanitizer 说有段错误,但是 valgrind 和 gdb 说没有?

问题描述 投票:0回答:1

我目前正在上一门课程,要求我编写汇编代码,准确地说是 x86-64 AT&T 语法汇编代码。下面是一个 c 文件,其中包含我必须编写其汇编代码的函数“bubble”的函数定义。

#include<stdio.h>
#include<stdlib.h>

void bubble(int* arr, int len);

int main(){
    int n;
    scanf("%d", &n);
    int* arr = malloc(sizeof(int)*n);
    for (int i = 0; i < n; i++)
    {
        scanf("%d", &arr[i]);
    }
    bubble(arr, n);
    for (int i = 0; i < n; i++)
    {
        printf("%d ", arr[i]);
    }
    printf("\n");
    free(arr);
}

下面是函数泡泡的汇编代码,

.global bubble
.text

bubble:
    movq $-1, %rcx
.L1:
    incq %rcx
    movl 4(%rdi,%rcx,4), %eax
    cmpl (%rdi,%rcx,4), %eax
    jge .T1
    movl (%rdi,%rcx,4), %eax
    movl 4(%rdi,%rcx,4), %ebx
    movl %eax, 4(%rdi,%rcx,4)
    movl %ebx, (%rdi,%rcx,4)
.T1:
    movq %rsi, %rax
    subq %rcx, %rax
    cmpq $0x2, %rax
    jne .L1
.T2:
    decq %rsi
    cmpq $0x1, %rsi
    jne bubble
    ret

我简单的用命令编译,

gcc bubble.c func.s

现在只要像上面那样编译并运行,就没有错误,程序按预期运行(注意 - 我正在 Ubuntu 上编译和运行)。

但是,在编译时使用

gcc bubble.c func.s -g -fsanitize=address

运行,出现以下错误,

=================================================================
==654==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000001 (pc 0x55d713a2944e bp 0x7ffed345b730 sp 0x7ffed345b6a0 T0)
==654==The signal is caused by a WRITE memory access.
==654==Hint: address points to the zero page.
    #0 0x55d713a2944e in main /mnt/c/Users/rudy/Desktop/CSO/test/bubble.c:6
    #1 0x7fe6ec4b0d8f in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
    #2 0x7fe6ec4b0e3f in __libc_start_main_impl ../csu/libc-start.c:392
    #3 0x55d713a29124 in _start (/mnt/c/Users/rudy/Desktop/CSO/test/a.out+0x1124)        

AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV /mnt/c/Users/rudy/Desktop/CSO/test/bubble.c:6 in main    
==654==ABORTING

将其放入 gcc 后,它运行良好并退出

[Inferior 1 (process 685) exited normally]

以及在命令中使用 valgrind,

valgrind --leak-check=full ./a.out

它运行良好并退出

==694== 
==694== HEAP SUMMARY:
==694==     in use at exit: 0 bytes in 0 blocks
==694==   total heap usage: 3 allocs, 3 frees, 2,068 bytes allocated
==694==
==694== All heap blocks were freed -- no leaks are possible
==694==
==694== For lists of detected and suppressed errors, rerun with: -s
==694== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

那么为什么地址消毒器会出现段错误?抱歉,如果我的问题或格式有任何问题,这是我的第一个问题。

assembly gcc segmentation-fault x86-64 address-sanitizer
1个回答
3
投票

您的

bubble
函数破坏了
%rbx
寄存器(修改它而不在返回之前恢复其先前的值)。这违反了 Linux/SysV x86-64 调用约定,该约定指定
%rbx
由函数调用保留。请参阅通过 linux x86-64 函数调用保留哪些寄存器x86 程序集 - 为什么 [e]bx 在调用约定中保留?.

最简单的修复就是使用一个不同的寄存器,它被指定为调用破坏,例如

%rdx
。如果你真的想使用
%rbx
,那么在你的函数顶部使用
push %rbx
,然后在返回之前使用
pop %rbx

至于为什么它只在使用 AddressSanitizer 时崩溃:似乎没有 ASAN,编译后的

main
代码实际上并没有在函数调用中的
%rbx
中存储任何重要值;实际上它根本不使用
%rbx
。 (对于未优化的编译来说并不奇怪。)而且我猜
main
的调用者也没有在那里存储值。所以在这种情况下不会造成任何伤害。但是当 ASAN 打开时,
%rbx
被它添加的检测代码使用。所以我们实际上不能相信 ASAN 的严格检查发现了你的错误;只是启用它会以一种恰好触发它的方式更改生成的代码。

(附带错误:如果传递长度为 0 或 1 的数组,您的

bubble
函数将崩溃。)

© www.soinside.com 2019 - 2024. All rights reserved.