2017-01-09 1 views
1

erkennen Wenn ich Address Sanitizer (clang v3.4) zur Erkennung von Speicherlecks verwende, habe ich festgestellt, dass die Option -O (außer -O0) immer zu einem Leck führen würde -erfasstes ErgebnisAdresse Sanitizer kann Speicherverluste nicht mit der Option -O

Der Code ist einfach:

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

int main() 
{ 
    int* array = (int *)malloc(sizeof(int) * 100); 
    for (int i = 0; i < 100; i++) //Initialize 
    array[i] = 0; 
    return 0; 
} 

wenn kompilieren mit -O0,

clang -fsanitize=address -g -O0 main.cpp 

es richtig Speicher erkennt,

==2978==WARNING: Trying to symbolize code, but external symbolizer is not initialized! 

================================================================= 
==2978==ERROR: LeakSanitizer: detected memory leaks 

Direct leak of 400 byte(s) in 1 object(s) allocated from: 
    #0 0x4652f9 (/home/mrkikokiko/sdk/MemoryCheck/a.out+0x4652f9) 
    #1 0x47b612 (/home/mrkikokiko/sdk/MemoryCheck/a.out+0x47b612) 
    #2 0x7fce3603af44 (/lib/x86_64-linux-gnu/libc.so.6+0x21f44) 

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

jedoch, wenn -O hinzugefügt,

clang -fsanitize=address -g -O main.cpp 

nichts wird erkannt! Und ich finde nichts davon im offiziellen Dokument.

+0

Ihr Code ist Code C, nicht C++ Code. Das C++ - Tag ist falsch und ein C-Tag sollte verwendet werden. –

+0

Sie verwenden kein Array, vielleicht wird es optimiert? –

+0

@BasileStarynkevitch siehe die Zeile 'clang -fsanitize = Adresse -g -O main.cpp' - das zeigt an, dass OP C++ benutzt (der Clan-Compiler wählt die Sprache basierend auf der Dateiendung' .cpp'). OP-Code ist gültig C++. –

Antwort

5

Dies ist, weil your code is completely optimized away. Die resultierende Anordnung ist so etwas wie:

main:         # @main 
    xorl %eax, %eax 
    retq 

Ohne Aufruf malloc, gibt es keine Speicherzuweisung ... und daher kein Speicherleck.


Um AddressSanitizer den Speicherverlust erkennen haben, können Sie entweder:

  • Compile with optimizations disabled, wie Simon Kraemer in den Kommentaren erwähnt.

  • Mark array als volatile, preventing the optimization:

    main:         # @main 
         pushq %rax 
         movl $400, %edi    # imm = 0x190 
         callq malloc     # <<<<<< call to malloc 
         movl $9, %ecx 
    .LBB0_1:        # =>This Inner Loop Header: Depth=1 
         movl $0, -36(%rax,%rcx,4) 
         movl $0, -32(%rax,%rcx,4) 
         movl $0, -28(%rax,%rcx,4) 
         movl $0, -24(%rax,%rcx,4) 
         movl $0, -20(%rax,%rcx,4) 
         movl $0, -16(%rax,%rcx,4) 
         movl $0, -12(%rax,%rcx,4) 
         movl $0, -8(%rax,%rcx,4) 
         movl $0, -4(%rax,%rcx,4) 
         movl $0, (%rax,%rcx,4) 
         addq $10, %rcx 
         cmpq $109, %rcx 
         jne  .LBB0_1 
         xorl %eax, %eax 
         popq %rcx 
         retq 
    
+1

Oder kompilieren Sie einfach mit '-O0': https://godbolt.org/g/0ul4bk –

+0

@SimonKraemer: Ich nahm an, das OP war sich dessen bewusst, als er erwähnte, dass beim Kompilieren mit '-O0' das Speicherleck gemeldet wird korrekt. –

+0

wollte nur für die Vollständigkeit hinzufügen ... –

3

Schauen Sie in den generierten Code.

Beide GCC & Clang eigentlich über die Semantik von malloc. Da auf meinem Linux/Debian-System <stdlib.h> enthält

extern void *malloc (size_t __size) __THROW __attribute_malloc__ __wur; 

und die __attribute_malloc__ & _wur (und __THROW) sind Makros an anderer Stelle definiert. Lesen Sie mehr über Common Function Attributes in GCC documentation und Clang Dokumentation says:

Clang zielt darauf ab, eine breite Palette von GCC-Erweiterungen zu unterstützen.

Ich vermute stark, dass mit -O der Aufruf an malloc es durch Entfernen optimiert ist.

Auf meinem Linux/x86-64 Maschine clang -O -S psbshdk.c (mit Klirren 3.8) ich in der Tat bin immer:

.globl main 
    .align 16, 0x90 
    .type main,@function 
main:         # @main 
    .cfi_startproc 
# BB#0: 
    xorl %eax, %eax 
    retq 
.Lfunc_end0: 
    .size main, .Lfunc_end0-main 
    .cfi_endproc 

Die Adresse Sanitizer auf dem emittierten binären arbeitet (was nicht enthält jeden malloc Anruf) .

BTW, könnten Sie mit clang -O -g kompilieren dann verwenden Sie valgrind, oder kompilieren Sie mit clang -O -fsanitize=address -g. Beide clang & gcc sind in der Lage zu optimieren und geben einige Debug-Informationen (die "ungefähr" sein können, wenn eine Menge zu optimieren).