Утечка памяти в неизвестном модуле сообщается с помощью JNA и JUnitJAVA

Программисты JAVA общаются здесь
Ответить
Anonymous
 Утечка памяти в неизвестном модуле сообщается с помощью JNA и JUnit

Сообщение Anonymous »

Это конкретная проблема, которую я обнаружил при создании MRE для моего предыдущего вопроса. Неясно, та же ли это проблема, хотя она кажется связанной, поэтому я задаю ее как отдельный вопрос.
Рассмотрим следующий тестовый класс JUnit:
Рассмотрим следующий тестовый класс JUnit:
p>

Код: Выделить всё

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 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]
Я запускаю его на Docker Ubuntu 24.04 с пакетами openjdk-8-jdk clang-17, используя Gradle, с предварительно загруженным дезинфицирующим средством адресов. JNA 5.12.1, JUnit 5.8.2, хост-система — последняя версия Arch Linux. Скрипт для его запуска:

Код: Выделить всё

echo -e "leak:libjvm\nleak:libjli\nleak:libz\nleak:liblcms\nleak:liblcms2\nleak:libjavalcms\nleak:libawt\n" >> 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
Он постоянно выдает следующий отчет об утечке:

Код: Выделить всё

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  ()
#2 0x759231607bcf  ()
#3 0x759231607bcf  ()
#4 0x7592316080f5  ()
#5 0x759231607e3f  ()
#6 0x75923197befb  ()

SUMMARY: AddressSanitizer: 1048576 byte(s) leaked in 1 allocation(s).
Это явно относится к собственной памяти, выделенной в строке 19. Поскольку экземпляр Memory должен освобождать собственную память в gc, я не думаю, что это настоящая утечка - скорее, похоже, что JNA выгружается до того, как это произойдет. Однако:
  • избавимся от ArrayList,stream и toArray и напрямую создадим Pointer[] ptrs = new Указатель[1]; ptrs[0] = new Memory(1024 * 1024); приводит к исчезновению отчета об утечке
  • уменьшение количества фиктивных тестов приводит к исчезновению отчета об утечке, в зависимости от точного количества
В моем коде собственная память malloc никогда не затрагивается, поэтому я рассматриваю возможность странного поведения, связанного с перераспределением памяти.
Изменение порядка тесты (изменяя их имена, поскольку порядок определяется JUnit) показывает, что этот отчет появляется, когда тест «найти» запускается после «фиктивных» тестов. Когда «поиск» выполняется перед всеми «фиктивными», проверка вывода без подавлений показывает другой отчет для того же распределения:

Код: Выделить всё

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  ()
#2 0x7ec3e1c07bcf  ()
#3 0x7ec3e1c07bcf  ()
#4 0x7ec3e1c080f5  ()
#5 0x7ec3e1c07e3f  ()
#6 0x7ec3e1f75ebb  ()
#7 0x7ec3e1fa91ab  ()
#8 0x7ec3e1c07e3f  ()
#9 0x7ec3e1c07e3f  ()
#10 0x7ec3e1c07f26  ()
#11 0x7ec3e1c004e6  ()
#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  ()
#17 0x7ec3e1c07e3f  ()
#18 0x7ec3e1c07e3f  ()
#19 0x7ec3e1c07f26  ()
#20 0x7ec3e1c07e3f  ()
#21 0x7ec3e1c07e3f  ()
#22 0x7ec3e1c07f26  ()
#23 0x7ec3e1c07f26  ()
#24 0x7ec3e1c07e3f  ()
#25 0x7ec3e1c07e3f  ()
#26 0x7ec3e1c0813a  ()
#27 0x7ec3e1c0813a  ()
#28 0x7ec3e1c07e3f  ()
#29 0x7ec3e1c07f26  ()
Сообщалось о многих других утечках (скорее всего, ложноположительных из-за GC), но в моих экспериментах ни одна из них никогда не проявляла такого поведения, где в зависимости от порядка тестов только asan и < появляются неизвестные модули>без какой-либо известной библиотеки Java - хотя это может быть возможно, но очень редко для других отчетов об утечках. В разных экспериментах они выделяют разное количество байтов при разном количестве выделений, но всегда сообщается хотя бы одна библиотека Java (обычно libjvm.so).
Несмотря на ASLR , в трассировке можно отслеживать одни и те же вызовы по младшим байтам адресов. В отчетах об утечках, показанных здесь, и во всех других отчетах, соответствующих одному и тому же распределению в разных экспериментах/прогонах, адреса #0–#5 всегда заканчиваются одними и теми же байтами, но для адреса #6 они различаются.
Я создал полный репозиторий, чтобы удобно воспроизвести эту ошибку, вызвав run.sh. Вся соответствующая информация и код копируются в этот вопрос.
Мой вопрос: что именно заставляет этот конкретный отчет об утечке содержать только asan и ? Чтобы внести ясность, меня не волнует, появляется ли иногда , главное, чтобы всегда была хотя бы одна известная библиотека (не asan), которую я могу использовать для подавления.

Подробнее здесь: https://stackoverflow.com/questions/793 ... -and-junit
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «JAVA»