This is a specific issue I found while making MRE for my earlier question. It’s not clear if it’s the same issue, even though it seems related, so I’m asking it as a separate question.
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. Script to run it:
echo -e "leak:libjvmnleak:libjlinleak:libznleak:liblcmsnleak:liblcms2nleak:libjavalcmsnleak:libawtn" >> lsan.supp
export LD_PRELOAD="/usr/lib/llvm-17/lib/clang/17/lib/linux/libclang_rt.asan-x86_64.so"
export ASAN_OPTIONS="handle_segv=0"
export LSAN_OPTIONS="suppressions="$(pwd)"/lsan.supp:print_suppressions=0"
./gradlew clean 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. Since an instance of Memory
should free the native memory on gc, I don’t think it’s a real leak – rather, it looks like JNA getting unloaded before that happens. However:
- getting rid of the
ArrayList
,stream
andtoArray
and directly creatingPointer[] ptrs = new Pointer[1]; ptrs[0] = new Memory(1024 * 1024);
makes the leak report disappear - reducing the number of dummy tests makes the leak report disappear, depending on the exact number
- changing the names of the tests can make the leak report also disappear
The malloc’d native memory is never touched in my code, so I’m considering the possibility of strange behaviour related to memory overcommit.
It could also be related to order of tests determined by JUnit. That’s the only explanation I can think of why names of tests matter.
I made a full repo to conveniently reproduce this error by calling run.sh
. All relevant information and code is copied to this question.
My question here is: what exactly causes this specific leak report?