Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

libasan detects leaks #364

Open
ghost opened this issue Jan 19, 2024 · 5 comments
Open

libasan detects leaks #364

ghost opened this issue Jan 19, 2024 · 5 comments

Comments

@ghost
Copy link

ghost commented Jan 19, 2024

Hi!

We compile all binaries with the libasan, which detects several memory leaks:
Sample code:

#include <Foundation/Foundation.h>

@interface Obj: NSObject
@end

@implementation Obj
@end

int main(void)
{
return 0;
}

Compile with: gcc $(gnustep-config --objc-flags --gui-libs) -fsanitize=address -lgnustep-base -lobjc test.mm -o test

Error returned:

=================================================================
==521628==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 1840 byte(s) in 115 object(s) allocated from:
    #0 0x7f18e02179cf in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:69
    #1 0x7f18dfabbc9c in objc_malloc (/lib/x86_64-linux-gnu/libobjc.so.4+0xac9c)

Direct leak of 40 byte(s) in 1 object(s) allocated from:
    #0 0x7f18e02179cf in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:69
    #1 0x7f18dfabbe4c in class_copyMethodList (/lib/x86_64-linux-gnu/libobjc.so.4+0xae4c)

Indirect leak of 6496 byte(s) in 406 object(s) allocated from:
    #0 0x7f18e02179cf in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:69
    #1 0x7f18dfabbc9c in objc_malloc (/lib/x86_64-linux-gnu/libobjc.so.4+0xac9c)

SUMMARY: AddressSanitizer: 8376 byte(s) leaked in 522 allocation(s).

system:
Linux NAME 5.15.133.1-microsoft-standard-WSL2 #1 SMP Thu Oct 5 21:02:42 UTC 2023 x86_64 GNU/Linux

$ gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/12/lto-wrapper
OFFLOAD_TARGET_NAMES=nvptx-none:amdgcn-amdhsa
OFFLOAD_TARGET_DEFAULT=1
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Debian 12.2.0-14' --with-bugurl=file:///usr/share/doc/gcc-12/README.Bugs --enable-languages=c,ada,c++,go,d,fortran,objc,obj-c++,m2 --prefix=/usr --with-gcc-major-version-only --program-suffix=-12 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-plugin --enable-default-pie --with-system-zlib --enable-libphobos-checking=release --with-target-system-zlib=auto --enable-objc-gc=auto --enable-multiarch --disable-werror --enable-cet --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none=/build/gcc-12-bTRWOB/gcc-12-12.2.0/debian/tmp-nvptx/usr,amdgcn-amdhsa=/build/gcc-12-bTRWOB/gcc-12-12.2.0/debian/tmp-gcn/usr --enable-offload-defaulted --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
Supported LTO compression algorithms: zlib zstd
gcc version 12.2.0 (Debian 12.2.0-14)
$ sudo apt list --installed | grep gnustep
WARNING: apt does not have a stable CLI interface. Use with caution in scripts.

gnustep-back-common/stable,now 0.29.0-3 amd64 [installed,automatic]
gnustep-back0.29-cairo/stable,now 0.29.0-3 amd64 [installed,automatic]
gnustep-back0.29/stable,now 0.29.0-3 all [installed,automatic]
gnustep-base-common/stable,now 1.28.1+really1.28.0-5 all [installed,automatic]
gnustep-base-doc/stable,now 1.28.1+really1.28.0-5 all [installed,automatic]
gnustep-base-runtime/stable,now 1.28.1+really1.28.0-5 amd64 [installed,automatic]
gnustep-common/stable,now 2.9.1-2 amd64 [installed,automatic]
gnustep-core-devel/stable,now 7.10 all [installed,automatic]
gnustep-core-doc/stable,now 7.10 all [installed,automatic]
gnustep-devel/stable,now 7.10 all [installed]
gnustep-gui-common/stable,now 0.29.0-2 all [installed,automatic]
gnustep-gui-doc/stable,now 0.29.0-2 all [installed,automatic]
gnustep-gui-runtime/stable,now 0.29.0-2+b3 amd64 [installed,automatic]
gnustep-icons/stable,now 1.0-10 all [installed,automatic]
gnustep-make-doc/stable,now 2.9.1-2 all [installed,automatic]
gnustep-make/stable,now 2.9.1-2 all [installed,automatic]
gnustep/stable,now 7.10 all [installed]
libgnustep-base-dev/stable,now 1.28.1+really1.28.0-5 amd64 [installed,automatic]
libgnustep-base1.28/stable,now 1.28.1+really1.28.0-5 amd64 [installed,automatic]
libgnustep-gui-dev/stable,now 0.29.0-2+b3 amd64 [installed]
libgnustep-gui0.29/stable,now 0.29.0-2+b3 amd64 [installed,automatic]

