AddressSanitizer not finding an obvious leak after changing printf - c

I'm scratching my head trying to figure out why ASAN isn't picking up on a simple memory leak. valgrind finds it just fine. Help?
Example that ASAN does find.
#include <stdlib.h>
#include <stdio.h>
void blah(void)
{
int *some_int = malloc(sizeof(int));
*some_int = 1;
printf("hello %p\n", some_int);
// some_int is lost here
}
int main()
{
blah();
return 0;
}
mbryan#remotedev-mbryan:~/git/mbryan/onefs$ clang -fsanitize=address -O0 q.c
mbryan#remotedev-mbryan:~/git/mbryan/onefs$ ./a.out
hello 0x602000000010
=================================================================
==10751==ERROR: LeakSanitizer: detected memory leaks
Direct leak of 4 byte(s) in 1 object(s) allocated from:
#0 0x4d9bd0 in malloc (/ifs/home/mbryan/git/mbryan/onefs/a.out+0x4d9bd0)
#1 0x5120f3 in blah (/ifs/home/mbryan/git/mbryan/onefs/a.out+0x5120f3)
#2 0x512183 in main (/ifs/home/mbryan/git/mbryan/onefs/a.out+0x512183)
#3 0x7f3515000b96 in __libc_start_main /build/glibc-OTsEL5/glibc-2.27/csu/../csu/libc-start.c:310
SUMMARY: AddressSanitizer: 4 byte(s) leaked in 1 allocation(s).
So far so good. Now print the value instead of the pointer:
#include <stdlib.h>
#include <stdio.h>
void blah(void)
{
int *some_int = malloc(sizeof(int));
*some_int = 1;
printf("hello %d\n", *some_int); // <---------------
}
int main()
{
blah();
return 0;
}
mbryan#remotedev-mbryan:~/git/mbryan/onefs$ clang -fsanitize=address -O0 q.c
mbryan#remotedev-mbryan:~/git/mbryan/onefs$ ./a.out
hello 1
...now the leak doesn't show up.
On the latter if I recompile without the sanitizer and run valgrind, valgrind does indeed show a leak:
==10782== definitely lost: 4 bytes in 1 blocks
Looking at the assembly: I see the optimimzer hasn't made my malloc'd variable a local or some other trickery. So: why isn't AddressSanitizer picking up this one? Am I missing something obvious?
This is on Ubuntu18.04 using clang 6.0.0-1ubuntu2.

I've been informed from the ASAN folks that this is a known bug:
https://github.com/google/sanitizers/issues/937
LeakSanitizer: false negative when functions stack frames overlay #937

Related

Valgrind C/C++ Unitialized value created by stack allocation used outside the stack

I got a strange findings in valgrind memcheck, I cannot share the whole code (huge and proprietary), but here is a simplified version:
Conditional jump or move depends on uninitialised value(s)
func2(modu2.c:12631)
func1(modu1.c:1808)
main(main.c:1808)
Uninitialised value was created by a stack allocation
func1_1(modu1.c:691)
func1_1 is called inside func1, all variables created by stack allocation should have been deleted at the end of the function, func2 is never (triple checked) called inside func1_1.
Question 1: Does it has some reasonable explanation other than Valgrind has gone mad? Could some build flags/configuration trigger such issues?
Also, inside func2, the code look like that:
void func2(var input)
{
var tmp = 0;
tmp = input.x + input.y;
if(tmp < 100) // here was the use
doStuff();
}
Question 2: tmp is clearly initialized, could Valgrind send a finding if input.x was not? Both of them? Valgrind crazy?
Thank you very much, this issue is driving me crazy and I am pushing for tool to be part of the process, but I have to proof that it is reliable.
Consider the following example, where tmp is initialized in some sense:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct { int x; int y; } Point;
void foo(const Point *p)
{
int tmp = p->x;
Point *q = new Point;
if (tmp < 742) { delete q; delete q; }
}
int main(int argc, char **argv)
{
Point p;
// p.x = 1000;
foo(&p);
return 0;
}
Valgrind issues a valid error, since tmp depends on
the value of p.x which was not initialized:
$ g++ -g -O0 main.cpp -o main
$ valgrind ./main
==27183== Memcheck, a memory error detector
==27183== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==27183== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==27183== Command: ./main
==27183==
==27183== Conditional jump or move depends on uninitialised value(s)
==27183== at 0x108774: foo(Point const*) (main7.cpp:10)
==27183== by 0x1087C4: main (main7.cpp:17)
==27183==
==27183== Invalid free() / delete / delete[] / realloc()
...
==27183== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
When I remove the comment and initialize p.x everything goes fine.
So the short answer for you is that yes, valgrind uses analyzes that
enable him to monitor uninitialized variables, and propagate these values on.
When an if (exp) { ... } is encountered with exp having an uninitialized value,
both branches are considered

