llvm/clang/test/Analysis/array-struct.c

// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core.CastToStruct -verify %s

struct s {
  int data;
  int data_array[10];
};

typedef struct {
  int data;
} STYPE;

void g(char *p);
void g1(struct s* p);

// Array to pointer conversion. Array in the struct field.
void f(void) {
  int a[10];
  int (*p)[10];
  p = &a;
  (*p)[3] = 1;
  
  struct s d;
  struct s *q;
  q = &d;
  q->data = 3;
  d.data_array[9] = 17;
}

// StringLiteral in lvalue context and pointer to array type.
// p: ElementRegion, q: StringRegion
void f2(void) {
  char *p = "/usr/local";
  char (*q)[4];
  q = &"abc";
}

// Typedef'ed struct definition.
void f3(void) {
  STYPE s;
}

// Initialize array with InitExprList.
void f4(void) {
  int a[] = { 1, 2, 3};
  int b[3] = { 1, 2 };
  struct s c[] = {{1,{1}}};
}

// Struct variable in lvalue context.
// Assign UnknownVal to the whole struct.
void f5(void) {
  struct s data;
  g1(&data);
}

// AllocaRegion test.
void f6(void) {
  char *p;
  p = __builtin_alloca(10); 
  g(p);
  char c = *p;
  p[1] = 'a';
  // Test if RegionStore::EvalBinOp converts the alloca region to element
  // region.
  p += 2;
}

struct s2;

void g2(struct s2 *p);

// Incomplete struct pointer used as function argument.
void f7(void) {
  struct s2 *p = __builtin_alloca(10);
  g2(p);
}

// sizeof() is unsigned while -1 is signed in array index.
void f8(void) {
  int a[10];
  a[sizeof(a)/sizeof(int) - 1] = 1; // no-warning
}

// Initialization of struct array elements.
void f9(void) {
  struct s a[10];
}

// Initializing array with string literal.
void f10(void) {
  char a1[4] = "abc";
  char a3[6] = "abc";
}

// Retrieve the default value of element/field region.
void f11(void) {
  struct s a;
  g1(&a);
  if (a.data == 0) // no-warning
    a.data = 1;
}

// Convert unsigned offset to signed when creating ElementRegion from 
// SymbolicRegion.
void f12(int *list) {
  unsigned i = 0;
  list[i] = 1;
}

struct s1 {
  struct s2 {
    int d;
  } e;
};

// The binding of a.e.d should not be removed. Test recursive subregion map
// building: a->e, e->d. Only then 'a' could be added to live region roots.
void f13(double timeout) {
  struct s1 a;
  a.e.d = (int) timeout;
  if (a.e.d == 10)
    a.e.d = 4;
}

struct s3 {
  int a[2];
};

static struct s3 opt;

// Test if the embedded array is retrieved correctly.
void f14(void) {
  struct s3 my_opt = opt;
}

void bar(int*);

struct s3 gets3(void) {
  struct s3 s;
  return s;
}

void accessArrayFieldNoCrash(void) {
  bar(gets3().a);
  bar((gets3().a));
  bar(((gets3().a)));  
}

// Test if the array is correctly invalidated.
void f15(void) {
  int a[10];
  bar(a);
  if (a[1]) // no-warning
    (void)1;
}

struct s3 p[1];

// Code from postgresql.
// Current cast logic of region store mistakenly leaves the final result region
// an ElementRegion of type 'char'. Then load a nonloc::SymbolVal from it and
// assigns to 'a'. 
void f16(struct s3 *p) {
  struct s3 a = *((struct s3*) ((char*) &p[0])); // expected-warning{{Casting a non-structure type to a structure type and accessing a field can lead to memory access errors or data corruption}}
}

void inv(struct s1 *);

// Invalidate the struct field.
void f17(void) {
  struct s1 t;
  int x;
  inv(&t);
  if (t.e.d)
    x = 1;
}

void read(char*);

void f18(void) {
  char *q;
  char *p = (char *) __builtin_alloca(10);
  read(p);
  q = p;
  q++;
  if (*q) { // no-warning
  }
}


// [PR13927] offsetof replacement macro flagged as "dereference of a null pointer"
int offset_of_data_array(void)
{
  return ((char *)&(((struct s*)0)->data_array)) - ((char *)0); // no-warning
}

int testPointerArithmeticOnVoid(void *bytes) {
  int p = 0;
  if (&bytes[0] == &bytes[1])
    return 6/p; // no-warning
  return 0;
}

int testRValueArraySubscriptExpr(void *bytes) {
  int *p = (int*)&bytes[0];
  *p = 0;
  if (*(int*)&bytes[0] == 0)
    return 0;
  return 5/(*p); // no-warning
}