Summary
Re-instrumentação do dataset de 190 APKs JCA com a imagem phtcosta/rvandroid:0.9.0 (gh56/gh57/gh58 aplicados) produz 5 APKs com java.lang.VerifyError em runtime. Causa: bug de off-by-N no binding de argumentos do callee quando o construtor casado tem parâmetros long / double (wide, 2 slots) entremeados com refs.
O trabalho de gh56 (binding-correctness, commit 3d51b410, refs #56) corrigiu offset de receiver e semântica de <init> mas não tratou contagem de slots widos no cursor de registradores de argumentos.
Reprodução
- Instrumentar
experimento-20260508/filters/experiment_apks.txt a partir dos originais em JOAO/APKs/ via docker/docker-compose.instrument-jca190.yml (imagem 0.9.0, dexlib2, JCA, skip-static/skip-execution).
- Rodar
scripts/validate_instrument_jca190.py contra emulador API 30 x86_64.
- Observar 5 / 190 com
FAIL_VERIFY — verifier rejeita <init> por registrador não-referência (Long Low Half ou Boolean) tratado como referência.
APKs afetados (FAIL_VERIFY)
| APK |
Classe |
Forma do construtor |
com.github.soundpod_16.apk |
yu5 |
25 params, 6× long intercalados; rejeita v7 (Long Low Half) |
com.grappim.taigamobile.fdroid_38.apk |
ga.e |
19 params, boolean/refs mistos; rejeita v3 (Boolean) |
com.shub39.rush_5730.apk |
— |
— |
gizz.tapes.foss_63.apk |
— |
— |
org.fossify.musicplayer_14.apk |
— |
— |
Logcats de crash preservados em out/validate_instrument_jca190/logs/<apk>.logcat.
Mensagem do verifier (amostra)
java.lang.VerifyError: Verifier rejected class yu5: void yu5.<init>(java.lang.String, mu5, java.lang.String, java.lang.String, cs0, cs0, long, long, long, ok0, int, xr, long, long, long, long, boolean, gl3, int, int, long, int, int, java.lang.String, java.lang.Boolean) failed to verify: [0xF] tried to get class from non-reference register v7 (type=Long (Low Half))
Causa raiz
PointcutMatcher.buildCallMatch (~linha 222) em rvsec-instrumentation-dexlib2/pointcut-engine/src/main/java/br/unb/cic/rv/pointcut/PointcutMatcher.java itera os paramTypes do callee e mapeia cada um para regs[baseOffset + i] — avançando o cursor de regs em exatamente 1 por parâmetro. DEX representa long e double com 2 slots contíguos, então para callees cuja lista de params contenha um wide antes do param sendo bindado, todo argBinding subsequente resolve para o registrador errado (high half do wide, ou primitivo a jusante).
O próprio arquivo já documenta a contiguidade de wide-pair (linha 244, contexto de $return/move-result-wide) mas nunca aplica a regra ao argBindings.
Fix proposto
Substituir o mapeamento por índice por um cursor de registrador que avança 2 para J/D e 1 caso contrário:
int regOffset = baseOffset;
for (int i = 0; i < paramTypes.size(); i++) {
String paramType = paramTypes.get(i);
int reg = regs[regOffset];
// bind argument i to register `reg`
regOffset += (paramType.equals("J") || paramType.equals("D")) ? 2 : 1;
}
Lacuna de teste
PointcutMatcherConstructorTest.java e DexWeaverConstructorAdviceTest.java só cobrem [B e String. Nenhum teste do INV-INS-70..73 cobre construtor com long/double interleaved com refs. A remediação deve adicionar fixture espelhando a forma de 25 params do yu5 antes do fix.
Track
Quick Path (fix mecânico single-file; sem decisões de design; bug-fix com teste de regressão).
Critérios de aceitação
- Nova fixture em
PointcutMatcherConstructorTest com pelo menos um long e um boolean intercalados com refs no callee — falha antes do fix, passa depois.
- Re-instrumentar os 190 APKs com o fix produz zero FAIL_VERIFY em
validate_instrument_jca190.py.
- Contagens de FAIL_FATAL (categoria R8/Compose) e FAIL_INSTALL não mudam (fora do escopo de gh59).
Refs
Summary
Re-instrumentação do dataset de 190 APKs JCA com a imagem
phtcosta/rvandroid:0.9.0(gh56/gh57/gh58 aplicados) produz 5 APKs comjava.lang.VerifyErrorem runtime. Causa: bug de off-by-N no binding de argumentos do callee quando o construtor casado tem parâmetroslong/double(wide, 2 slots) entremeados com refs.O trabalho de gh56 (binding-correctness, commit
3d51b410, refs #56) corrigiu offset de receiver e semântica de<init>mas não tratou contagem de slots widos no cursor de registradores de argumentos.Reprodução
experimento-20260508/filters/experiment_apks.txta partir dos originais emJOAO/APKs/viadocker/docker-compose.instrument-jca190.yml(imagem0.9.0, dexlib2, JCA, skip-static/skip-execution).scripts/validate_instrument_jca190.pycontra emulador API 30 x86_64.FAIL_VERIFY— verifier rejeita<init>por registrador não-referência (Long Low Half ou Boolean) tratado como referência.APKs afetados (FAIL_VERIFY)
com.github.soundpod_16.apkyu5longintercalados; rejeitav7(Long Low Half)com.grappim.taigamobile.fdroid_38.apkga.ev3(Boolean)com.shub39.rush_5730.apkgizz.tapes.foss_63.apkorg.fossify.musicplayer_14.apkLogcats de crash preservados em
out/validate_instrument_jca190/logs/<apk>.logcat.Mensagem do verifier (amostra)
Causa raiz
PointcutMatcher.buildCallMatch(~linha 222) emrvsec-instrumentation-dexlib2/pointcut-engine/src/main/java/br/unb/cic/rv/pointcut/PointcutMatcher.javaitera osparamTypesdo callee e mapeia cada um pararegs[baseOffset + i]— avançando o cursor deregsem exatamente 1 por parâmetro. DEX representalongedoublecom 2 slots contíguos, então para callees cuja lista de params contenha um wide antes do param sendo bindado, todoargBindingsubsequente resolve para o registrador errado (high half do wide, ou primitivo a jusante).O próprio arquivo já documenta a contiguidade de wide-pair (linha 244, contexto de
$return/move-result-wide) mas nunca aplica a regra aoargBindings.Fix proposto
Substituir o mapeamento por índice por um cursor de registrador que avança 2 para
J/De 1 caso contrário:Lacuna de teste
PointcutMatcherConstructorTest.javaeDexWeaverConstructorAdviceTest.javasó cobrem[BeString. Nenhum teste do INV-INS-70..73 cobre construtor comlong/doubleinterleaved com refs. A remediação deve adicionar fixture espelhando a forma de 25 params doyu5antes do fix.Track
Quick Path (fix mecânico single-file; sem decisões de design; bug-fix com teste de regressão).
Critérios de aceitação
PointcutMatcherConstructorTestcom pelo menos umlonge umbooleanintercalados com refs no callee — falha antes do fix, passa depois.validate_instrument_jca190.py.Refs
out/validate_instrument_jca190/install_report.csv— resultado completo da validação3d51b410, refs [Bug] dexlib2: VerifyError em constructor advice — argumentos invertidos no invoke do monitor #56) — change pai que introduziu o trabalho de constructor binding