Memory leak in <unknown module>

81 views
Skip to first unread message

Xellos

unread,
Dec 29, 2024, 6:12:43 PM12/29/24
to Java Native Access

Context: I want to take a Java project that uses a native library via JNA and run its JUnit tests under address sanitizer, suppressing all memory leaks reported from JNA or other Java libraries. I don't care if they're false positive or even true positive leaks, I only need to suppress chosen libraries.

Consider the following JUnit test class:

import com.sun.jna.Memory;
import com.sun.jna.Pointer;
import java.lang.Integer;
import java.util.ArrayList;
import java.util.List;
import org.junit.jupiter.api.Test;

public class MyTest {
    private void dummyTest() {
        new Memory(1024 * 9);
    }

    @Test
    public void find() {
        List<Integer> list = new ArrayList<>();
        list.add(new Integer(1));

        list.stream().map(arg -> {
            Pointer ptr = new Memory(1024 * 1024);
            return ptr;
        }).toArray(Pointer[]::new);
    }

    @Test
    public void test001() {
        dummyTest();
    }

// [91 more identical tests named test002...test092 follow]

I run it on Docker Ubuntu 24.04 with packages openjdk-8-jdk clang-17 using Gradle, with address sanitizer preloaded. JNA 5.12.1, JUnit 5.8.2, host system is an up-to-date Arch Linux. See repo for full reproduction - run.sh to build and run docker, it executes "./run_with_asan.sh ./gradlew clean build test".

It consistently produces the following leak report:

Direct leak of 1048576 byte(s) in 1 object(s) allocated from:
    #0 0x759245cfb372 in malloc (/usr/lib/llvm-17/lib/clang/17/lib/linux/libclang_rt.asan-x86_64.so+0xfb372) (BuildId: 91f375f2a48c6b133a56d8cc059d017ae5de4982)
    #1 0x7592316185e6  (<unknown module>)
    #2 0x759231607bcf  (<unknown module>)
    #3 0x759231607bcf  (<unknown module>)
    #4 0x7592316080f5  (<unknown module>)
    #5 0x759231607e3f  (<unknown module>)
    #6 0x75923197befb  (<unknown module>)

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

This clearly refers to the native memory allocated on line 19. Could this be a JNA bug?

Expected correct behaviour: a library other than <unknown module> (or asan) appears in this leak report (therefore, no leak report appears if at least one such library is in the suppressions list).

The test class has to be large - this leak report disappears or appears depending on number of JUnit tests and even their exact names. It could be just an effect of changing order of tests. That's part of why I'm very unsure if it's an issue with JNA specifically, or something general with unloading/symbolizer/etc.

Matthias Bläsing

unread,
Dec 30, 2024, 3:05:32 AM12/30/24
to jna-...@googlegroups.com
Hi,

JNA, its native components and libffi all allocate native memory. The native memory is in most cases tied to the lifecycle of the corresponding java object and gets freed by a "Cleaner".

So you write "this leak report disappears or appears", this matches GC behavior. There are no guarantees,  when or if the GC runs. If it does not run and the Java process is terminated, the native memory will look like it was not freed. So nothing special here.

Greeting

Matthias
--
You received this message because you are subscribed to the Google Groups "Java Native Access" group.
To unsubscribe from this group and stop receiving emails from it, send an email to jna-users+...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/jna-users/af78fe45-af3a-44f3-86f2-93cd3d29ad63n%40googlegroups.com.

Message has been deleted
Message has been deleted

Xellos

unread,
Dec 30, 2024, 3:46:26 PM12/30/24
to Java Native Access
That's not what I'm asking about. I don't care when it's freed or if it's freed at all or when GC will run, but about not getting all <unknown module> so that I can suppress it. The issue is with reported leak in <unknown module>, not reported leak in general.

Note the run_with_asan.sh script already includes suppressions for many libs (to avoid huge output):
echo -e "leak:libjvm\nleak:libjli\nleak:libz\nleak:liblcms\nleak:liblcms2\nleak:libjavalcms\nleak:libawt\n" >> lsan.supp

When the leak report disappears, it can also be the result of successful suppression. However, the issue is that it doesn't happen always.

(What's up with deleting messages? I just wanted to ask...)

Xellos

unread,
Dec 30, 2024, 3:46:34 PM12/30/24
to Java Native Access
That's not what I'm asking about. I don't care whether it will be eventually freed or when GC will run, but about not getting all <unknown module> so that I can suppress it.

On Monday, 30 December 2024 at 09:05:32 UTC+1 mbla...@doppel-helix.eu wrote:

Matthias Bläsing

unread,
Dec 31, 2024, 3:15:45 AM12/31/24
to jna-...@googlegroups.com
Hi,

Am Montag, dem 30.12.2024 um 01:40 -0800 schrieb Xellos:
(What's up with deleting messages? I just wanted to ask...)

you got into the moderation. I suspect, that the "deleted" messages are rthe results of that.

Greetings

Matthias

Xellos

unread,
Jan 1, 2025, 8:37:27 PMJan 1
to Java Native Access
Ah, sorry for the confusion then.

Some additional info: I checked order of JUnit test execution and the leak report above appears when "find" test runs after the "dummy" tests. When "find" runs before all "dummy", the leak report corresponding to the same allocation becomes much larger e.g.

Direct leak of 1048576 byte(s) in 1 object(s) allocated from:
    #0 0x7ec3f62fb372 in malloc (/usr/lib/llvm-17/lib/clang/17/lib/linux/libclang_rt.asan-x86_64.so+0xfb372) (BuildId: 91f375f2a48c6b133a56d8cc059d017ae5de4982)
    #1 0x7ec3e1c185e6  (<unknown module>)
    #2 0x7ec3e1c07bcf  (<unknown module>)
    #3 0x7ec3e1c07bcf  (<unknown module>)
    #4 0x7ec3e1c080f5  (<unknown module>)
    #5 0x7ec3e1c07e3f  (<unknown module>)
    #6 0x7ec3e1f75ebb  (<unknown module>)
    #7 0x7ec3e1fa91ab  (<unknown module>)
    #8 0x7ec3e1c07e3f  (<unknown module>)
    #9 0x7ec3e1c07e3f  (<unknown module>)
    #10 0x7ec3e1c07f26  (<unknown module>)
    #11 0x7ec3e1c004e6  (<unknown module>)
    #12 0x7ec3f1eb2884  (/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/amd64/server/libjvm.so+0x6b2884) (BuildId: d38655f827ac6a65fdbe1898b1278717fdb89a4e)
    #13 0x7ec3f221ac0b  (/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/amd64/server/libjvm.so+0xa1ac0b) (BuildId: d38655f827ac6a65fdbe1898b1278717fdb89a4e)
    #14 0x7ec3f221c166  (/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/amd64/server/libjvm.so+0xa1c166) (BuildId: d38655f827ac6a65fdbe1898b1278717fdb89a4e)
    #15 0x7ec3f1f66e83 in JVM_InvokeMethod (/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/amd64/server/libjvm.so+0x766e83) (BuildId: d38655f827ac6a65fdbe1898b1278717fdb89a4e)
    #16 0x7ec3e1c185e6  (<unknown module>)
    #17 0x7ec3e1c07e3f  (<unknown module>)
    #18 0x7ec3e1c07e3f  (<unknown module>)
    #19 0x7ec3e1c07f26  (<unknown module>)
    #20 0x7ec3e1c07e3f  (<unknown module>)
    #21 0x7ec3e1c07e3f  (<unknown module>)
    #22 0x7ec3e1c07f26  (<unknown module>)
    #23 0x7ec3e1c07f26  (<unknown module>)
    #24 0x7ec3e1c07e3f  (<unknown module>)
    #25 0x7ec3e1c07e3f  (<unknown module>)
    #26 0x7ec3e1c0813a  (<unknown module>)
    #27 0x7ec3e1c0813a  (<unknown module>)
    #28 0x7ec3e1c07e3f  (<unknown module>)
    #29 0x7ec3e1c07f26  (<unknown module>)

and it's successfully suppressed using run_with_asan.sh. None of the many other (also suppressed, most likely false positive due to GC as you say) leak reports in the same output exhibit this behaviour with only asan and <unknown module>s for some source code and at least one known non-asan library (i.e. desired behaviour) for another source code, or at least it didn't happen in my experiments.
Reply all
Reply to author
Forward
0 new messages