
char xs[5];
struct {
    char ys[5];
    char zs[0];
} stru;

void f(void) {
    char c;

    c = xs[-1]; // $ MISSING: Alert // BAD [NOT DETECTED]
    c = xs[0]; // GOOD
    c = xs[4]; // GOOD
    c = xs[5]; // $ Alert // BAD
    c = xs[6]; // $ Alert // BAD

    c = stru.ys[-1]; // $ MISSING: Alert // BAD [NOT DETECTED]
    c = stru.ys[0]; // GOOD
    c = stru.ys[4]; // GOOD
    c = stru.ys[5]; // $ Alert // BAD
    c = stru.ys[6]; // $ Alert // BAD

    c = stru.zs[-1]; // $ MISSING: Alert // BAD [NOT DETECTED]
    c = stru.zs[0]; // GOOD (zs is variable size)
    c = stru.zs[4]; // GOOD (zs is variable size)
    c = stru.zs[5]; // GOOD (zs is variable size)
    c = stru.zs[6]; // GOOD (zs is variable size)
}

void* malloc(long unsigned int);
void test_buffer_sentinal() {
  struct { char len; char buf[1]; } *b = malloc(10); // len(buf.buffer) effectively 8
  b->buf[0] = 0; // GOOD
  b->buf[7] = 0; // GOOD
  b->buf[8] = 0; // $ MISSING: Alert // BAD [NOT DETECTED]
}

union u {
  unsigned long value;
  char ptr[1];
};

void union_test() {
  union u u;
  u.ptr[0] = 0; // GOOD
  u.ptr[sizeof(u)-1] = 0; // GOOD
  u.ptr[sizeof(u)] = 0; // $ MISSING: Alert // BAD [NOT DETECTED]
}

void test_struct_union() {
  struct { union u u; } v;
  v.u.ptr[0] = 0; // GOOD
  v.u.ptr[sizeof(union u)-1] = 0; // GOOD
  v.u.ptr[sizeof(union u)] = 0; // $ MISSING: Alert // BAD [NOT DETECTED]
}

void union_test2() {
  union { char ptr[1]; unsigned long value; } u;
  u.ptr[0] = 0; // GOOD
  u.ptr[sizeof(u)-1] = 0; // GOOD
  u.ptr[sizeof(u)] = 0; // $ MISSING: Alert // BAD [NOT DETECTED]
}

typedef struct {
    char len;
    char buf[1];
} var_buf;

void test_alloc() {
  // Special case of taking sizeof without any addition or multiplications
  var_buf *b = malloc(sizeof(var_buf));
  b->buf[1] = 0; // $ MISSING: Alert // BAD [NOT DETECTED]
}
