░░░                              ░░░             ▀▄
                       ▄ ▀▀▄              ░░░                                   ■  ▒          ░░░
                     ▄      ▒        ▄▄                ▒    ▄▀       ▒         ▄  ▀▄▄
                     ▄▄             ▄                ▄█    █       ▄▀           ▄█▀▀▀     ▀▀ ▄
                      ▀▄▀█▄▄▄▄▄▄██▀ ▀▄▀███▄▄▄      ▄▄█▄▄▄ █▄▄▄   ▄▀▄▄▀  ▄▄▄▄▄    ▀▄▀ ▒    ▄▄▄▄▀
                      ▀▀▄▄  █▄▀▀▄     ▄▀ ▄▄ ▀▄   ▄▀▄▀▀▀▀▄  ▀▄▀▀▄██▀█   █▀▌  ▐▄          ▄█▀▀▀▀▄▄
                            █▀ ▄▄ ▒   ░░   █ █▀ ▄▄▀ ■▀ ▀▄  ▒ ▀▄▀▄▀ █  ▀▄    ██▄  ▓     ▄█ ▄▀▀ ██▀▄
           ▄              ▒ ██   ▄    ▓▓   ▒ █▄ ██ █   ██  █▄  ▀  ▀▒  ██   ▐▌██  █ ▒   ▄█ ▓   ██            ▄
             ▀            ▒ ▀█     ▄  ██     █  ░░ ▒   ▓▓  █▄     ██  ▓▓   █ ░█  ▄ ▄   ██ ▒   ▀▄          ▀
            ▀▄            ▓ ▓█      ▀▀█▀▄▄▄▄▀   ▒▒     ░░▀ ▒▒ ░   ▒▒  ░░  ▐▌ ██  █ ▒   ▀▀ ▄▄▄▄▄ ▄         ▄▀
           ░█▀            █ █▓      ▒ ▓ ▀▀▄    ▄▄▄▄▄▓▓▀▄█  ░▓ ▒   ▓░▐ █▓  ▓  ▌▓  ░▒░ ▄▀██  ▄▄▄▀▀          ▀█░
           ▄╬▄            ▓ ▓▒      █ █▓   ▀▒▄  ▀░▀▀   █▓  ▓█ █   █▓  ▓█ ▐▌  ▓▓  ▓▓█ ▄▀█▓     ▄█ ▒        ▄╬▄
      ,    ▌█▌    ,       ▓ ░▀      ░ ▓█  ▀  ▀░░▄▄     ░▓  █▓ █   ▒█▐ ▌▓ █   ▌▒  █▓█   ░█ ▒   █▓ █   ,    ▐█▐    ,
      ▄ ▄ ═▌█▌═ ▄ ▄  ░░▀▀▀▀ ██      ░ █▒    ▀▄ ▀▓░░░▄▄ █░  ▓░ ▓   ▀█▐ █░▐▌   ▌█  ░░░   ▀░ ▓   ░█ ▀   ▄ ▄ ═▐█▐═ ▄ ▄ 
       ▀▀█▓▄▓█▓█▀▀    ▀▄ ▀░░░░   ▒  ▀▄▓▀▒     █  █▓▄▀▀▀░▄▀░░█ █   ░░█▀▀▓█    █   ░▓█ ▀▄▓█ ▓   ░  ▄▄   ▀▀█▓█▓▄▓█▀▀  
           ▀▓▄%         ▀  ▀▄     ▀░░▀ ▄    ▄▀  ▄▀     █▀  ▀█ ▓   ░▀▄▄  ▀ ▄▄▀   ▒▀ █▄  ▀█ █   ▓▄▀  ▀     %▄▓▀      
   ▒      •▀▒             ▀▄        ▄▄▀    ▒  ▄▀          ▀▄  ▓   ▄▀   ▀ ▄▄  ▀    ▄▀  ■▄  ░   ▀            ▒▀•      ▒   
 ▄▀▀▀▀▄▄▄█▄▄▒                ■                ░     ▒        ▀█         ■       ▄▀      ▀▄░                ▒▄▄█▄▄▄▀▀▀▀▄ 
 ░ ░  •▀                                       ▀ ▄▄▀                           ▒          ▀                     ▀•  ░ ░ 
 █ ▒▄▀                                                                               [ Arte por L.Ayres ]         ▀▄▒ █ 
 █ ▒                                                                                                                ▒ █
 █ █                                                                                                                █ █
 █ ▒        usando zig para buildar e instrumentar programas em c e c++                                             ▒ █
 █▒▒        gbrls                                                                                                   ▒▒█
 █ ▒                                                                                                                ▒ █
 █ █        import "base.typ": base                                                                                 █ █
 █ ▒                                                                                                                ▒ █
 █▒▒        show: base                                                                                              ▒▒█
 █ ▒                                                                                                                ▒ █
 █ █        Zig é uma liguagem de programação e toolchain publicada inicialmente em 2016 por Andrew                 █ █
 █ ▒        Kelly.                                                                                                  ▒ █
 █▒▒                                                                                                                ▒▒█
 █ ▒        A linguagem em si parece mais com C e Go do que C++ e Rust, principalmente por                          ▒ █
 █ █        causa do seu minimalismo.                                                                               █ █
 █▒▒ ¡                                                                                                              ▒▒█
 █ ▒,█▄     A Zig Software Fundation (ZSF) foi criada para manter o Zig, ela segue uma                              ▒ █
 █ █▀▀°     estrutura de uma empresa sem fins lucrativos, da mesma forma que a wikipedia                            █ █
 █▒▒        por exemplo.                                                                                            ▒▒█
 █ ▒                                                                                                                ▒ █
 █ █        Na homepage do projeto Zig, um dos primeiros pontos é:                                                  █ █
 █ ▒                                                                                                                ▒ █
 █▒▒        > "Melhore incrementalmente sua codebase em C/C++/Zig"                                                  ▒▒█
 █ ▒                                                                                                                ▒ █
 █ █        Esse foi um ponto que me deixou surpreso e ate agora tem trazido muitas ideias                          █ █
 █ ▒        de como usar Zig como mais uma ferramenta para diversao e lucro!                                        ▒ █
 █▒▒                                                                                                                ▒▒█
 █ ▒        Um aviso importante é que Zig ainda não foi estabilizada, ou seja, cada release                         ▒ █
 █ █        pode ter grandes mudancas na linguagem, no sistema de build, na lib std, etc.                           █ █
 █ ▒                                                                                                                ▒ █
 █▒▒        ---                                                                                                   ¡ ▒▒█
 █ ▒                                                                                                             ▄█,▒ █
 █ █        Vamos ver esse programa simples  em C que tem um bug de _Use After Free_ (UAF).                      °▀▀█ █
 █▒▒                                                                                                                ▒▒█
 █ ▒        // main.c                                                                                               ▒ █
 █ █        #include <stdio.h>                                                                                      █ █
 █ ▒        #include <inttypes.h>                                                                                   ▒ █
 █▒▒        #include <stdlib.h>                                                                                     ▒▒█
 █ ▒                                                                                                                ▒ █
 █ █        void print(uint8_t* ptr) {                                                                              █ █
 █ ▒            for(int i = 0; i < 8; i++)                                                                          ▒ █
 █▒▒                printf("%x ", ptr[i]);                                                                          ▒▒█
 █ ▒                                                                                                                ▒ █
 █ █            putchar('\n');                                                                                      █ █
 █ ▒        }                                                                                                       ▒ █
 █▒▒ ¡                                                                                                              ▒▒█
 █ ▒,█▄     int main(void) {                                                                                        ▒ █
 █ █▀▀°         uint8_t* p = malloc(100);                                                                           █ █
 █▒▒            free(p);                                                                                            ▒▒█
 █ ▒            print(p);                                                                                           ▒ █
 █ █                                                                                                                █ █
 █ ▒            return 0;                                                                                           ▒ █
 █▒▒        }                                                                                                       ▒▒█
 █ ▒                                                                                                                ▒ █
 █ █                                                                                                                █ █
 █ ▒        Existem diversas formas que poderiamos instrumentar ele para detectar este bug                          ▒ █
 █▒▒        durante a execução do programa. Aqui vou presentar mais uma forma.                                      ▒▒█
 █ ▒                                                                                                                ▒ █
 █ █        O script build.zig vai configurar o processo de build desse programa (o                                 █ █
 █ ▒        compilador de zig compila C e C++ com clang):                                                           ▒ █
 █▒▒                                                                                                              ¡ ▒▒█
 █ ▒        Obs: Para entender melhor como funciona o build, você pode em uma pasta vazia                        ▄█,▒ █
 █ █        rodar zig init, um build.zig vai ser gerado com comentarios uteis, e depois                          °▀▀█ █
 █▒▒        disso o melhor material é o proprio codigo fonte do std.Build.                                          ▒▒█
 █ ▒                                                                                                                ▒ █
 █ █        Com o arquivo abaixo o que efetivamente estamos fazendo é usando o build.zig                            █ █
 █ ▒        como um sistema de build para um programa todo em C:                                                    ▒ █
 █▒▒                                                                                                                ▒▒█
 █ ▒        ┌─────────┐ zig cc  ┌──────┐                                                                            ▒ █
 █ █        │build.zig --------> main.c│                                                                            █ █
 █ ▒        └─────────┘         └──────┘                                                                            ▒ █
 █▒▒                                                                                                                ▒▒█
 █ ▒        // build.zig                                                                                            ▒ █
 █ █        const std = @import("std");                                                                             █ █
 █ ▒                                                                                                                ▒ █
 █▒▒ ¡      pub fn build(b: *std.Build) void {                                                                      ▒▒█
 █ ▒,█▄         const target = b.standardTargetOptions(.{});                                                        ▒ █
 █ █▀▀°         const optimize = b.standardOptimizeOption(.{});                                                     █ █
 █▒▒                                                                                                                ▒▒█
 █ ▒            const exe = b.addExecutable(.{                                                                      ▒ █
 █ █                .name = "main",                                                                                 █ █
 █ ▒                .root_module = b.createModule(.{                                                                ▒ █
 █▒▒                    .target = target,                                                                           ▒▒█
 █ ▒                    .optimize = optimize,                                                                       ▒ █
 █ █                }),                                                                                             █ █
 █ ▒            });                                                                                                 ▒ █
 █▒▒                                                                                                                ▒▒█
 █ ▒            exe.addCSourceFile(.{                                                                               ▒ █
 █ █                .file = b.path("main.c"),                                                                       █ █
 █ ▒                .flags = &.{},                                                                                  ▒ █
 █▒▒            });                                                                                               ¡ ▒▒█
 █ ▒                                                                                                             ▄█,▒ █
 █ █            exe.linkLibC();                                                                                  °▀▀█ █
 █▒▒                                                                                                                ▒▒█
 █ ▒            b.installArtifact(exe);                                                                             ▒ █
 █ █            const run_exe = b.addRunArtifact(exe);                                                              █ █
 █ ▒            const run_step = b.step("run", "run the main.c");                                                   ▒ █
 █▒▒                                                                                                                ▒▒█
 █ ▒            run_step.dependOn(&run_exe.step);                                                                   ▒ █
 █ █        }                                                                                                       █ █
 █ ▒                                                                                                                ▒ █
 █▒▒                                                                                                                ▒▒█
 █ ▒        Podemos rodar esse programa com zig build run.                                                          ▒ █
 █ █        Agora, vamos adicionar a instrumencação, criando um arquivo hooks.zig e                                 █ █
 █ ▒        editando o build.zig.                                                                                   ▒ █
 █▒▒ ¡                                                                                                              ▒▒█
 █ ▒,█▄     // build.zig                                                                                            ▒ █
 █ █▀▀°     const lib = b.addLibrary(.{                                                                             █ █
 █▒▒            .linkage = .static,                                                                                 ▒▒█
 █ ▒            .name = "ziglib",                                                                                   ▒ █
 █ █            .root_module = b.createModule(.{                                                                    █ █
 █ ▒                .root_source_file = b.path("hooks.zig"),                                                        ▒ █
 █▒▒                .target = target,                                                                               ▒▒█
 █ ▒                .optimize = optimize,                                                                           ▒ █
 █ █            }),                                                                                                 █ █
 █ ▒        });                                                                                                     ▒ █
 █▒▒        lib.linkLibC();                                                                                         ▒▒█
 █ ▒                                                                                                                ▒ █
 █ █        // ...                                                                                                  █ █
 █ ▒                                                                                                                ▒ █
 █▒▒        exe.addCSourceFile(.{                                                                                 ¡ ▒▒█
 █ ▒            .file = b.path("main.c"),                                                                        ▄█,▒ █
 █ █            .flags = &.{},                                                                                   °▀▀█ █
 █▒▒        });                                                                                                     ▒▒█
 █ ▒                                                                                                                ▒ █
 █ █        exe.linkLibrary(lib); // é importante que a lib em zig seja linkada antes da libc                       █ █
 █ ▒        exe.linkLibC();                                                                                         ▒ █
 █▒▒                                                                                                                ▒▒█
 █ ▒                                                                                                                ▒ █
 █ █        E o arquivo com a instrumentação:                                                                       █ █
 █ ▒                                                                                                                ▒ █
 █▒▒        // hooks.zig                                                                                            ▒▒█
 █ ▒                                                                                                                ▒ █
 █ █        const std = @import("std");                                                                             █ █
 █ ▒        const dlsym = std.c.dlsym;                                                                              ▒ █
 █▒▒ ¡                                                                                                              ▒▒█
 █ ▒,█▄     fn getFn(name: [*:0]const u8, T: type) T {                                                              ▒ █
 █ █▀▀°         const ptr = dlsym(@ptrFromInt(std.math.maxInt(usize)), name);                                       █ █
 █▒▒            const fnp: T = @ptrCast(ptr);                                                                       ▒▒█
 █ ▒            return fnp;                                                                                         ▒ █
 █ █        }                                                                                                       █ █
 █ ▒                                                                                                                ▒ █
 █▒▒        export fn malloc(in: usize) callconv(.c) ?*anyopaque {                                                  ▒▒█
 █ ▒            const fnp = getFn("malloc", *const fn (usize) callconv(.c) ?*anyopaque);                            ▒ █
 █ █            const memPtr = fnp(in);                                                                             █ █
 █ ▒            if (memPtr != zero) {                                                                               ▒ █
 █▒▒                std.debug.print("(~) [trace] malloc(bytes: 0x{x}) -> 0x{x}\n", .{ in,                           ▒▒█
 █ ▒        @intFromPtr(memPtr) }); };                                                                              ▒ █
 █ █            } else {                                                                                            █ █
 █ ▒                std.debug.print("malloc returned null\n", .{});                                                 ▒ █
 █▒▒            }                                                                                                 ¡ ▒▒█
 █ ▒        }                                                                                                    ▄█,▒ █
 █ █                                                                                                             °▀▀█ █
 █▒▒                                                                                                                ▒▒█
 █ ▒        Agora rodando normalmente com zig build run a nossa função de malloc no                                 ▒ █
 █ █        hooks.zig vai ser utilizada ao inves do malloc da libc, mas por causa do                                █ █
 █ ▒        dlsym [1] podemos chamar o malloc original. Esse tipo de instrumentação                                 ▒ █
 █▒▒        funciona porque estamos usando dynamic linking, por isso podemos ter o mesmo                            ▒▒█
 █ ▒        simbolo definido em secoes diferentes.                                                                  ▒ █
 █ █                                                                                                                █ █
 █ ▒        Outra alternativa seria exportar a partir dos hooks a função com outro nome como                        ▒ █
 █▒▒        zmalloc e no build adicionar uma macro para renomear o malloc. A ideia disso veio daqui                 ▒▒█
 █ ▒        [2].                                                                                                    ▒ █
 █ █                                                                                                                █ █
 █ ▒        // build.zig                                                                                            ▒ █
 █▒▒ ¡      const mod = b.createModule(.{                                                                           ▒▒█
 █ ▒,█▄         .target = target,                                                                                   ▒ █
 █ █▀▀°         .optimize = optimize,                                                                               █ █
 █▒▒        });                                                                                                     ▒▒█
 █ ▒        mod.addCMacro("malloc", "zmalloc");                                                                     ▒ █
 █ █        const exe = b.addExecutable(.{                                                                          █ █
 █ ▒            .name = "main",                                                                                     ▒ █
 █▒▒            .root_module = mod,                                                                                 ▒▒█
 █ ▒            .linkage = .static, // dessa forma o programa final pode ser estaticamente linkado                  ▒ █
 █ █        });                                                                                                     █ █
 █ ▒                                                                                                                ▒ █
 █▒▒                                                                                                                ▒▒█
 █ ▒        Mas quando linkar estaticamente, vamos perder o malloc original que antes podia                         ▒ █
 █ █        ser acessado com dlsym. Apesar disso, essa forma permite que o binario final seja                       █ █
 █ ▒        totalmente estaticamente linkado, o que desbloqueia algumas aplicacoes interessantes.                   ▒ █
 █▒▒                                                                                                              ¡ ▒▒█
 █ ▒        // hooks.zig                                                                                         ▄█,▒ █
 █ █        export fn zmalloc(sz: usize) ?*anyopaque {                                                           °▀▀█ █
 █▒▒            std.debug.print("malloc called! {x}\n", .{sz});                                                     ▒▒█
 █ ▒            return null;                                                                                        ▒ █
 █ █        }                                                                                                       █ █
 █ ▒                                                                                                                ▒ █
 █▒▒                                                                                                                ▒▒█
 █ ▒        Podemos tambem adicionar hooks que vao rodar no inicio e no final da execução do                        ▒ █
 █ █        programa. Note que esses hooks do .init_array e .fini_array (na versao atual                            █ █
 █ ▒        do zig, 0.15.2) somente sao incluidos se tiver alguma função do hooks.zig que                           ▒ █
 █▒▒        vai ser utilizada pelo programa C, com o malloc hookado. Valeu R3tr074 por                              ▒▒█
 █ ▒        ter apresentado essa tecnica no feedback da primeira versao do artigo.                                  ▒ █
 █ █                                                                                                                █ █
 █ ▒        // hooks.zig                                                                                            ▒ █
 █▒▒ ¡      export const init_array linksection(".init_array") = [_]*const fn () callconv(.c)                       ▒▒█
 █ ▒,█▄     void{&zig_init};                                                                                        ▒ █
 █ █▀▀°     export const fini_array linksection(".fini_array") = [_]*const fn () callconv(.c)                       █ █
 █▒▒        void{&zig_fini};                                                                                        ▒▒█
 █ ▒                                                                                                                ▒ █
 █ █        fn zig_init() callconv(.c) void {                                                                       █ █
 █ ▒            // ...                                                                                              ▒ █
 █▒▒        }                                                                                                       ▒▒█
 █ ▒                                                                                                                ▒ █
 █ █        fn zig_fini() callconv(.c) void {                                                                       █ █
 █ ▒            // ...                                                                                              ▒ █
 █▒▒        }                                                                                                       ▒▒█
 █ ▒                                                                                                                ▒ █
 █ █                                                                                                                █ █
 █ ▒        Voltando ao problema inicial de instrumentar o alocador, podemos usar eles para                         ▒ █
 █▒▒        substituir o alocador da libc por qualquer outro, nesse caso vou mostrar usando                       ¡ ▒▒█
 █ ▒        um alocador builtin do zig que tem funcionalidades para detectar leaks e limpa a                     ▄█,▒ █
 █ █        memoria alocada para 0xaaaaaaaa... em todo free.                                                     °▀▀█ █
 █▒▒                                                                                                                ▒▒█
 █ ▒        Tambem vamos adicionar um hashmap para acompanhar as alocacoes                                          ▒ █
 █ █                                                                                                                █ █
 █ ▒        // hooks.zig                                                                                            ▒ █
 █▒▒        // ...                                                                                                  ▒▒█
 █ ▒        var gpa = std.heap.DebugAllocator(.{}){};                                                               ▒ █
 █ █        const alloc = gpa.allocator();                                                                          █ █
 █ ▒                                                                                                                ▒ █
 █▒▒        const AllocationMap = std.AutoHashMap(usize, usize);                                                    ▒▒█
 █ ▒        var allocations: AllocationMap = undefined;                                                             ▒ █
 █ █        var allocations_mutex: std.Thread.Mutex = .{};                                                          █ █
 █ ▒                                                                                                                ▒ █
 █▒▒ ¡      fn zig_init() callconv(.c) void {                                                                       ▒▒█
 █ ▒,█▄         allocations = AllocationMap.init(gpa);                                                              ▒ █
 █ █▀▀°     }                                                                                                       █ █
 █▒▒                                                                                                                ▒▒█
 █ ▒        // ...                                                                                                  ▒ █
 █ █        export fn malloc(in: usize) callconv(.c) ?*anyopaque {                                                  █ █
 █ ▒        // ...                                                                                                  ▒ █
 █▒▒            const slice = alloc.alloc(u8, in) catch {                                                           ▒▒█
 █ ▒                @panic("Failed to allocate");                                                                   ▒ █
 █ █            };                                                                                                  █ █
 █ ▒            // ...                                                                                              ▒ █
 █▒▒                                                                                                                ▒▒█
 █ ▒            allocations_mutex.lock();                                                                           ▒ █
 █ █            defer allocations_mutex.unlock();                                                                   █ █
 █ ▒                                                                                                                ▒ █
 █▒▒            allocations.put(@intFromPtr(slice.ptr), size) catch {                                             ¡ ▒▒█
 █ ▒                gpa.free(slice);                                                                             ▄█,▒ █
 █ █                return null;                                                                                 °▀▀█ █
 █▒▒            };                                                                                                  ▒▒█
 █ ▒            return @ptrCast(slice.ptr);                                                                         ▒ █
 █ █        }                                                                                                       █ █
 █ ▒                                                                                                                ▒ █
 █▒▒        export fn free(ptr: ?*anyopaque) callconv(.c) void {                                                    ▒▒█
 █ ▒            // ...                                                                                              ▒ █
 █ █            allocations_mutex.lock();                                                                           █ █
 █ ▒            defer allocations_mutex.unlock();                                                                   ▒ █
 █▒▒                                                                                                                ▒▒█
 █ ▒            const ptrVal: usize = @intFromPtr(ptr);                                                             ▒ █
 █ █                                                                                                                █ █
 █ ▒            if (allocations.get(ptrVal)) |size| {                                                               ▒ █
 █▒▒ ¡              const slice: []u8 = @as([*]u8, @ptrCast(ptr))[0..size]; // esse cast é necessario               ▒▒█
 █ ▒,█▄     porque esse alocador retornou um slice, ao inves de um ponteiro cru.                                    ▒ █
 █ █▀▀°             alloc.free(slice);                                                                              █ █
 █▒▒                _ = allocations.remove(ptrVal);                                                                 ▒▒█
 █ ▒            }                                                                                                   ▒ █
 █ █        }                                                                                                       █ █
 █ ▒                                                                                                                ▒ █
 █▒▒        // ...                                                                                                  ▒▒█
 █ ▒                                                                                                                ▒ █
 █ █        fn zig_fini() callconv(.c) void {                                                                       █ █
 █ ▒            std.debug.print("\n===== [fini hook]\n", .{});                                                      ▒ █
 █▒▒                                                                                                                ▒▒█
 █ ▒            // ...                                                                                              ▒ █
 █ █            allocations.deinit(); // Se não liberar aqui, essa memoria vai contar como vazada pelo              █ █
 █ ▒        alocador.                                                                                               ▒ █
 █▒▒            std.debug.print("leaks: {any}\n", .{gpa.detectLeaks()});                                          ¡ ▒▒█
 █ ▒        }                                                                                                    ▄█,▒ █
 █ █                                                                                                             °▀▀█ █
 █▒▒                                                                                                                ▒▒█
 █ ▒        Agora alterando o main.c para não dar free                                                              ▒ █
 █ █                                                                                                                █ █
 █ ▒        int main(void) {                                                                                        ▒ █
 █▒▒            uint8_t* p = malloc(100);                                                                           ▒▒█
 █ ▒            // free(p);                                                                                         ▒ █
 █ █                                                                                                                █ █
 █ ▒            return 0;                                                                                           ▒ █
 █▒▒        }                                                                                                       ▒▒█
 █ ▒                                                                                                                ▒ █
 █ █                                                                                                                █ █
 █ ▒        Quando rodar o programa vamos ter:                                                                      ▒ █
 █▒▒ ¡                                                                                                              ▒▒█
 █ ▒,█▄     [init hook]                                                                                             ▒ █
 █ █▀▀°     (~) [trace] malloc(bytes: 0x64) -> 7fb8701e0000                                                         █ █
 █▒▒                                                                                                                ▒▒█
 █ ▒        ===== [fini hook]                                                                                       ▒ █
 █ █        error(gpa): memory address 0x7fb8701e0000 leaked:                                                       █ █
 █ ▒        .../hooks.zig:49:38: 0x1130425 in malloc (hooks.zig)                                                    ▒ █
 █▒▒                    const slice = alloc.alloc(u8, in) catch {                                                   ▒▒█
 █ ▒                                             ^                                                                  ▒ █
 █ █        .../main.c:13:18: 0x1025cc8 in main (.../main.c)                                                        █ █
 █ ▒            uint8_t* p = malloc(100);                                                                           ▒ █
 █▒▒                         ^                                                                                      ▒▒█
 █ ▒        ???:?:?: 0x7fb87020d5b4 in ??? (libc.so.6)                                                              ▒ █
 █ █        ???:?:?: 0x7fb87020d667 in ??? (libc.so.6)                                                              █ █
 █ ▒        ???:?:?: 0x1025b94 in ??? (???)                                                                         ▒ █
 █▒▒                                                                                                              ¡ ▒▒█
 █ ▒        leaks: true                                                                                          ▄█,▒ █
 █ █                                                                                                             °▀▀█ █
 █▒▒                                                                                                                ▒▒█
 █ ▒        O alocador mostra onde foi alocada a memoria que vazou e ate o stack trace                              ▒ █
 █ █        mostrando o source de Zig e C! Para entender como essas funcionalidades foram                           █ █
 █ ▒        implementadas o source é bem organizado e legivel [3], mesmo que você não tenha                         ▒ █
 █▒▒        familiaridade com Zig [4][5][6].                                                                        ▒▒█
 █ ▒                                                                                                                ▒ █
 █ █        Aqui no final, é o codigo inteiro do hook.zig para o programa C dinamicamente                           █ █
 █ ▒        linkado com algumas funcionalidades extras, como mostrando o stacktrace em toda                         ▒ █
 █▒▒        call de free e malloc.                                                                                  ▒▒█
 █ ▒                                                                                                                ▒ █
 █ █        const std = @impor et("std");                                                                           █ █
 █ ▒        const dlsym = st alocada para 0xaaaaaaaa...d.c.dlsym;                                                   ▒ █
 █▒▒ ¡                                                                                                              ▒▒█
 █ ▒,█▄     var gpa = std.heap.DebugAllocator(.{}){};                                                               ▒ █
 █ █▀▀°     const alloc = gpa.allocator();                                                                          █ █
 █▒▒                                                                                                                ▒▒█
 █ ▒        const use_libc_alloc = false;                                                                           ▒ █
 █ █        const verbose = false;                                                                                  █ █
 █ ▒                                                                                                                ▒ █
 █▒▒        const AllocationMap = std.AutoHashMap(usize, usize);                                                    ▒▒█
 █ ▒        var allocations: AllocationMap = undefined;                                                             ▒ █
 █ █        var allocations_mutex: std.Thread.Mutex = .{};                                                          █ █
 █ ▒                                                                                                                ▒ █
 █▒▒        export const init_array linksection(".init_array") = [_]*const fn () callconv(.c)                       ▒▒█
 █ ▒        void{&zig_init};                                                                                        ▒ █
 █ █        export const fini_array linksection(".fini_array") = [_]*const fn () callconv(.c)                       █ █
 █ ▒        void{&zig_fini};                                                                                        ▒ █
 █▒▒                                                                                                              ¡ ▒▒█
 █ ▒        fn zig_init() callconv(.c) void {                                                                    ▄█,▒ █
 █ █            std.debug.print("[init hook]\n", .{});                                                           °▀▀█ █
 █▒▒            allocations = AllocationMap.init(alloc);                                                            ▒▒█
 █ ▒        }                                                                                                       ▒ █
 █ █                                                                                                                █ █
 █ ▒        fn zig_fini() callconv(.c) void {                                                                       ▒ █
 █▒▒            std.debug.print("\n===== [fini hook]\n", .{});                                                      ▒▒█
 █ ▒                                                                                                                ▒ █
 █ █            if (!use_libc_alloc) {                                                                              █ █
 █ ▒                allocations.deinit();                                                                           ▒ █
 █▒▒                std.debug.print("leaks: {any}\n", .{gpa.detectLeaks()});                                        ▒▒█
 █ ▒            } else {                                                                                            ▒ █
 █ █                defer allocations.deinit();                                                                     █ █
 █ ▒                var it = allocations.iterator();                                                                ▒ █
 █▒▒ ¡              const leaks = it.next() != null;                                                                ▒▒█
 █ ▒,█▄             std.debug.print("leaks: {any}\n", .{leaks});                                                    ▒ █
 █ █▀▀°             if (leaks) print_alloc_state();                                                                 █ █
 █▒▒            }                                                                                                   ▒▒█
 █ ▒        }                                                                                                       ▒ █
 █ █                                                                                                                █ █
 █ ▒        fn getFn(name: [*:0]const u8, T: type) T {                                                              ▒ █
 █▒▒            const ptr = dlsym(@ptrFromInt(std.math.maxInt(usize)), name);                                       ▒▒█
 █ ▒            const fnp: T = @ptrCast(ptr);                                                                       ▒ █
 █ █            return fnp;                                                                                         █ █
 █ ▒        }                                                                                                       ▒ █
 █▒▒                                                                                                                ▒▒█
 █ ▒        export fn malloc(in: usize) callconv(.c) ?*anyopaque {                                                  ▒ █
 █ █            const fnp = getFn("malloc", *const fn (usize) callconv(.c) ?*anyopaque);                            █ █
 █ ▒            const memPtr: ?*anyopaque = blk: {                                                                  ▒ █
 █▒▒                if (use_libc_alloc) {                                                                         ¡ ▒▒█
 █ ▒                    break :blk fnp(in);                                                                      ▄█,▒ █
 █ █                } else {                                                                                     °▀▀█ █
 █▒▒                    const slice = alloc.alloc(u8, in) catch {                                                   ▒▒█
 █ ▒                        @panic("Failed to allocate");                                                           ▒ █
 █ █                    };                                                                                          █ █
 █ ▒                    break :blk @ptrCast(slice.ptr);                                                             ▒ █
 █▒▒                }                                                                                               ▒▒█
 █ ▒            };                                                                                                  ▒ █
 █ █                                                                                                                █ █
 █ ▒            const zero: ?*anyopaque = @ptrFromInt(0);                                                           ▒ █
 █▒▒                                                                                                                ▒▒█
 █ ▒            if (memPtr != zero) {                                                                               ▒ █
 █ █                std.debug.print("(~) [trace] malloc(bytes: 0x{x}) -> {x}\n", .{ in,                             █ █
 █ ▒        @intFromPtr(memPtr) });                                                                                 ▒ █
 █▒▒ ¡              allocations_mutex.lock();                                                                       ▒▒█
 █ ▒,█▄             defer allocations_mutex.unlock();                                                               ▒ █
 █ █▀▀°             allocations.put(@intFromPtr(memPtr), in) catch {                                                █ █
 █▒▒                    @panic("Failed to update allocations map");                                                 ▒▒█
 █ ▒                };                                                                                              ▒ █
 █ █            } else {                                                                                            █ █
 █ ▒                std.debug.print("malloc returned null\n", .{});                                                 ▒ █
 █▒▒            }                                                                                                   ▒▒█
 █ ▒            if (verbose) {                                                                                      ▒ █
 █ █                print_alloc_state();                                                                            █ █
 █ ▒                print_stacktrace();                                                                             ▒ █
 █▒▒            }                                                                                                   ▒▒█
 █ ▒                                                                                                                ▒ █
 █ █            return memPtr;                                                                                      █ █
 █ ▒        }                                                                                                       ▒ █
 █▒▒        export fn free(ptr: ?*anyopaque) callconv(.c) void {                                                  ¡ ▒▒█
 █ ▒            const fnp = getFn("free", *const fn (?*anyopaque) callconv(.c) void);                            ▄█,▒ █
 █ █            std.debug.print("(~) [trace] free(ptr: {x})\n", .{@intFromPtr(ptr)});                            °▀▀█ █
 █▒▒                                                                                                                ▒▒█
 █ ▒            if (verbose) {                                                                                      ▒ █
 █ █                print_alloc_state();                                                                            █ █
 █ ▒                print_stacktrace();                                                                             ▒ █
 █▒▒            }                                                                                                   ▒▒█
 █ ▒                                                                                                                ▒ █
 █ █            if (use_libc_alloc) {                                                                               █ █
 █ ▒                fnp(ptr);                                                                                       ▒ █
 █▒▒            } else {                                                                                            ▒▒█
 █ ▒                const ptrVal: usize = @intFromPtr(ptr);                                                         ▒ █
 █ █                allocations_mutex.lock();                                                                       █ █
 █ ▒                defer allocations_mutex.unlock();                                                               ▒ █
 █▒▒ ¡              if (allocations.get(ptrVal)) |size| {                                                           ▒▒█
 █ ▒,█▄                 const slice: []u8 = @as([*]u8, @ptrCast(ptr))[0..size];                                     ▒ █
 █ █▀▀°                 alloc.free(slice);                                                                          █ █
 █▒▒                    _ = allocations.remove(ptrVal);                                                             ▒▒█
 █ ▒                }                                                                                               ▒ █
 █ █            }                                                                                                   █ █
 █ ▒        }                                                                                                       ▒ █
 █▒▒                                                                                                                ▒▒█
 █ ▒        fn print_alloc_state() void {                                                                           ▒ █
 █ █            std.debug.print("\n=== allocator state: \n", .{});                                                  █ █
 █ ▒                                                                                                                ▒ █
 █▒▒            var it = allocations.iterator();                                                                    ▒▒█
 █ ▒            while (it.next()) |entry| {                                                                         ▒ █
 █ █                std.debug.print("key = {x}, value = {any}\n", .{ entry.key_ptr.*, entry.value_ptr.*             █ █
 █ ▒        });                                                                                                     ▒ █
 █▒▒            }                                                                                                 ¡ ▒▒█
 █ ▒        }                                                                                                    ▄█,▒ █
 █ █                                                                                                             °▀▀█ █
 █▒▒        inline fn print_stacktrace() void {                                                                     ▒▒█
 █ ▒            std.debug.print("[stacktrace begin] =====\n", .{});                                                 ▒ █
 █ █            const stderr = std.debug.lockStderrWriter(&.{});                                                    █ █
 █ ▒            defer std.debug.unlockStderrWriter();                                                               ▒ █
 █▒▒                                                                                                                ▒▒█
 █ ▒            std.debug.dumpCurrentStackTraceToWriter(@returnAddress(), stderr) catch {};                         ▒ █
 █ █            std.debug.print("[stacktrace end] =====\n\n", .{});                                                 █ █
 █ ▒        }                                                                                                       ▒ █
 █▒▒                                                                                                                ▒▒█
 █ ▒                                                                                                                ▒ █
 █ █        Nesses exemplos anteriores, Zig é usado como um uma "peca extra" que é                                  █ █
 █ ▒        encaixada ao programa principal que é escrito em C. Tambem podemos fazer o                              ▒ █
 █▒▒ ¡      contrario, usar Zig como o programa principal e incluir funcionalidades de um                           ▒▒█
 █ ▒,█▄     programa C.                                                                                             ▒ █
 █ █▀▀°                                                                                                             █ █
 █▒▒        O build.zig na pasta do quickjs serve para compilar o quickjs e podermos incluir                        ▒▒█
 █ ▒        ele do harness como um modulo. Fazer desse jeito não é necessario, poderiamos                           ▒ █
 █ █        ter somente um build.zig, mas eu achei que fica mais organizado dessa forma.                            █ █
 █ ▒                                                                                                                ▒ █
 █▒▒        Os arquivos estao organizados assim:                                                                    ▒▒█
 █ ▒                                                                                                                ▒ █
 █ █        ./quickjs/                                                                                              █ █
 █ ▒        ./quickjs/qjs.c                                                                                         ▒ █
 █▒▒        ./quickjs/quickjs.h                                                                                     ▒▒█
 █ ▒        ./quickjs/build.zig                                                                                     ▒ █
 █ █        ...etc                                                                                                  █ █
 █ ▒        ./                                                                                                      ▒ █
 █▒▒        ./build.zig                                                                                           ¡ ▒▒█
 █ ▒        ./build.zon                                                                                          ▄█,▒ █
 █ █        ./harness.zig                                                                                        °▀▀█ █
 █▒▒                                                                                                                ▒▒█
 █ ▒                                                                                                                ▒ █
 █ █        Esse arquivo abaixo é o build.zig para buildar a engine quickjs. é um pouco de                          █ █
 █ ▒        uma gambiarra porque eu ignorei os arquivos que produzem os entrypoints do                              ▒ █
 █▒▒        programa, dessa forma podemos usar como uma biblioteca dinamica.                                        ▒▒█
 █ ▒                                                                                                                ▒ █
 █ █                                                                                                                █ █
 █ ▒        Note tambem o addTranslateC que vai traduzir um arquivo C para Zig (funciona                            ▒ █
 █▒▒        bem na maioria dos casos), isso nos vai permitir incluir funcoes o quickjs com                          ▒▒█
 █ ▒        os tipos corretamente traduzidos, como se fosse nativa do Zig.                                          ▒ █
 █ █                                                                                                                █ █
 █ ▒        // ./quickjs/build.zig                                                                                  ▒ █
 █▒▒ ¡      pub fn build(b: *std.Build) void {                                                                      ▒▒█
 █ ▒,█▄         const target = b.standardTargetOptions(.{});                                                        ▒ █
 █ █▀▀°         const optimize = b.standardOptimizeOption(.{});                                                     █ █
 █▒▒                                                                                                                ▒▒█
 █ ▒            const header = b.addTranslateC(.{ // aqui                                                           ▒ █
 █ █                .root_source_file = b.path("qjs.c"),                                                            █ █
 █ ▒                .target = target,                                                                               ▒ █
 █▒▒                .optimize = optimize,                                                                           ▒▒█
 █ ▒            });                                                                                                 ▒ █
 █ █                                                                                                                █ █
 █ ▒            const mod = b.addModule("qjs", .{                                                                   ▒ █
 █▒▒                .target = target,                                                                               ▒▒█
 █ ▒                .optimize = optimize,                                                                           ▒ █
 █ █                .root_source_file = header.getOutput(),                                                         █ █
 █ ▒            });                                                                                                 ▒ █
 █▒▒                                                                                                              ¡ ▒▒█
 █ ▒            mod.addCSourceFiles(.{                                                                           ▄█,▒ █
 █ █                .files = &.{                                                                                 °▀▀█ █
 █▒▒                    // "qjs.c",                                                                                 ▒▒█
 █ ▒                    // "qjsc.c",                                                                                ▒ █
 █ █                    "quickjs-libc.c",                                                                           █ █
 █ ▒                    "quickjs.c",                                                                                ▒ █
 █▒▒                    "cutils.c",                                                                                 ▒▒█
 █ ▒                    "dtoa.c",                                                                                   ▒ █
 █ █                    "libunicode.c",                                                                             █ █
 █ ▒                    "libregexp.c",                                                                              ▒ █
 █▒▒                },                                                                                              ▒▒█
 █ ▒                .flags = &.{                                                                                    ▒ █
 █ █                    // "-fsanitize=address",                                                                    █ █
 █ ▒                    "-Wall",                                                                                    ▒ █
 █▒▒ ¡                  "-Wextra",                                                                                  ▒▒█
 █ ▒,█▄                 "-D_GNU_SOURCE",                                                                            ▒ █
 █ █▀▀°                 "-DCONFIG_VERSION=\"2021-03-27\"",                                                          █ █
 █▒▒                    // "-DDUMP_BYTECODE",                                                                       ▒▒█
 █ ▒                    // "-DDUMP_FREE",                                                                           ▒ █
 █ █                    // "-DDUMP_SHAPES",                                                                         █ █
 █ ▒                    // "-DDUMP_MEM",                                                                            ▒ █
 █▒▒                    // "-DDUMP_OBJECTS",                                                                        ▒▒█
 █ ▒                    // "-DDUMP_GC",                                                                             ▒ █
 █ █                },                                                                                              █ █
 █ ▒            });                                                                                                 ▒ █
 █▒▒                                                                                                                ▒▒█
 █ ▒            const obj = b.addLibrary(.{                                                                         ▒ █
 █ █                .root_module = mod,                                                                             █ █
 █ ▒                .name = "quickjslib_ziggy",                                                                     ▒ █
 █▒▒                .linkage = .dynamic,                                                                          ¡ ▒▒█
 █ ▒            });                                                                                              ▄█,▒ █
 █ █            // obj.linkLibC();                                                                               °▀▀█ █
 █▒▒            obj.linkSystemLibrary("m");                                                                         ▒▒█
 █ ▒            obj.linkSystemLibrary("dl");                                                                        ▒ █
 █ █            obj.linkSystemLibrary("pthread");                                                                   █ █
 █ ▒                                                                                                                ▒ █
 █▒▒            b.installArtifact(obj);                                                                             ▒▒█
 █ ▒                                                                                                                ▒ █
 █ █            //                                                                                                  █ █
 █ ▒            // exe.linkSystemLibrary("asan");                                                                   ▒ █
 █▒▒        }                                                                                                       ▒▒█
 █ ▒        // ...                                                                                                  ▒ █
 █ █                                                                                                                █ █
 █ ▒                                                                                                                ▒ █
 █▒▒ ¡      E no ./build.zon adicionamos esse quickjs como uma dependencia local                                    ▒▒█
 █ ▒,█▄                                                                                                             ▒ █
 █ █▀▀°     .{                                                                                                      █ █
 █▒▒            // ...                                                                                              ▒▒█
 █ ▒            .dependencies = .{                                                                                  ▒ █
 █ █                .qjs = .{                                                                                       █ █
 █ ▒                    .path = "./quickjs",                                                                        ▒ █
 █▒▒                },                                                                                              ▒▒█
 █ ▒            },                                                                                                  ▒ █
 █ █            // ...                                                                                              █ █
 █ ▒        }                                                                                                       ▒ █
 █▒▒                                                                                                                ▒▒█
 █ ▒                                                                                                                ▒ █
 █ █        E no ./build.zig centralizamos a build, o qjs e o harness                                               █ █
 █ ▒                                                                                                                ▒ █
 █▒▒        pub fn build(b: *std.Build) void {                                                                    ¡ ▒▒█
 █ ▒            const target = b.standardTargetOptions(.{});                                                     ▄█,▒ █
 █ █            const optimize = b.standardOptimizeOption(.{});                                                  °▀▀█ █
 █▒▒                                                                                                                ▒▒█
 █ ▒            const qjs = b.dependency("qjs", .{ .target = target, .optimize = optimize });                       ▒ █
 █ █            const harness_mod =                                                                                 █ █
 █ ▒                b.createModule(.{                                                                               ▒ █
 █▒▒                    .root_source_file = b.path("harness.zig"),                                                  ▒▒█
 █ ▒                    .target = target,                                                                           ▒ █
 █ █                    .optimize = optimize,                                                                       █ █
 █ ▒                });                                                                                             ▒ █
 █▒▒                                                                                                                ▒▒█
 █ ▒            harness_mod.addImport("qjs", qjs.module("qjs"));                                                    ▒ █
 █ █            const harness_exe = b.addExecutable(.{ .name = "harness", .root_module = harness_mod });            █ █
 █ ▒            harness_exe.linkSystemLibrary("m");                                                                 ▒ █
 █▒▒ ¡          harness_exe.linkSystemLibrary("dl");                                                                ▒▒█
 █ ▒,█▄         harness_exe.linkSystemLibrary("pthread");                                                           ▒ █
 █ █▀▀°                                                                                                             █ █
 █▒▒            b.installArtifact(harness_exe);                                                                     ▒▒█
 █ ▒            const run_exe = b.addRunArtifact(harness_exe);                                                      ▒ █
 █ █            const run_step = b.step("run", "Run the app");                                                      █ █
 █ ▒            run_step.dependOn(&run_exe.step);                                                                   ▒ █
 █▒▒                                                                                                                ▒▒█
 █ ▒            run_step.dependOn(b.getInstallStep());                                                              ▒ █
 █ █        }                                                                                                       █ █
 █ ▒                                                                                                                ▒ █
 █▒▒                                                                                                                ▒▒█
 █ ▒        Com isso configurado, podemos usar as funcoes do quickjs como se estivessemos escrevendo em             ▒ █
 █ █        C                                                                                                       █ █
 █ ▒                                                                                                                ▒ █
 █▒▒        const qjs = @import("qjs");                                                                           ¡ ▒▒█
 █ ▒        //  ...                                                                                              ▄█,▒ █
 █ █                                                                                                             °▀▀█ █
 █▒▒        // vai guardar e serializar o resultao do testes                                                        ▒▒█
 █ ▒        const EvalRecord = struct {                                                                             ▒ █
 █ █            input: [:0]u8,                                                                                      █ █
 █ ▒            output: []u32,                                                                                      ▒ █
 █▒▒        };                                                                                                      ▒▒█
 █ ▒                                                                                                                ▒ █
 █ █        // ...                                                                                                  █ █
 █ ▒                                                                                                                ▒ █
 █▒▒        fn eval_string(data: [:0]u8) ?EvalRecord {                                                              ▒▒█
 █ ▒            var tmp: u64 = undefined;                                                                           ▒ █
 █ █            const vtable: qjs.JSMallocFunctions = .{ .js_malloc = js_malloc_hook, .js_free =                    █ █
 █ ▒        js_free_hook, .js_realloc = js_realloc_hook };                                                          ▒ █
 █▒▒ ¡                                                                                                              ▒▒█
 █ ▒,█▄         const rt = qjs.JS_NewRuntime2(&vtable, @ptrCast(&tmp));                                             ▒ █
 █ █▀▀°         const ctx = qjs.JS_NewContext(rt);                                                                  █ █
 █▒▒            const value = qjs.JS_Eval(ctx, data, data.len, "<none>", qjs.JS_EVAL_TYPE_GLOBAL);                  ▒▒█
 █ ▒            const nbytes = 0x100;                                                                               ▒ █
 █ █                                                                                                                █ █
 █ ▒            switch (value.tag) {                                                                                ▒ █
 █▒▒                qjs.JS_TAG_INT => std.debug.print("obj is int: {}\n", .{value.u.int32}),                        ▒▒█
 █ ▒                qjs.JS_TAG_EXCEPTION => std.debug.print("obj is exception: {any}\n",                            ▒ █
 █ █        .{value.u.ptr}),                                                                                        █ █
 █ ▒                qjs.JS_TAG_OBJECT, qjs.JS_TAG_STRING => {                                                       ▒ █
 █▒▒                    std.debug.print("obj is obj/string: {any}\n", .{value.u.ptr});                              ▒▒█
 █ ▒                    litdbg.mem(u64, value.u.ptr, nbytes) catch {};                                              ▒ █
 █ █                                                                                                                █ █
 █ ▒                    const objptr: usize = @intFromPtr(value.u.ptr);                                             ▒ █
 █▒▒                    const memptr: [*]u32 = @ptrCast(@alignCast(value.u.ptr));                                 ¡ ▒▒█
 █ ▒                    const teleptr: [*]usize = @ptrCast(@alignCast(value.u.ptr));                             ▄█,▒ █
 █ █                                                                                                             °▀▀█ █
 █▒▒                    const shape = teleptr[1];                                                                   ▒▒█
 █ ▒                    const prop = teleptr[2];                                                                    ▒ █
 █ █                                                                                                                █ █
 █ ▒                    @breakpoint();                                                                              ▒ █
 █▒▒                    std.debug.print("shape: {x}, prop: {x}\n", .{ shape, prop });                               ▒▒█
 █ ▒                    debug_print_mem(@ptrFromInt(objptr), 0x10);                                                 ▒ █
 █ █                                                                                                                █ █
 █ ▒                    return .{ .input = data, .output = memptr[0..0x18] };                                       ▒ █
 █▒▒                },                                                                                              ▒▒█
 █ ▒                qjs.JS_TAG_UNDEFINED => std.debug.print("obj is undefined\n", .{}),                             ▒ █
 █ █                else => std.debug.print("obj is unknown tag: {}\n", .{value.tag}),                              █ █
 █ ▒            }                                                                                                   ▒ █
 █▒▒ ¡                                                                                                              ▒▒█
 █ ▒,█▄         return null;                                                                                        ▒ █
 █ █▀▀°     }                                                                                                       █ █
 █▒▒                                                                                                                ▒▒█
 █ ▒        // ...                                                                                                  ▒ █
 █ █                                                                                                                █ █
 █ ▒        fn logTest(comptime name: []const u8, comptime input: []const u8) !void {                               ▒ █
 █▒▒            const res = eval_string(@ptrCast(@constCast(input)));                                               ▒▒█
 █ ▒                                                                                                                ▒ █
 █ █            const f = try std.fs.cwd().createFile(name, .{});                                                   █ █
 █ ▒                                                                                                                ▒ █
 █▒▒            var json_writer = std.Io.Writer.Allocating.init(std.heap.page_allocator);                           ▒▒█
 █ ▒            defer json_writer.deinit();                                                                         ▒ █
 █ █            try std.json.Stringify.value(res, .{}, &json_writer.writer);                                        █ █
 █ ▒            const arr = try json_writer.toOwnedSliceSentinel(0);                                                ▒ █
 █▒▒                                                                                                              ¡ ▒▒█
 █ ▒            const written = try f.write(arr);                                                                ▄█,▒ █
 █ █                                                                                                             °▀▀█ █
 █▒▒            std.debug.print("written {} bytes: {s}\n", .{ written, arr });                                      ▒▒█
 █ ▒        }                                                                                                       ▒ █
 █ █                                                                                                                █ █
 █ ▒        // ...                                                                                                  ▒ █
 █▒▒                                                                                                                ▒▒█
 █ ▒        pub fn main() !void {                                                                                   ▒ █
 █ █            try logTest("basic_string.json", "let str = \"gwimbly\"; str");                                     █ █
 █ ▒            try logTest("basic_obj.json", "let obj = {a: 42, b: 1337}; obj");                                   ▒ █
 █▒▒            try logTest("basic_arrbuf.json", "let arrbuf = new ArrayBuffer(0xcafe); arrbuf");                   ▒▒█
 █ ▒        }                                                                                                       ▒ █
 █ █                                                                                                                █ █
 █ ▒                                                                                                                ▒ █
 █▒▒ ¡      Dessa forma temos um harness para criar o runtime do quickjs, enviar inputs e                           ▒▒█
 █ ▒,█▄     observar os resultados. Uma grande facilidade é que o Zig tem serialização JSON                         ▒ █
 █ █▀▀°     builtin, que usei na intrumentação para salvar no disco os testes. Outra                                █ █
 █▒▒        funcionalidade interessante é que podemos rodar com a flag --watch, assim:                              ▒▒█
 █ ▒        - zig build run --watch                                                                                 ▒ █
 █ █        Isso vai recompilar e rodar o programa toda vez que tiver uma modificação no                            █ █
 █ ▒        codigo, isso é muito util para criar um loop de feedback quase instantaneo do                           ▒ █
 █▒▒        resultado dos testes. Essa ideia eu exploro mais no apendice desse artigo.                              ▒▒█
 █ ▒                                                                                                                ▒ █
 █ █                                                                                                                █ █
 █ ▒        No final o que montamos foi uma instrumentação em userspace que é adicionada                            ▒ █
 █▒▒        diretamente no executavel e que é completamente customizavel. E alem disso,                             ▒▒█
 █ ▒        o processo de build, linking (e ate mais coisas que não form abordadas aqui)                            ▒ █
 █ █        foi organizado por um so arquivo build.zig, tem um bonus tambem que essa                                █ █
 █ ▒        toolchain permite cross compilation entre arquiteturas e sistemas operacionais.                         ▒ █
 █▒▒                                                                                                              ¡ ▒▒█
 █ ▒                                                                                                             ▄█,▒ █
 █ █        Alem do que foi apresentado aqui, o Zig ainda tem algumas coisas que acho bem                        °▀▀█ █
 █▒▒        promissoras, mas que não tive contato o suficiente para apresentar aqui, como um                        ▒▒█
 █ ▒        novo fuzzer implementado do zero integrado na toolchain do Zig [7].                                     ▒ █
 █ █                                                                                                                █ █
 █ ▒                                                                                                                ▒ █
 █▒▒        [1] - https://linux.die.net/man/3/dlsym                                                                 ▒▒█
 █ ▒        [2] -                                                                                                   ▒ █
 █ █        https://ziggit.dev/t/zalloc-replace-malloc-and-friends-with-a-zig-allocator-in-your-c-code/11073        █ █
 █ ▒        [3] - https://codeberg.org/ziglang/zig/src/branch/master/lib/std/heap/debug_allocator.zig               ▒ █
 █▒▒        [4] - https://ziglang.org/learn/                                                                        ▒▒█
 █ ▒        [5] - https://ziglang.org/documentation/master/std/                                                     ▒ █
 █ █        [6] - https://ziglang.org/documentation/master/                                                         █ █
 █ ▒        [7] - https://github.com/ziglang/zig/issues/20702                                                       ▒ █
 █▒▒ ¡      [8] - https://typst.app/                                                                                ▒▒█
 █ ▒,█▄     ---                                                                                                     ▒ █
 █ █▀▀°                                                                                                             █ █
 █▒▒        [apendice]                                                                                              ▒▒█
 █ ▒                                                                                                                ▒ █
 █ █        Depois do fim tem nada, mas o nada se contrai, cria um frasco vazio, que entao                          █ █
 █ ▒        é preenchido. Aqui é esse lugar.                                                                        ▒ █
 █▒▒                                                                                                                ▒▒█
 █ ▒        A parte do artigo que fala sobre rodar a instrumentaco com zig build run                                ▒ █
 █ █        --watch faz parte de uma ideia maior, que é "Literate Debugging".                                       █ █
 █ ▒                                                                                                                ▒ █
 █▒▒        Essa ideia foi fortemente baseada no conceito de "Literate Programming"                                 ▒▒█
 █ ▒        introduzido pelo Donald Knuth.                                                                          ▒ █
 █ █                                                                                                                █ █
 █ ▒        A ideia de "Literate Debugging" é que geralmente quando estamos debugando                               ▒ █
 █▒▒        algo estamos escrevendo programas, em gdbscript, python ou alguma outra coisa                         ¡ ▒▒█
 █ ▒        o objetivo final deles é mostrar a execução do programa para uma pessoa                              ▄█,▒ █
 █ █        (geralmente nos mesmos). A ideia de puxar o literario aqui, é que foco é                             °▀▀█ █
 █▒▒        movido para a pessoa que esta lendo o resultado.                                                        ▒▒█
 █ ▒                                                                                                                ▒ █
 █ █        Eu fui atraido por essa ideia por causa de situacoes como escrever um blog ou                           █ █
 █ ▒        uns slides com diagramas mostrando como a a pilha de um programa se comportava                          ▒ █
 █▒▒        ao longo de uns pontos especificos da sua execução. Um jeito poderia ser printar                        ▒▒█
 █ ▒        o gdb e colar as imagens, mas eu não queria imagens pixeladas, outro jeito                              ▒ █
 █ █        melhor poderia ser logar a saida do GDB para um arquivo com `set logging enabled                        █ █
 █ ▒        on`, mas ainda podemos fazer melhor.                                                                    ▒ █
 █▒▒                                                                                                                ▒▒█
 █ ▒        O harness para o quickjs que mostrei na seção principal do artigo, gera um                              ▒ █
 █ █        arquivo json para cada teste, a cada modificação do arquivo por causa do --watch.                       █ █
 █ ▒        Para montar uma visualização disso para  uns slides ou um blog, eu                                      ▒ █
 █▒▒ ¡      posso gerar um pdf, svg, html, etc dinamicamente baseado nesse json.                                    ▒▒█
 █ ▒,█▄                                                                                                             ▒ █
 █ █▀▀°     Uma ferramenta que tenho gostado bastante para isso tem sido o typst [8] (com                           █ █
 █▒▒        ele podemos escrever um codigo que parece com markdown e latex que gera                                 ▒▒█
 █ ▒        documentos estaticos).                                                                                  ▒ █
 █ █                                                                                                                █ █
 █ ▒        Isso aqui é como ficou o codigo em typst para ler o json e mostrar em uma tabela                        ▒ █
 █▒▒                                                                                                                ▒▒█
 █ ▒        #let showLog(src) = {                                                                                   ▒ █
 █ █          let basic_str = json(src)                                                                             █ █
 █ ▒          let hex_32 = (                                                                                        ▒ █
 █▒▒            basic_str                                                                                           ▒▒█
 █ ▒              .output                                                                                           ▒ █
 █ █              .chunks(2)                                                                                        █ █
 █ ▒              .enumerate()                                                                                      ▒ █
 █▒▒              .map(((i, n)) => {                                                                              ¡ ▒▒█
 █ ▒                if (calc.rem((i + 1), 2) == 0) {                                                             ▄█,▒ █
 █ █                  set text(fill: luma(100%))                                                                 °▀▀█ █
 █▒▒                  raw(to_hex(i * 8, width: 2) + " " + to_hex_list(n))                                           ▒▒█
 █ ▒                } else {                                                                                        ▒ █
 █ █                  set text(fill: luma(70%))                                                                     █ █
 █ ▒                  raw(to_hex(i * 8, width: 2) + " " + to_hex_list(n))                                           ▒ █
 █▒▒                }                                                                                               ▒▒█
 █ ▒              })                                                                                                ▒ █
 █ █          )                                                                                                     █ █
 █ ▒                                                                                                                ▒ █
 █▒▒          (                                                                                                     ▒▒█
 █ ▒            code: raw(block: true, lang: "js", basic_str.input),                                                ▒ █
 █ █            hex: grid(                                                                                          █ █
 █ ▒              inset: 2pt,                                                                                       ▒ █
 █▒▒ ¡            fill: code_bg,                                                                                    ▒▒█
 █ ▒,█▄           ..hex_32                                                                                          ▒ █
 █ █▀▀°         ),                                                                                                  █ █
 █▒▒          )                                                                                                     ▒▒█
 █ ▒        }                                                                                                       ▒ █
 █ █                                                                                                                █ █
 █ ▒        #let logs = (                                                                                           ▒ █
 █▒▒          showLog("basic_arrbuf.json"),                                                                         ▒▒█
 █ ▒          showLog("basic_string.json"),                                                                         ▒ █
 █ █          showLog("basic_obj.json"),                                                                            █ █
 █ ▒        )                                                                                                       ▒ █
 █▒▒                                                                                                                ▒▒█
 █ ▒        #block(fill: code_bg)[                                                                                  ▒ █
 █ █          #grid(                                                                                                █ █
 █ ▒            columns: 3,                                                                                         ▒ █
 █▒▒            gutter: 8pt,                                                                                      ¡ ▒▒█
 █ ▒            ..logs.map(log => log.code),                                                                     ▄█,▒ █
 █ █            ..logs.map(log => log.hex)                                                                       °▀▀█ █
 █▒▒          )                                                                                                     ▒▒█
 █ ▒        ]                                                                                                       ▒ █
 █ █                                                                                                                █ █
 █ ▒                                                                                                                ▒ █
 █▒▒        Uma coisa que funcionou muito bem com essa configuração é que eu posso rodar                            ▒▒█
 █ ▒        zig build run --watch e typst watch qjs_debug.typ entao toda vez que eu                                 ▒ █
 █ █        criar um teste ou modificar alguma coisa no harness.zig, o pdf vai ser                                  █ █
 █ ▒        atualizao instantaneamente com os novos resultados.                                                     ▒ █
 █▒▒                                                                                                                ▒▒█
 █ ▒        Acredito que essa ideia tem muito potencial, ainda podemos fazer muito com                              ▒ █
 █ █        ela, como: desenvolver novas ferramentas, criar material didatico, ou ate mesmo                         █ █
 █ ▒        so a filosofia de que o que fazemos no final é transmitir ideias para pessoas.                          ▒ █
 █▒▒                                                                                                                ▒▒█
 █ ▒                                                                                                                ▒ █
 █▒▒▒▒▒ ░░                                                                                                    ▒▒▒▒▒▒▒▒█
 █ ▒                                                                                                                ▓▄█
 █ █                                    T R A M O I A   ·   Z I N E   ·  2 0 2 6                                 gld ██
  ▀▄▄▄▄                                                                                                          ▒▒▄▄▀