git-trace

romele / git-trace public

62 commits · 1 branch · 1 tag · 1 contributor (top: Romele) · first commit 3d ago · last push 12m ago

tests/fuzzdrv.c

/*
 * fuzzdrv — unit-level fuzz driver for git-trace's untrusted-input
 * parsers.  Reads a blob (argv[1] or stdin) and feeds it to every
 * target.  Build with -fsanitize=address,undefined and link against
 * ASan-instrumented project objects (see tests/fuzz.sh).
 *
 * Exit 0 on clean run; the sanitizers abort on any memory error.
 */

#include "util.h"
#include "highlight.h"
#include "webhook.h"
#include "auth.h"
#include "wcommit.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

static unsigned char *slurp(const char *path, size_t *out)
{
    FILE *f = path ? fopen(path, "rb") : stdin;
    if (!f)
        return NULL;
    size_t cap = 65536, n = 0;
    unsigned char *b = malloc(cap + 1);
    if (!b) {
        fclose(f);
        return NULL;
    }
    size_t r;
    while ((r = fread(b + n, 1, cap - n, f)) > 0) {
        n += r;
        if (n == cap)
            break;                          /* 64 KiB is plenty */
    }
    b[n] = '\0';                            /* some targets want C strings */
    fclose(f);
    *out = n;
    return b;
}

int main(int argc, char **argv)
{
    size_t n = 0;
    unsigned char *blob = slurp(argc > 1 ? argv[1] : NULL, &n);
    if (!blob)
        return 2;

    /* form_get: treat the blob as a urlencoded body */
    {
        char out[256];
        form_get((const char *)blob, n, "csrf", out, sizeof out);
        form_get((const char *)blob, n, "", out, sizeof out);
    }

    /* url_decode */
    {
        char *d = url_decode((const char *)blob, n);
        free(d);
    }

    /* gt_glob: first half is the pattern, second the subject */
    {
        size_t h = n / 2;
        char pat[512], subj[512];
        size_t pl = h > sizeof pat - 1 ? sizeof pat - 1 : h;
        size_t sl = (n - h) > sizeof subj - 1 ? sizeof subj - 1 : n - h;
        memcpy(pat, blob, pl);
        pat[pl] = '\0';
        memcpy(subj, blob + h, sl);
        subj[sl] = '\0';
        gt_glob(pat, subj);
        gt_glob(subj, pat);
    }

    /* hl_emit as C and as script */
    {
        struct buf b;
        buf_init(&b);
        hl_emit(&b, (const char *)blob, n, "x.c");
        buf_free(&b);
        buf_init(&b);
        hl_emit(&b, (const char *)blob, n, "x.sh");
        buf_free(&b);
    }

    /* json_put_esc + buf_put_escaped + buf_put_urlenc */
    {
        struct buf b;
        buf_init(&b);
        json_put_esc(&b, (const char *)blob, n);
        buf_free(&b);
        buf_init(&b);
        buf_put_escaped(&b, (const char *)blob, n);
        buf_put_urlenc(&b, (const char *)blob, 0);
        buf_put_urlenc(&b, (const char *)blob, 1);
        buf_free(&b);
    }

    /* multipart parser: first blob line is the boundary, the rest is
     * the body; also fuzz with the whole blob as the boundary */
    {
        char *nl = memchr(blob, '\n', n);
        if (nl && nl != (char *)blob) {
            char bnd[240];
            size_t bl = (size_t)(nl - (char *)blob);
            if (bl > sizeof bnd - 1)
                bl = sizeof bnd - 1;
            memcpy(bnd, blob, bl);
            bnd[bl] = '\0';
            const char *d;
            size_t dl;
            char fn[256];
            wc_mp_find((char *)blob, n, bnd, "file",
                       &d, &dl, fn, sizeof fn);
            wc_mp_find((char *)blob, n, bnd, "csrf", &d, &dl, NULL, 0);
            wc_mp_find((char *)blob, n, bnd, "", &d, &dl, NULL, 0);
            wc_mp_find((char *)blob, n, (char *)blob, "x",
                       &d, &dl, NULL, 0);
        }
    }

    /* basename + cdisp attr on the raw blob */
    {
        char fn[256], hv[128];
        wc_basename((const char *)blob, fn, sizeof fn);
        wc_mp_attr((const char *)blob, "name", hv, sizeof hv);
        wc_mp_attr((const char *)blob, (const char *)blob,
                   hv, sizeof hv);
    }

    free(blob);
    return 0;
}