C Clang and AddressSanitizer

Hello,

I've installed FreeBSD13
Code:
:~ $ uname -a
FreeBSD pc.freebsd 13.0-RELEASE-p4 FreeBSD 13.0-RELEASE-p4 #0: Tue Aug 24 07:33:27 UTC 2021     root@amd64-builder.daemonology.net:/usr/obj/usr/src/amd64.amd64/sys/GENERIC  amd64
and want to use AddressSanitizer with clang.

It's a clean system with a minimal installation - just xorg and a window manager (awesome wm). And the c-file is just an empty main function.

Clang is installed (not by me).
Code:
:~ $ clang --version
FreeBSD clang version 11.0.1 (git@github.com:llvm/llvm-project.git llvmorg-11.0.1-0-g43ff75f2c3fe)
Target: x86_64-unknown-freebsd13.0
Thread model: posix
InstalledDir: /usr/bin

When I try to use it, an error occurs.
Code:
 :~ $ ls -a
.       ..      a.out   main.c
:~ $ clang -std=c11 -Wall -fsanitize=address -fno-omit-frame-pointer main.c
:~ $ ls -a
.       ..      a.out   main.c
:~ $ ./a.out 
==22487==Sanitizer CHECK failed: /usr/src/contrib/llvm-project/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_bsd.cpp:71 ((Err)) == ((0)) (-1, 0)

llvm is installed too:
Code:
:~ $ pkg info | grep llvm
llvm12-12.0.1_5                LLVM and Clang

So I tried to compile with clang12:
Code:
:~$ clang12 -std=c11 -Wall -fsanitize=address -fno-omit-frame-pointer main.c
:~ $ ./a.out 
==27545==Sanitizer CHECK failed: /wrkdirs/usr/ports/devel/llvm12/work/llvm-project-12.0.1.src/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_bsd.cpp:62 ((Err)) == ((0)) (-1, 0)

Can you use AddresSanitizer with clang?
 
Last edited by a moderator:
First of all, yes, clang/llvm 11.0.1 is in base (for FreeBSD 13).

I just tried compiling and linking one of my projects adding -fsanitize=address and it worked fine (and I get no messages running it, so I guess no bugs here, hehe).

So, maybe there is a problem with your code? Although admittedly, the message you receive doesn't look all too helpful.
 
  • Thanks
Reactions: a6h
It's a new system and a regular empty c-file.

Code:
#include <stdio.h>

int main(void){
    return 0;
}

Actually it's my second installation (as a virtual machine now). Because I had same problems with a regular installation. But this (second) installation is almost empy. I've just installed two or three things (xorg + awesomewm).
 
Well, then I can't reproduce:
Code:
$ cat - >santest.c
#include <stdio.h>

int main(void){
    return 0;
}
 
$ clang -std=c11 -Wall -fsanitize=address -fno-omit-frame-pointer santest.c

$ ./a.out
No messages whatsoever here.
Code:
$ freebsd-version -kr
13.0-RELEASE-p4
13.0-RELEASE-p4
13.0-RELEASE-p4
 
Doing some quick testing; the issue you are encountering is because you enabled the proc_debug hardening option. LLVM sanitizer uses proc to check the memory mappings; which that hardening feature blocks that ability; disabling it will allow the address sanitizer to work properly.

https://forums.freebsd.org/threads/freebsd-11-new-installer-options.57807/

This thread goes into how to change temporarily (until you reboot or keep through reboots). The specific option you are concerned about is security.bsd.unprivileged_proc_debug=0.
The =0 portion disables access.
 
Have you run your executable as follows?

With clang 14.0.0 ( pkg install llvm-devel)

Code:
❯ clang --version
clang version 14.0.0
Target: x86_64-portbld-freebsd13.0
Thread model: posix
InstalledDir: /usr/local/llvm-devel/bin

❯ clang -std=c11 -Wall -fsanitize=address -fno-omit-frame-pointer -o foo foo.c

