aboutsummaryrefslogtreecommitdiffstats
path: root/tests/fuzz/fuzz_input.c
blob: 3d6dde38ff489284f0e5a13629e73d50a8a53587 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
/* Fuzz target: the input decoder (src/input.c).
 *
 * Decodes the bytes the outer terminal sends: CSI, SS3, kitty keyboard,
 * SGR mouse, bracketed paste, focus reports -- and any terminal can send any
 * garbage. Feed in data-chosen chunks so split escape sequences are hit,
 * then resolve the pending-ESC path via input_timeout, and render every
 * event with input_event_describe so the event's fields are all read.
 */
#include "input.h"

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

static void on_event(const input_event_t *ev, void *ud) {
  (void)ud;
  char buf[256];
  input_event_describe(ev, buf, sizeof buf);
  input_event_describe(ev, buf, 4); /* tiny cap must truncate, not overrun */
  if (ev->kind == EV_PASTE && ev->paste_len) {
    volatile char sink = ev->paste[0];
    sink = ev->paste[ev->paste_len - 1];
    (void)sink;
  }
  if (ev->kind == EV_KEY && ev->text_len) {
    if (ev->text_len > sizeof ev->text) abort();
  }
}

int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
  input_parser_t *p = input_new();
  if (!p) return 0;

  size_t i = 0;
  while (i < size) {
    size_t chunk = (size_t)(data[i] % 11) + 1; /* small, split-heavy */
    if (chunk > size - i) chunk = size - i;
    input_feed(p, data + i, chunk, on_event, NULL);
    i += chunk;
  }

  if (input_pending(p)) input_timeout(p, on_event, NULL);
  input_free(p);
  return 0;
}