Exemplo: fonte Java Foo.java
:
public class Foo {
public static void main(String[] args) {}
};
Eu o executo no docker do Ubuntu 24.04 com o sanitizador de endereço (contém o sanitizador de vazamento) pré-carregado, além de um interceptador para dlopen/dlclose de acordo com o problema do github . O compilador e o inicializador Java são do openjdk-8-jdk
pacote.
javac Foo.java
LD_PRELOAD="/usr/lib/llvm-17/lib/clang/17/lib/linux/libclang_rt.asan-x86_64.so:/root/libinterceptor.so" java Foo
O código do interceptador é
#define _GNU_SOURCE
#include <dlfcn.h>
#include <link.h>
#include <stdio.h>
#include <string.h>
int dlclose(void *handle) {
printf("Intercepted a dlclose call, handle %ld\n", (intptr_t)handle);
return 0;
}
void* dlopen(const char* filename, int flags){
typedef void* (*dlopen_t)(const char*, int);
dlopen_t original_dlopen = (dlopen_t)dlsym(RTLD_NEXT, "dlopen");
flags |= RTLD_NODELETE;
void *ret = original_dlopen(filename, flags);
printf("Intercepted a dlopen call for %s, handle %ld, injecting RTLD_NODELETE\n", filename, (intptr_t)ret);
return ret;
}
Muitos vazamentos de memória (falsos positivos) são relatados. Isso é bom, eles provavelmente são devidos à coleta de lixo e à incapacidade do leak sanitizer de entender o que está acontecendo lá. Não estou perguntando o que fazer com eles, sei que devo ignorá-los, pois são falsos positivos, estou usando-os para demonstrar o problema em questão. Parte da saída do erro lsan:
Direct leak of 120 byte(s) in 1 object(s) allocated from:
#0 0x7f3d1c0fb372 in malloc (/usr/lib/llvm-17/lib/clang/17/lib/linux/libclang_rt.asan-x86_64.so+0xfb372) (BuildId: 91f375f2a48c6b133a56d8cc059d017ae5de4982)
#1 0x7f3d17f8c7b4 (/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/amd64/server/libjvm.so+0x98c7b4) (BuildId: d38655f827ac6a65fdbe1898b1278717fdb89a4e)
#2 0x7f3d178d29bd (/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/amd64/server/libjvm.so+0x2d29bd) (BuildId: d38655f827ac6a65fdbe1898b1278717fdb89a4e)
#3 0x7f3d178d2a7a (/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/amd64/server/libjvm.so+0x2d2a7a) (BuildId: d38655f827ac6a65fdbe1898b1278717fdb89a4e)
#4 0x7f3d17af07a9 (/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/amd64/server/libjvm.so+0x4f07a9) (BuildId: d38655f827ac6a65fdbe1898b1278717fdb89a4e)
#5 0x7f3d17a5ac4d (/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/amd64/server/libjvm.so+0x45ac4d) (BuildId: d38655f827ac6a65fdbe1898b1278717fdb89a4e)
#6 0x7f3d17a5c3ca (/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/amd64/server/libjvm.so+0x45c3ca) (BuildId: d38655f827ac6a65fdbe1898b1278717fdb89a4e)
#7 0x7f3d17a6323a (/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/amd64/server/libjvm.so+0x46323a) (BuildId: d38655f827ac6a65fdbe1898b1278717fdb89a4e)
#8 0x7f3d180c3a34 (/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/amd64/server/libjvm.so+0xac3a34) (BuildId: d38655f827ac6a65fdbe1898b1278717fdb89a4e)
#9 0x7f3d180c4680 (/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/amd64/server/libjvm.so+0xac4680) (BuildId: d38655f827ac6a65fdbe1898b1278717fdb89a4e)
#10 0x7f3d180c64c4 (/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/amd64/server/libjvm.so+0xac64c4) (BuildId: d38655f827ac6a65fdbe1898b1278717fdb89a4e)
#11 0x7f3d17af25d7 (/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/amd64/server/libjvm.so+0x4f25d7) (BuildId: d38655f827ac6a65fdbe1898b1278717fdb89a4e)
#12 0x7f3d17af36b9 (/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/amd64/server/libjvm.so+0x4f36b9) (BuildId: d38655f827ac6a65fdbe1898b1278717fdb89a4e)
#13 0x7f3d17e59707 (/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/amd64/server/libjvm.so+0x859707) (BuildId: d38655f827ac6a65fdbe1898b1278717fdb89a4e)
#14 0x7f3d17e5b308 (/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/amd64/server/libjvm.so+0x85b308) (BuildId: d38655f827ac6a65fdbe1898b1278717fdb89a4e)
#15 0x7f3d17ca99cb (/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/amd64/server/libjvm.so+0x6a99cb) (BuildId: d38655f827ac6a65fdbe1898b1278717fdb89a4e)
#16 0x7f3d07a24dc7 (<unknown module>)
#17 0x7f3d07a080f5 (<unknown module>)
#18 0x7f3d07a004e6 (<unknown module>)
#19 0x7f3d17cb2884 (/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/amd64/server/libjvm.so+0x6b2884) (BuildId: d38655f827ac6a65fdbe1898b1278717fdb89a4e)
#20 0x7f3d17d2e75e (/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/amd64/server/libjvm.so+0x72e75e) (BuildId: d38655f827ac6a65fdbe1898b1278717fdb89a4e)
#21 0x7f3d17d2efbf (/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/amd64/server/libjvm.so+0x72efbf) (BuildId: d38655f827ac6a65fdbe1898b1278717fdb89a4e)
#22 0x7f3d1bac6c8a in JNU_NewStringPlatform (/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/amd64/libjava.so+0x1dc8a) (BuildId: 95ab745b31a25f66a623ffeaf6822cdc641c5fab)
#23 0x7f3d1babf2cb in Java_java_lang_System_initProperties (/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/amd64/libjava.so+0x162cb) (BuildId: 95ab745b31a25f66a623ffeaf6822cdc641c5fab)
#24 0x7f3d07a185e6 (<unknown module>)
#25 0x7f3d07a07e3f (<unknown module>)
#26 0x7f3d07a004e6 (<unknown module>)
#27 0x7f3d17cb2884 (/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/amd64/server/libjvm.so+0x6b2884) (BuildId: d38655f827ac6a65fdbe1898b1278717fdb89a4e)
#28 0x7f3d17cb115e (/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/amd64/server/libjvm.so+0x6b115e) (BuildId: d38655f827ac6a65fdbe1898b1278717fdb89a4e)
#29 0x7f3d17cb179f (/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/amd64/server/libjvm.so+0x6b179f) (BuildId: d38655f827ac6a65fdbe1898b1278717fdb89a4e)
Aqui está o problema: muitos desses relatórios de vazamento têm <unknown module>
s no stack trace. Minha pergunta é como transformá-los em bibliotecas conhecidas para que eu possa rastrear o que acontece. Não estou perguntando especificamente sobre Java, este é apenas um exemplo em que o encontrei - mas pode acabar sendo específico para o inicializador Java ou outros programas.
Se os <unknown module>
s foram causados por carregamento ou descarregamento dinâmico, então interceptar dlopen
ou dlclose
deve ser suficiente. No entanto, a única saída padrão que estou obtendo é
Intercepted a dlopen call for /usr/lib/jvm/java-8-openjdk-amd64/jre/lib/amd64/server/libjvm.so, handle 89747636617344, injecting RTLD_NODELETE
Intercepted a dlopen call for librt.so.1, handle 89747636681856, injecting RTLD_NODELETE
Intercepted a dlopen call for /usr/lib/jvm/java-8-openjdk-amd64/jre/lib/amd64/libverify.so, handle 89747636684928, injecting RTLD_NODELETE
Intercepted a dlopen call for /usr/lib/jvm/java-8-openjdk-amd64/jre/lib/amd64/libjava.so, handle 89747636686464, injecting RTLD_NODELETE
Intercepted a dlopen call for /usr/lib/jvm/java-8-openjdk-amd64/jre/lib/amd64/libzip.so, handle 89747636688000, injecting RTLD_NODELETE
Intercepted a dlopen call for (null), handle 139900452795104, injecting RTLD_NODELETE
Intercepted a dlopen call for /usr/lib/jvm/java-8-openjdk-amd64/jre/lib/amd64/libzip.so, handle 89747636688000, injecting RTLD_NODELETE
Intercepted a dlopen call for /usr/lib/jvm/java-8-openjdk-amd64/jre/lib/amd64/libnio.so, handle 89747636689536, injecting RTLD_NODELETE
Não há linhas dlclose e nenhum dos handles (convertidos para hexadecimal, sem contar os do programa principal para nullptr filename) correspondem ao intervalo de endereços que aparecem em <unknown module>
s - talvez algo a ver com ASLR. Mais importante, <unknown module>
s ainda aparecem na saída de erro lsan, então ou essa abordagem não consegue evitar o descarregamento, ou o problema não é causado por carregamento/descarregamento dinâmico.
Como posso descobrir quais bibliotecas correspondem a <unknown module>
s?