❯ env ASAN_OPTIONS=detect_leaks=1:color=always ./foo
==15372==AddressSanitizer: detect_leaks is not supported on this platform.

Also with gcc11

Code:
❯ gcc11 -std=c11 -Wall -Wl,-rpath=/usr/local/lib/gcc11 -fsanitize=address -fno-omit-frame-pointer -o foo foo.c

❯ env ASAN_OPTIONS=detect_leaks=1:color=always ./foo
==521==AddressSanitizer: detect_leaks is not supported on this platform.

I'm not sure whether AddressSanitizer is supported on FreeBSD.

Here's a sample program foo.c:

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

int
main(void) {
        char *buffer = malloc(123);
        sprintf(buffer, "%d", 123);
        printf("%s\n", buffer);

        return EXIT_SUCCESS;
}

My /etc/sysctl.conf

Code:
# Enable Process Debugging Facilities
security.bsd.unprivileged_proc_debug=1
 
Last edited by a moderator:
The AddressSanitizer doesn't detect memory leaks:

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

int*
foo (void)
{
   int* p = malloc (sizeof (*p));
   *p = rand() % 10;
   return p;
}

int
main (void)
{
   for (size_t i = 0; i < 5; i++) {
      printf ("num: %d\n", *foo());
   }

   return EXIT_SUCCESS;
}

It should produce errors.
 
Have you run your executable

Code:
#include <stdio.h>                                                            
#include <stdlib.h>                                                           
                                                                              
int                                                                           
main (void)                                                                   
{                                                                             
   int* x = malloc (sizeof (*x));                                             
                                                                              
   *x = 1;                                                                    
   printf ("x: %d\n", *x);                                                    
                                                                              
   free (x);                                                                  
                                                                              
   *x = 2;                                                                    
   printf ("x: %d\n", *x);                                                    
                                                                              
   return EXIT_SUCCESS;                                                       
}

Code:
$ clang12 -std=c17 -Wall -Wextra -fsanitize=address main.c
$ ./a.out 
x: 1
=================================================================
==69632==ERROR: AddressSanitizer: heap-use-after-free on address 0x602000000010 at pc 0x0000002b7af9 bp 0x7fffffffe680 sp 0x7fffffffe678.......

In this case - it works.

But you are right - it doesn't detect memory leaks :-(
 
Hi any_name_you_wish

Ah, got it. My bad. Should have said that detecting leaks doesn't appear to be supported on FreeBSD when one enables AddressSanitizer (yet). AddressSanitizer works, indeed. There appear to be some differences between features supported on different platforms, however. Here's a use-after-free detected correctly:

Code:
❯ clang -std=c11 -Wall -Weverything -fsanitize=address -fno-omit-frame-pointer -o foo foo.c

❯ ./foo
=================================================================
==37930==ERROR: AddressSanitizer: heap-use-after-free on address 0x602000000010 at pc 0x0000002c345c bp 0x7fffffffe7f0 sp 0x7fffffffe7e8
WRITE of size 4 at 0x602000000010 thread T0
    #0 0x2c345b in main (/usr/home/yesudeep/code/foo/foo+0x2c345b)
    #1 0x2384cf in _start /usr/src/lib/csu/amd64/crt1_c.c:75:7
    #2 0x8002e9007  (<unknown module>)

0x602000000011 is located 0 bytes to the right of 1-byte region [0x602000000010,0x602000000011)
freed by thread T0 here:
    #0 0x293d62 in free /wrkdirs/usr/ports/devel/llvm-devel/work-default/llvm-project-a614a28772cbd8e0fc3c5fcf836493c2c8bc80da/compiler-rt/lib/asan/asan_malloc_linux.cpp:111:3
    #1 0x2c3415 in main (/usr/home/yesudeep/code/foo/foo+0x2c3415)
    #2 0x2384cf in _start /usr/src/lib/csu/amd64/crt1_c.c:75:7
    #3 0x8002e9007  (<unknown module>)