(Note: I also posted the issue under: gnustep/libobjc2#270, since I do not know where the memory leak is caused.)

@rfm
Copy link
Contributor

rfm commented Jan 19, 2024

Maybe I'm missing something, but libraries create resources which are expected to last until the program exits;
Is there a reason to think that libasan (I'm not familiar with that) is reporting anything other than those (ie false positives)?

@rfm
Copy link
Contributor

rfm commented Jan 19, 2024

Does libasan have a way to produce a long enough stack trace to tell you where to look to see why the memory was allocated?

@fredkiefer
Copy link
Member

Hi John,

thank you for your efforts. I did not know about this AddressSanitizer (libasan) but previously I used to run Valgrind again GNUstep applications to get similar information about our memory management.
First off, the results you found are in their current form not helpful, with a stack depth of two we only see that some objects where allocated and never freed, but cannot see where they were allocated nor which kind of objects these are.
Next, as Richard already pointed out, this could be natural behaviour for the effected libraries. I seem to remember that Richard even added some setting for libbase, that would allow these objects to register for cleanup at exit, but this needs to be enabled and is also not used in all places. Normally analysis tools come preconfigured with a list of such allocations that should be ignored in specific libraries. As GNUstep is a rather small project we cannot expect that such configurations for our libraries get shipped automatically. What you could do is use the result of your test and somehow create such an ignore list with it (no idea how this is done with libasan) and then take an actual GNUstep application and run libasan with this ignore list. The results from that analysis would be more useful.
The actual interesting cases are when there is a memory leak during that run of an application that accumulates never time. A few static allocated objects that a library won't clean up at exit may be ignored. The time spend to clean up is just not worth it.
When I ran my analysis with Valgrind the results for the GNUstep libraries where quite OK, of course after fixing some existing memory issues :-)

@rfm
Copy link
Contributor

rfm commented Jan 19, 2024

Thanks for saying all the stuff I ought to have said Fred.
You are surely right to point out that the 'cleanup at exit' in the base library is woefully incomplete; I basically gave up part way through implementing it because nobody really seemed interested in the idea of ensuring long term data structures could be destroyed at exit to avoid confusing leak checkers (also because it adds code complexity for no functional gain).

@hmelder
Copy link
Contributor

hmelder commented Jan 19, 2024

This can also come from libobjc2 if using GCC and legacy (assuming you are using libobjc2 and not gcc-objc):

If you're compiling with GCC (which I strongly recommend against), then it will emit the ancient GCC Objective-C ABI where a large number of features will not work. We do an upgrade pass on loading, which constructs the structures for the new ABI with heap memory for all loaded classes. This will probably show up as leaked, because we never free it (it is expected to be present for the lifetime of the program and there is no benefit from calling free a bunch of times before exit).

If you compile with clang and -fobjc-runtime=gnustep-2.0 (or 2.2 if you're using trunk), then you should not see these copies.

Originally posted by @davidchisnall in gnustep/libobjc2#270 (comment)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

3 participants