Does not AddressSanitizer trace memory leak from global variable?

I'm trying to use -fsanitize=address with gcc.
I declare global variable(ex. int*) and allocate memory with malloc, then I didn't call free function. I expect the sanitizer will show up error message about memory leak, but it exit with no error message.
So, I use local variable for test. Sanitizer works well on that test code. I put my codes below.
this is a global variable code.
#include<stdio.h>
#include<stdlib.h>
int *gv;
int main(){
gv = (int*)malloc(sizeof(int)*4);
printf("yooooolooooooo\n");
return 0;
}
and this is local variable code.
#include<stdio.h>
#include<stdlib.h>
int main(){
int *gv = (int*)malloc(sizeof(int)*4);
printf("yooooolooooooo\n");
return 0;
}
I compile with gcc -fsanitize=address -o test test.c.
upper code shows me just
yooooolooooooo
but local variable code shows
yooooolooooooo
=================================================================
==15484==ERROR: LeakSanitizer: detected memory leaks
Direct leak of 16 byte(s) in 1 object(s) allocated from:
#0 0x7f6e43395b60 in __interceptor_malloc (/usr/lib/x86_64-linux-gnu/libasan.so.5+0xedb60)
#1 0x564b5f8bd936 in main (/home/jiho/lab/test+0x936)
#2 0x7f6e42ed8b96 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21b96)
SUMMARY: AddressSanitizer: 16 byte(s) leaked in 1 allocation(s).
I wonder why sanitizer doesn't works with global variable...
thank you and i hope someone knows about it.
ps. my system is ubuntu 18.04 and x86_64.
Similar to Valgrind LeakSanitizer reports only "direct" leaks i.e. addresses that are no longer accessible from any existing user data (called "root-set" in LSan design document). In case of global variable the address is obviously still accessible.

How get output of address sanitizer when emiting SIGINT to halt a loop

When I compile this simple test program I get the obvious leak report from address sanitizer, but when I compile the same program but with a infinite loop, and break it emitting SIGINT I don't get any output.
Checking asm output, the malloc is not optimized away (if this is possible at all)
Is this the expected behavior of address sanitizer? I don't encounter this problem in other developments.
Working example:
#include <stdlib.h>
int main(void)
{
char *a = malloc(1024);
return 1;
}
Not working (kill with SIGINT):
#include <stdlib.h>
int main(void)
{
char *a = malloc(1024);
for(;;);
return 1;
}
compile: gcc test.c -o test -fsanitize=address
I encounter this problem in a full programm but I reduced it to this minimal example.
I tried many ways, with exit() and abort() calls, this works:
#include <stdlib.h>
#include <signal.h>
#include <stdio.h>
#include <setjmp.h>
jmp_buf jmpbuf;
void handler (int signum) {
printf("handler %d \n", signum);
// we jump from here to main()
// and then call return
longjmp(jmpbuf, 1);
}
int main(int argc, char *argv[])
{
if (setjmp(jmpbuf)) {
// we are in signal context here
return 2;
}
signal(SIGINT, handler);
signal(SIGTERM, handler);
char *a = malloc(1024);
while (argc - 1);
return 1;
}
Results in:
> gcc file.c -fsanitize=address && timeout 1 ./a.out arg
handler 15
=================================================================
==12970==ERROR: LeakSanitizer: detected memory leaks
Direct leak of 1024 byte(s) in 1 object(s) allocated from:
#0 0x7f4798c9bd99 in __interceptor_malloc /build/gcc/src/gcc/libsanitizer/asan/asan_malloc_linux.cc:86
#1 0x5569e64e0acd in main (/tmp/a.out+0xacd)
#2 0x7f479881206a in __libc_start_main (/usr/lib/libc.so.6+0x2306a)
SUMMARY: AddressSanitizer: 1024 byte(s) leaked in 1 allocation(s).
I guess that the address sanitizer function are executed after main returns.
The code responsible for printing that error output is called as a destructor (fini) procedure. Since your program terminates without calling any of the process destructors (due to the SIGINT), you do not get any error printouts.
__lsan_do_leak_check() can help you avoid using longjmp in #KamilCuk's answer:
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <sanitizer/lsan_interface.h>
void handler (int signum) {
__lsan_do_leak_check();
}
int main(int argc, char *argv[])
{
signal(SIGINT, handler);
char *a = malloc(1024);
a=0;
printf("lost pointer\n");
for(;;);
return 1;
}
Demo:
clang test.c -fsanitize=address -fno-omit-frame-pointer -g -O0 -o test && ./test
lost pointer
C-c C-c
=================================================================
==29365==ERROR: LeakSanitizer: detected memory leaks
Direct leak of 1024 byte(s) in 1 object(s) allocated from:
#0 0x4c9ca3 in malloc (/home/bjacob/test+0x4c9ca3)
#1 0x4f9187 in main /home/bjacob/test.c:13:14
#2 0x7fbc9898409a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2409a)
SUMMARY: AddressSanitizer: 1024 byte(s) leaked in 1 allocation(s).
Note I added a=0 to create a leak.
I also added a printf. Without that printf, the leak error is not printed. I suspect the compiler optimized-out the use of the variable "a" despite my using the -O0 compiler option.

