# Resultados dos testes em VM Bateria executada com `tests/vm/run_in_vm.sh` em duas distribuições, ambas em KVM (`qemu:///session`), com o código de `293e6a7`. ## Ambiente | | Debian 12 (bookworm) | Alpine 3.20.3 | |---|---|---| | Kernel | 6.1.0-54-cloud-amd64 | 6.6.49-0-virt | | libc | glibc 2.36 | **musl 1.2.5** | | gcc | 12.2.0 | 13.2.1 | | init | systemd + cloud-init | OpenRC + cloud-init | ## Resultado por item | # | Teste | Debian | Alpine | |---|---|---|---| | 1 | `autogen.sh` | passa | passa | | 1 | `configure --enable-warnings` | passa | **falha** (ver abaixo) | | 1 | `make -j` | passa, **0 warnings** | não alcançado | | 2 | `mkreiserfs` | passa | não alcançado | | 3 | `reiserfsck --check` | passa | não alcançado | | 4 | `debugreiserfs -S` | passa | não alcançado | | 5 | `reiserfstune -l` | passa | não alcançado | | 6 | `resize_reiserfs` 128→256 MiB | passa | não alcançado | | 7 | `fsck` pós-resize | passa | não alcançado | | 8 | rollback: grava | passa | não alcançado | | 8 | rollback: restaura | passa | não alcançado | | 8 | rollback: magic inválida rejeitada | passa | não alcançado | | 8 | rollback: arquivo inexistente rejeitado | passa | não alcançado | **Debian: 12/12.** Alpine: bloqueado no item 1. ## Achado 1 (bloqueante): não compila em musl O `configure` do Alpine falha com: ``` checking for register_printf_modifier... no checking for register_printf_specifier... no configure: error: reiserfsprogs requires a method to add printf modifiers ``` Causa: `reiserfscore/prints.c` usa `register_printf_specifier(3)`, extensão **glibc-only** (``). O musl não fornece `printf.h` nem essas funções. O `configure.ac` trata isso como erro fatal explícito — o comportamento é correto, mas o projeto **não compila fora da glibc**. Alcance medido: | Especificador | Uso | |---|---| | `%k` | 139 | | `%K` | 106 | | `%H` | 52 | | `%M` | 25 | | `%b` | 9 | | `%U` | 4 | | `%y` | 2 | | `%30H`, `%20y`, `%20k`, `%20K` | 4 | | **total** | **341** | Todos passam por `reiserfs_warning()` / `reiserfs_info()`. Portar exigiria substituir o mecanismo por funções de formatação explícitas (por exemplo `char *format_key(const struct reiserfs_key *)` com `%s`), uma mudança de API interna ampla — não um ajuste local. **Impacto prático**: reiserfsprogs fica restrito à glibc. Como o único uso atual da ferramenta é resgate de dados, isso importa: live images de recuperação baseadas em Alpine/musl não conseguem compilar o projeto. ## Achado 2 (corrigido nesta rodada): warning real no gcc 12 O gcc 12.2 do Debian acusou, duas vezes: ``` ../include/reiserfs_fs.h:63:54: warning: ‘relocated_ih’ may be used uninitialized ``` O gcc 16 do host não acusa. Investigação: * `fsck/semantic_check.c:620` passa `&relocated_ih` para `check_semantic_pass()`; * o bloco que escreveria `*new_ih` está **comentado** (linhas 471–486); * a chamada em `check_check_regular_file()` (linha 466) passa `NULL` como `new_ih`, com o comentário `/* relocate ? new_ih : */ NULL`; * portanto `RELOCATED` nunca é retornado por esse caminho e `case RELOCATED:` (linha 665) leria `relocated_ih` não inicializado. Não é alcançável hoje, mas é uma leitura potencial de lixo de pilha atrás de um `#case` que o compilador não consegue descartar. Correção: inicialização explícita `= { 0 }` com comentário explicando por que permanece zero. Verificado: **0 warnings no gcc 12.2 após a correção**. Em `fsck/semantic_rebuild.c` o caminho equivalente é seguro: o bloco `if (relocate) { ... *new_ih = *ih; retval = RELOCATED; }` está ativo (linhas 808–822), então `new_ih` é escrito antes do `case RELOCATED:` (linha 999). ## Validação com clang Ferramentaria: Fedora 44 (host) com **clang 22.1.8**, Debian 12 na VM com **clang 14.0.6**. Todos os builds abaixo usam `--enable-warnings` (-Wall -Wextra). | Build | Resultado | |---|---| | host clang in-tree, -j | 0/5 falhas, **0 warnings** | | host clang out-of-tree, -j | passa, 0 warnings | | host clang + ASan/UBSan out-of-tree, -j | 0/3 falhas, 0 warnings | | host gcc out-of-tree, -j | 3/3 limpo | | host `make distcheck` | passa (VPATH + install/uninstall + tarballs) | | VM Debian clang 14.0.6, bateria completa | **12/12, 0 warnings** | ### O que clang expôs (e foi corrigido) 1. **Corrida de build paralela em `compile_et`** (`reiserfscore/Makefile.am`): `reiserfs_err.c` e `reiserfs_err.h` eram alvos de UMA mesma receita; com `-j` o make executa a receita duas vezes em paralelo e um processo apaga o `.c` enquanto o outro compila → `clang: error: no input files`. Reproduzido com clang+ASan; a correção vale para qualquer compilador. A receita ficou atrelada apenas a `reiserfs_err.c`, e `reiserfs_err.h: reiserfs_err.c` apenas ordena os dois. 5/5 builds paralelos limpos após a correção. 2. **Build out-of-tree quebrado** (pré-existente, também com gcc): a regra referenciava `reiserfs_err.et` sem `$(srcdir)/`. Corrigido junto. 3. **`-Waddress-of-packed-member`** (só o clang aponta; 3 sítios): `fsck/semantic_check.c` e `fsck/semantic_rebuild.c` passavam `&tmp_deh->deh2_dir_id` como argumento `%K`, que espera `struct reiserfs_key *`. Funcionava por coincidência de offsets (`deh2_dir_id` em 4 lido como `k2_dir_id` em 0 do cast). Agora montam uma `reiserfs_key` local via `set_key_dirid`/`set_key_objectid` — saída idêntica, sem depender de coincidência. 4. **`-Wnull-dereference` em `reiserfscore/hashes.c`**: quatro stores mortos `*(int *)0 = 0` protegidos por condições inalcançáveis (após o loop `while (len >= 16)`, `len <= 15`; os ramos testavam `len >= 16/12/8/4`). Removidos. Comportamento verificado: saída de `keyed_hash`, `yura_hash` e `r5_hash` para 16 entradas (vazio a 17 bytes) **byte a byte idêntica** antes e depois (diff vazio). 5. **heap-use-after-free real, encontrado por ASan com clang**: `reiserfs_close()` chamava `fsync(fs->fs_dev)` DEPOIS de `reiserfs_free()` liberar `fs` — leitura pendente de 4 bytes em memória libertada (o ASan apontou exatamente `reiserfslib.c:406/407`; o gcc nunca acusou porque o heap ainda "devolve" o valor velho). Corrigido movendo o `fsync` para antes do free — a escrita já está no dispositivo neste ponto (`reiserfs_flush()` despeja journal e buffers; os `free_buffers()` de `reiserfs_free()` apenas validam e libertam, sem escrever). 6. **segundo heap-use-after-free, também no caminho de rollback** (`fsck/main.c:1313`, `fsck_rollback()`): a função fazia `freemem(fs)` e depois imprimia o banner final via `fsck_progress(...)`, que desreferencia `fs` (`fsck_data(fs)` etc.). Capturado por ASan em uma reexecução explícita do `--rollback-fsck-changes` com `halt_on_error` (a rodada inicial de smoke não exercitou esse ramo até o fim). Corrigido: o banner é impresso antes da limpeza, na mesma ordem usada por `the_end()` e pelos caminhos de rebuild. Revalidado: save, restore, rejeição de magic inválida e resize sob ASan+UBSan com `halt_on_error=1` — **zero erros**, saída funcional inalterada. Ambos os builds saneados (mkfs, check, tune, debugreiserfs, resize 64→128 MiB e rollback completo) passam com **zero erros**; a bateria completa no host gcc continua 12/12. ### Não-bugs registrados - LeakSanitizer: 136 bytes, 1 alocação em `debugreiserfs` (`getmem` no `main`, de vida de processo; o `exit` recolhe). Aceitável para ferramenta one-shot; por isso o job de CI com sanitizadores roda com `detect_leaks=0`. - `AddressSanitizer: WARNING: unexpected format specifier ... %U`: o interceptor do ASan não conhece os especificadores customizados do projeto. Informativo, uma vez por processo. ## Achado 3: limitação do ambiente (não do código) Nas imagens cloud o `cloud-init` não aplicou a senha do usuário: o datasource NoCloud exige o rótulo `cidata` e o CD correto, e o `sshd` demora a subir. O console serial, porém, fica disponível assim que o getty sobe — por isso o `tests/vm/guestcmd.py` dirige o pty e é o canal de automação usado. Isso não afeta o produto; afeta apenas como os testes são conduzidos. Além disso, a rede user-mode (`passt`) não entrega DHCP nem DNS por padrão: a interface sobe como `enp1s0` mas fica sem IP. Foi necessário configurar IP e resolver manualmente para instalar pacotes nas VMs. ## Como reproduzir ```sh cd tests/vm ./setup_env.sh # imagens + VMs (uma vez) ./run_in_vm.sh rfs-debian # gcc: build + bateria completa CC=clang ./run_in_vm.sh rfs-debian # clang no guest (instalar antes: ver README) ./run_in_vm.sh rfs-alpine # deve falhar no configure (esperado) ./teardown_env.sh # host: builds paralelos in-tree e out-of-tree, distcheck make distcheck CC=clang ./configure --enable-warnings && make -j"$(nproc)" ``` Detalhes do ambiente, topologia e limitações: `tests/vm/README.md`.