previously allocated by thread T0 here:
    #0 0x293ead in malloc /wrkdirs/usr/ports/devel/llvm-devel/work-default/llvm-project-a614a28772cbd8e0fc3c5fcf836493c2c8bc80da/compiler-rt/lib/asan/asan_malloc_linux.cpp:129:3
    #1 0x2c3408 in main (/usr/home/yesudeep/code/foo/foo+0x2c3408)
    #2 0x2384cf in _start /usr/src/lib/csu/amd64/crt1_c.c:75:7
    #3 0x8002e9007  (<unknown module>)

SUMMARY: AddressSanitizer: heap-use-after-free (/usr/home/yesudeep/code/foo/foo+0x2c345b) in main
Shadow bytes around the buggy address:
  0x4c03ffffffb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x4c03ffffffc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x4c03ffffffd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x4c03ffffffe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x4c03fffffff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x4c0400000000: fa fa[fd]fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x4c0400000010: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x4c0400000020: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x4c0400000030: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x4c0400000040: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x4c0400000050: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==37930==ABORTING

It appears to have a detect_leaks option on other platforms. Here's Linux for example where it is enabled by default:

Code:
❯ clang --version
Ubuntu clang version 14.0.0-++20211008104411+f4145c074cb8-1~exp1~20211008085218.709
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin

❯ clang -std=c11 -Wall -Weverything -fsanitize=address -fno-omit-frame-pointer -o foo foo.c

❯ ./foo
=================================================================
==27670==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 1024 byte(s) in 1 object(s) allocated from:
    #0 0x49ca8d in __interceptor_malloc (/home/yesudeep/code/foo/foo+0x49ca8d)
    #1 0x4d33b8 in main (/home/yesudeep/code/foo/foo+0x4d33b8)
    #2 0x7f57c380d564 in __libc_start_main csu/../csu/libc-start.c:332:16

SUMMARY: AddressSanitizer: 1024 byte(s) leaked in 1 allocation(s).

And on MacOS (and clang 13):

Code:
❯ clang --version
Homebrew clang version 13.0.0
Target: x86_64-apple-darwin20.6.0
Thread model: posix
InstalledDir: /usr/local/opt/llvm/bin

❯ env ASAN_OPTIONS=detect_leaks=1:color=always ./foo
=================================================================
==20210==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 1024 byte(s) in 1 object(s) allocated from:
    #0 0x100cdd7b0 in wrap_malloc+0xa0 (libclang_rt.asan_osx_dynamic.dylib:x86_64+0x447b0)
    #1 0x100c8be28 in main+0x18 (foo:x86_64+0x100003e28)
    #2 0x7fff2035af3c in start+0x0 (libdyld.dylib:x86_64+0x15f3c)

SUMMARY: AddressSanitizer: 1024 byte(s) leaked in 1 allocation(s).

❯ ./foo   # not enabled by default

Thanks for the tip. Got ASAN working on FreeBSD!
 
Paul Floyd yep. that's something i'll try to integrate into my workflow as well. I'll read up on Valgrind memcheck to see how.

Here's why I'm trying to get ASAN to work:

I currently use ASAN with bazel (and a bazel CI) and would want AddressSanitizer to support leak detection on FreeBSD so that the CI build processes can report errors detected by automated runs that look like the following:

Code:
# run exec
❯ bazel run --config=asan_freebsd //some/project:executable

# run all tests
❯ bazel test --config=asan_freebsd ...

The CI allows one to write fairly portable code that one can test rapidly and in-parallel on multiple operating systems. I do hope that ASAN adds support for leak detection on FreeBSD as well.
 
I have no experience with bazel, but the following should work

Code:
bazel run --run_under='valgrind {valgrind options}'
bazel test --config=memcheck whatever
 
Back
Top