Why is Valgrind complaining about printf instead of my uninitialized counter?

I just started using Valgrind, and I'm not sure the error messages I get are what they should be. For instance, Valgrind just gave me a very long chain of warnings about printf() making jumps based on uninitialized memory. It was obviously that the issue wasn't with printf(). Rather, my program was giving printf() tainted memory.
I managed to produce the following MCVE:
#include <stdio.h>
int main(void)
{
int d;
d++;
printf("%d\n", d);
return 0;
}
It's really obvious that the problem here lies in d++. However, Valgrind only detects and warns me of uninitialized memory usage in the next line, with 6 messages in the form
==12178== Conditional jump or move depends on uninitialised value(s)
==12178== at 0x4E7F79D: vfprintf (vfprintf.c:1636)
==12178== by 0x4E871F8: printf (printf.c:33)
==12178== by 0x1086D1: main (mcve.c:7)
I compiled this with
gcc mcve.c -g -O0
And I ran Valgrind with
valgrind --leak-check=yes ./a.out
Then I discovered there's --track-origins=yes. It attempts to help, but it gets lost easily with pointers. For instance, it doesn't work for the next MCVE:
#include <stdio.h>
int f2(int *p)
{
(*p)++;
return *p;
}
int f1(void)
{
int d;
return f2(&d);
}
int main(void)
{
printf("%d\n", f1());
return 0;
}
Here it says that the error is in the stack frame of f1(). It's kind of helpful, but considering the performance penalty involved, maybe it's not worth it.
What can I do to make best use of Valgrind?
A deliberate decision in Valgrind is that it does not complain
just because some uninitialised memory is copied or similar.
It complaints only when the use of uninitialised memory changes the
behaviour of your program. This deliberate choice avoids a lot of false-positive errors.
See http://www.valgrind.org/docs/manual/mc-manual.html#mc-manual.uninitvals
for more information.

How to find memory leaks with Clang

I have installed Clang in my machine (ubuntu) in order to find memory leaks in my C code. I wrote a sample code in order to check the working of it which is as follows:
/* File: hello.c for leak detection */
#include <stdio.h>
#include <stdlib.h>
void *x;
int main() {
x = malloc(2);
x = 0; // Memory leak
return 0;
}
I found some options in internet to compile like
$ scan-build clang --analyze hello.c
and
$ scan-build clang -fsanitize=address hello.c
But none of them are showing any signs of memory leak.
scan-build: Using '/usr/bin/clang' for static analysis scan-build:
Removing directory '/tmp/scan-build-2015-07-02-122717-16928-1' because
it contains no reports. scan-build: No bugs found.
Can anyone kindly tell how to correctly use Clang for Memory leak detection.
Interestingly, the clang static analyzer finds the memory leak if you declare void *x inside main:
int main() {
void *x = malloc(2);
x = 0; // Memory leak
return 0;
}
Analyzing this code by running:
scan-build clang -g hello.c
gives a warning like:
hello.c:9:3: warning: Potential leak of memory pointed to by 'x'
return 0;
^~~~~~~~

Resources