#include <string.h>
#include "analyzer-decls.h"

/* Zero-fill of uninitialized buffer.  */

void test_1 (void)
{
  char buf[256];
  memset (buf, 0, 256);
  __analyzer_eval (buf[42] == 0); /* { dg-warning "TRUE" } */
}

/* As above, but with __builtin_memset.  */

void test_1a (void)
{
  char buf[256];
  __builtin_memset (buf, 0, 256);
  __analyzer_eval (buf[42] == 0); /* { dg-warning "TRUE" } */
}

/* Zero-fill of partially initialized buffer.  */

void test_2 (void)
{
  char buf[256];
  buf[42] = 'A';
  __analyzer_eval (buf[42] == 'A'); /* { dg-warning "TRUE" } */
  memset (buf, 0, 256);
  __analyzer_eval (buf[42] == '\0'); /* { dg-warning "TRUE" } */
}

/* A "memset" with known non-zero value.  */

void test_3 (int val)
{
  char buf[256];
  memset (buf, 'A', 256);
  __analyzer_eval (buf[42] == 'A'); /* { dg-warning "TRUE" } */
}

/* A "memset" with unknown value.  */

void test_4 (char val)
{
  char buf[256];
  memset (buf, val, 256);
  __analyzer_eval (buf[42] == (char)val); /* { dg-warning "TRUE" } */
}

/* A "memset" with unknown num bytes.  */

void test_5 (int n)
{
  char buf[256];
  buf[42] = 'A';
  __analyzer_eval (buf[42] == 'A'); /* { dg-warning "TRUE" } */
  memset (buf, 0, n);

  /* We can't know if buf[42] was written to or not.  */
  __analyzer_eval (buf[42] == 'A'); /* { dg-warning "UNKNOWN" } */
  __analyzer_eval (buf[42] == '\0'); /* { dg-warning "UNKNOWN" } */
}

/* As test_5, but with "__builtin___memset_chk".  */

void test_5a (int n)
{
  char buf[256];
  buf[42] = 'A';
  __analyzer_eval (buf[42] == 'A'); /* { dg-warning "TRUE" } */
  __builtin___memset_chk (buf, 0, n, __builtin_object_size (buf, 0));

  /* We can't know if buf[42] was written to or not.  */
  __analyzer_eval (buf[42] == 'A'); /* { dg-warning "UNKNOWN" } */
  __analyzer_eval (buf[42] == '\0'); /* { dg-warning "UNKNOWN" } */
}

/* A "memset" with unknown value, but with zero size.  */

static size_t __attribute__((noinline))
get_zero (void)
{
  return 0;
}

void test_6 (int val)
{
  char buf[256];
  buf[42] = 'A';
  memset (buf, 'B', get_zero ());
  __analyzer_eval (buf[42] == 'A'); /* { dg-warning "TRUE" } */  
}

void test_6b (int val)
{
  char buf[256];
  memset (buf, 'A', sizeof (buf));
  memset (buf, 'B', get_zero ());
  __analyzer_eval (buf[42] == 'A'); /* { dg-warning "TRUE" } */  
}

/* A "memset" of known size that's not the full buffer.  */

void test_7 (void)
{
  char buf[256];
  buf[128] = 'A';
  memset (buf, 0, 128);
  __analyzer_eval (buf[0] == '\0'); /* { dg-warning "TRUE" } */
  __analyzer_eval (buf[127] == '\0'); /* { dg-warning "TRUE" } */
  __analyzer_eval (buf[128] == 'A'); /* { dg-warning "TRUE" } */
}

void test_8 (void)
{
  char buf[20];
  memset (buf + 0, 0, 1);
  memset (buf + 1, 1, 1);
  memset (buf + 2, 2, 1);
  memset (buf + 3, 3, 1);
  memset (buf + 4, 4, 2);
  memset (buf + 6, 6, 2);
  memset (buf + 8, 8, 4);
  memset (buf + 12, 12, 8);
  __analyzer_eval (buf[0] == 0); /* { dg-warning "TRUE" } */
  __analyzer_eval (buf[1] == 1); /* { dg-warning "TRUE" } */
  __analyzer_eval (buf[2] == 2); /* { dg-warning "TRUE" } */
  __analyzer_eval (buf[3] == 3); /* { dg-warning "TRUE" } */
  __analyzer_eval (buf[4] == 4); /* { dg-warning "TRUE" } */
  __analyzer_eval (buf[5] == 4); /* { dg-warning "TRUE" } */
  __analyzer_eval (buf[6] == 6); /* { dg-warning "TRUE" } */
  __analyzer_eval (buf[7] == 6); /* { dg-warning "TRUE" } */
  __analyzer_eval (buf[8] == 8); /* { dg-warning "TRUE" } */
  __analyzer_eval (buf[9] == 8); /* { dg-warning "TRUE" } */
  __analyzer_eval (buf[10] == 8); /* { dg-warning "TRUE" } */
  __analyzer_eval (buf[11] == 8); /* { dg-warning "TRUE" } */
  __analyzer_eval (buf[12] == 12); /* { dg-warning "TRUE" } */
  __analyzer_eval (buf[13] == 12); /* { dg-warning "TRUE" } */
  __analyzer_eval (buf[14] == 12); /* { dg-warning "TRUE" } */
  __analyzer_eval (buf[15] == 12); /* { dg-warning "TRUE" } */
  __analyzer_eval (buf[16] == 12); /* { dg-warning "TRUE" } */
  __analyzer_eval (buf[17] == 12); /* { dg-warning "TRUE" } */
  __analyzer_eval (buf[18] == 12); /* { dg-warning "TRUE" } */
  __analyzer_eval (buf[19] == 12); /* { dg-warning "TRUE" } */
}

