Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Address sanitizer says there is a segfault, but valgrind and gdb say there isn't?

I am currently taking a course which requires me to write assembly code, to be precise x86-64 AT&T syntax assembly code. Below is a c file which contains the function definition of a function "bubble" whose assembly code I have to write.

#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);
}

And below is the assembly code for the function bubble,

.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

I simply compile with the command,

gcc bubble.c func.s

Now on just compiling as above and running, there are no errors and the program runs as expected (note - I am compiling and running on Ubuntu).

However, on compiling using

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

and running, I get the following error,

=================================================================
==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

On putting it into gcc, it runs fine and exits with

[Inferior 1 (process 685) exited normally]

and on using valgrind with command,

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

it runs fine and exits with

==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)

So then why does address sanitizer give that segfault? Apologies if there are any issues with my question or formatting, this is my first question.

like image 497
Anili Avatar asked Feb 03 '26 21:02

Anili


1 Answers

Your bubble function clobbers the %rbx register (modifies it without restoring its previous value before returning). This violates the Linux/SysV x86-64 calling conventions, which specify that %rbx is to be preserved by fuction calls. See What registers are preserved through a linux x86-64 function call, x86 Assembly - Why is [e]bx preserved in calling conventions?.

The simplest fix is just to use a different register that is designated as call-clobbered, such as %rdx. If you really want to use %rbx, then push %rbx at the top of your function, and pop %rbx just before returning.

As to why it crashes only when using AddressSanitizer: it appears that without ASAN, the compiled main code doesn't actually store any important value in %rbx across the function call; indeed it doesn't use %rbx at all. (Not too surprising for unoptimized compilation.) And I guess that the caller of main doesn't store a value there either. So no harm happens to result in that case. But when ASAN is switched on, %rbx is used by the instrumentation code that it adds. So we can't actually credit ASAN's rigorous checking for finding your bug; it's simply that enabling it changes the generated code in a way that happens to trigger it.

(Side bug: your bubble function will crash if passed an array of length 0 or 1.)

like image 200
Nate Eldredge Avatar answered Feb 05 '26 11:02

Nate Eldredge