/* Various overlapping memset calls with different sizes and values.  */

void test_9 (void)
{
  char buf[8];
  memset (buf, 0, 8);
  __analyzer_eval (buf[0] == 0); /* { dg-warning "TRUE" } */
  __analyzer_eval (buf[1] == 0); /* { dg-warning "TRUE" } */
  __analyzer_eval (buf[2] == 0); /* { dg-warning "TRUE" } */
  __analyzer_eval (buf[3] == 0); /* { dg-warning "TRUE" } */
  __analyzer_eval (buf[4] == 0); /* { dg-warning "TRUE" } */
  __analyzer_eval (buf[5] == 0); /* { dg-warning "TRUE" } */
  __analyzer_eval (buf[6] == 0); /* { dg-warning "TRUE" } */
  __analyzer_eval (buf[7] == 0); /* { dg-warning "TRUE" } */

  memset (buf + 1, 1, 4);  
  __analyzer_eval (buf[0] == 0); /* { dg-warning "TRUE" } */
  __analyzer_eval (buf[1] == 1); /* { dg-warning "TRUE" } */
  __analyzer_eval (buf[2] == 1); /* { dg-warning "TRUE" } */
  __analyzer_eval (buf[3] == 1); /* { dg-warning "TRUE" } */
  __analyzer_eval (buf[4] == 1); /* { dg-warning "TRUE" } */
  __analyzer_eval (buf[5] == 0); /* { dg-warning "TRUE" } */
  __analyzer_eval (buf[6] == 0); /* { dg-warning "TRUE" } */
  __analyzer_eval (buf[7] == 0); /* { dg-warning "TRUE" } */

  memset (buf + 2, 2, 4);  
  __analyzer_eval (buf[0] == 0); /* { dg-warning "TRUE" } */
  __analyzer_eval (buf[1] == 1); /* { dg-warning "TRUE" } */
  __analyzer_eval (buf[2] == 2); /* { dg-warning "TRUE" } */
  __analyzer_eval (buf[3] == 2); /* { dg-warning "TRUE" } */
  __analyzer_eval (buf[4] == 2); /* { dg-warning "TRUE" } */
  __analyzer_eval (buf[5] == 2); /* { dg-warning "TRUE" } */
  __analyzer_eval (buf[6] == 0); /* { dg-warning "TRUE" } */
  __analyzer_eval (buf[7] == 0); /* { dg-warning "TRUE" } */

  memset (buf + 4, 3, 3);  
  __analyzer_eval (buf[0] == 0); /* { dg-warning "TRUE" } */
  __analyzer_eval (buf[1] == 1); /* { dg-warning "TRUE" } */
  __analyzer_eval (buf[2] == 2); /* { dg-warning "TRUE" } */
  __analyzer_eval (buf[3] == 2); /* { dg-warning "TRUE" } */
  __analyzer_eval (buf[4] == 3); /* { dg-warning "TRUE" } */
  __analyzer_eval (buf[5] == 3); /* { dg-warning "TRUE" } */
  __analyzer_eval (buf[6] == 3); /* { dg-warning "TRUE" } */
  __analyzer_eval (buf[7] == 0); /* { dg-warning "TRUE" } */

  memset (buf + 0, 4, 3);  
  __analyzer_eval (buf[0] == 4); /* { dg-warning "TRUE" } */
  __analyzer_eval (buf[1] == 4); /* { dg-warning "TRUE" } */
  __analyzer_eval (buf[2] == 4); /* { dg-warning "TRUE" } */
  __analyzer_eval (buf[3] == 2); /* { dg-warning "TRUE" } */
  __analyzer_eval (buf[4] == 3); /* { dg-warning "TRUE" } */
  __analyzer_eval (buf[5] == 3); /* { dg-warning "TRUE" } */
  __analyzer_eval (buf[6] == 3); /* { dg-warning "TRUE" } */
  __analyzer_eval (buf[7] == 0); /* { dg-warning "TRUE" } */
}
