struct S100 {
  int i;
  int* p;
};


int test100() {
  int x = 0;
  struct S100 s100;
  // GOOD: address is only written to another stack variable, which is
  // safe.
  s100.p = &x;
  return x;
}

static struct S100 s101;

int test101() {
  int x = 0;
  // BAD: local address is written to a static variable, which could
  // be unsafe.
  s101.p = &x; // $ Alert
  return x;
}

int test102() {
  int x = 0;
  static struct S100 s102;
  // BAD: local address is written to a local static variable, which could
  // be unsafe.
  s102.p = &x; // $ Alert
  return x;
}

void test103(int *p) {
  static struct S100 s103;
  // BAD: address is written to a local static variable, which could
  // be unsafe.
  s103.p = p; // $ Alert
}

// Helper for test103.
void test103_caller1(int *p) {
  test103(p);
}

// Helper for test103.
void test103_caller2() {
  int x = 0;
  test103_caller1(&x);
}

void test104(int *p) {
  static struct S100 s104;
  // GOOD: a stack address does not flow here, so this assignment is safe.
  s104.p = p;
}

void test104_caller1(int *p) {
  test104(p);
}

void test104_caller2() {
  static int x = 0;
  test104_caller1(&x);
}

// Test for pointer arithmetic.
int test105() {
  int x = 0;
  int* p0 = &x;
  int* p1 = p0 + 1;
  int* p2 = p1 - 1;
  int* p3 = 1 + p2;
  p3++;
  // BAD: local address is written to a static variable, which could
  // be unsafe.
  s101.p = p3; // $ Alert
  return x;
}

static struct S100 s106;

// Test for taking the address of a field.
void test106() {
  S100 s;
  // BAD: local address is written to a static variable, which could
  // be unsafe.
  s106.p = &(s.i); // $ Alert
}

// Test for reference types.
int test107() {
  int x = 0;
  int& r0 = x;
  int& r1 = r0;
  r1++;
  // BAD: local address is written to a static variable, which could
  // be unsafe.
  s101.p = &r1; // $ Alert
  return r1;
}

struct S200 {
  int i;
  union {
    void* p;
    const char* str;
  };
};

int test200() {
  int x = 0;
  struct S200 s200;
  // GOOD: address is only written to another stack variable, which is
  // safe.
  s200.p = &x;
  return x;
}

static struct S200 s201;

int test201() {
  int x = 0;
  // BAD: local address is written to a static variable, which could
  // be unsafe.
  s201.p = &x; // $ Alert
  return x;
}

int test202() {
  int x = 0;
  static struct S200 s202;
  // BAD: local address is written to a local static variable, which could
  // be unsafe.
  s202.p = &x; // $ Alert
  return x;
}

// Example used in qhelp.
static const int* xptr;

void example1() {
  int x = 0;
  xptr = &x; // $ Alert // BAD: address of local variable stored in non-local memory.
}

void example2() {
  static const int x = 0;
  xptr = &x; // GOOD: storing address of static variable is safe.
}

struct S300 {
  int a1[15];
  int a2[14][15];
  int a3[13][14][15];
  int *p1;
  int (*p2)[15];
  int (*p3)[14][15];
  int** pp;
};

void test301() {
  static S300 s;
  int b1[15];
  int b2[14][15];
  int b3[13][14][15];

  s.p1 = b1;      // $ Alert // BAD: address of local variable stored in non-local memory.
  s.p1 = &b1[1];  // $ Alert // BAD: address of local variable stored in non-local memory.

  s.p2 = b2;         // $ Alert // BAD: address of local variable stored in non-local memory.
  s.p2 = &b2[1];     // $ Alert // BAD: address of local variable stored in non-local memory.
  s.p1 = b2[1];      // $ Alert // BAD: address of local variable stored in non-local memory.
  s.p1 = &b2[1][2];  // $ Alert // BAD: address of local variable stored in non-local memory.

  s.p3 = b3;            // $ Alert // BAD: address of local variable stored in non-local memory.
  s.p3 = &b3[1];        // $ Alert // BAD: address of local variable stored in non-local memory.
  s.p2 = b3[1];         // $ Alert // BAD: address of local variable stored in non-local memory.
  s.p2 = &b3[1][2];     // $ Alert // BAD: address of local variable stored in non-local memory.
  s.p1 = b3[1][2];      // $ Alert // BAD: address of local variable stored in non-local memory.
  s.p1 = &b3[1][2][3];  // $ Alert // BAD: address of local variable stored in non-local memory.

  s.pp[0] = b1;            // $ Alert // BAD: address of local variable stored in non-local memory.
  s.pp[0] = &b1[1];        // $ Alert // BAD: address of local variable stored in non-local memory.
  s.pp[0] = b2[1];         // $ Alert // BAD: address of local variable stored in non-local memory.
  s.pp[0] = &b2[1][2];     // $ Alert // BAD: address of local variable stored in non-local memory.
  s.pp[0] = b3[1][2];      // $ Alert // BAD: address of local variable stored in non-local memory.
  s.pp[0] = &b3[1][2][3];  // $ Alert // BAD: address of local variable stored in non-local memory.
}

void test302() {
  S300 s;
  int b1[15];
  int b2[14][15];
  int b3[13][14][15];

  s.p1 = b1;      // GOOD: address is only stored in another local variable
  s.p1 = &b1[1];  // GOOD: address is only stored in another local variable

  s.p2 = b2;         // GOOD: address is only stored in another local variable
  s.p2 = &b2[1];     // GOOD: address is only stored in another local variable
  s.p1 = b2[1];      // GOOD: address is only stored in another local variable
  s.p1 = &b2[1][2];  // GOOD: address is only stored in another local variable

  s.p3 = b3;            // GOOD: address is only stored in another local variable
  s.p3 = &b3[1];        // GOOD: address is only stored in another local variable
  s.p2 = b3[1];         // GOOD: address is only stored in another local variable
  s.p2 = &b3[1][2];     // GOOD: address is only stored in another local variable
  s.p1 = b3[1][2];      // GOOD: address is only stored in another local variable
  s.p1 = &b3[1][2][3];  // GOOD: address is only stored in another local variable

  // Even though s is local, we don't know that s.pp is local because
  // there is a pointer indirection involved.
  s.pp[0] = b1;            // $ Alert // BAD: address of local variable stored in non-local memory.
  s.pp[0] = &b1[1];        // $ Alert // BAD: address of local variable stored in non-local memory.
  s.pp[0] = b2[1];         // $ Alert // BAD: address of local variable stored in non-local memory.
  s.pp[0] = &b2[1][2];     // $ Alert // BAD: address of local variable stored in non-local memory.
  s.pp[0] = b3[1][2];      // $ Alert // BAD: address of local variable stored in non-local memory.
  s.pp[0] = &b3[1][2][3];  // $ Alert // BAD: address of local variable stored in non-local memory.
}

void test303() {
  static S300 s;
  S300 x;

  s.p1 = x.a1;      // $ Alert // BAD: address of local variable stored in non-local memory.
  s.p1 = &x.a1[1];  // $ Alert // BAD: address of local variable stored in non-local memory.

  s.p2 = x.a2;         // $ Alert // BAD: address of local variable stored in non-local memory.
  s.p2 = &x.a2[1];     // $ Alert // BAD: address of local variable stored in non-local memory.
  s.p1 = x.a2[1];      // $ Alert // BAD: address of local variable stored in non-local memory.
  s.p1 = &x.a2[1][2];  // $ Alert // BAD: address of local variable stored in non-local memory.

  s.p3 = x.a3;            // $ Alert // BAD: address of local variable stored in non-local memory.
  s.p3 = &x.a3[1];        // $ Alert // BAD: address of local variable stored in non-local memory.
  s.p2 = x.a3[1];         // $ Alert // BAD: address of local variable stored in non-local memory.
  s.p2 = &x.a3[1][2];     // $ Alert // BAD: address of local variable stored in non-local memory.
  s.p1 = x.a3[1][2];      // $ Alert // BAD: address of local variable stored in non-local memory.
  s.p1 = &x.a3[1][2][3];  // $ Alert // BAD: address of local variable stored in non-local memory.

  // Even though s is local, we don't know that s.pp is local because
  // there is a pointer indirection involved.
  s.pp[0] = x.a1;            // $ Alert // BAD: address of local variable stored in non-local memory.
  s.pp[0] = &x.a1[1];        // $ Alert // BAD: address of local variable stored in non-local memory.
  s.pp[0] = x.a2[1];         // $ Alert // BAD: address of local variable stored in non-local memory.
  s.pp[0] = &x.a2[1][2];     // $ Alert // BAD: address of local variable stored in non-local memory.
  s.pp[0] = x.a3[1][2];      // $ Alert // BAD: address of local variable stored in non-local memory.
  s.pp[0] = &x.a3[1][2][3];  // $ Alert // BAD: address of local variable stored in non-local memory.
}

void test304() {
  S300 s;
  S300 x;

  s.p1 = x.a1;      // GOOD: address is only stored in another local variable
  s.p1 = &x.a1[1];  // GOOD: address is only stored in another local variable

  s.p2 = x.a2;         // GOOD: address is only stored in another local variable
  s.p2 = &x.a2[1];     // GOOD: address is only stored in another local variable
  s.p1 = x.a2[1];      // GOOD: address is only stored in another local variable
  s.p1 = &x.a2[1][2];  // GOOD: address is only stored in another local variable

  s.p3 = x.a3;            // GOOD: address is only stored in another local variable
  s.p3 = &x.a3[1];        // GOOD: address is only stored in another local variable
  s.p2 = x.a3[1];         // GOOD: address is only stored in another local variable
  s.p2 = &x.a3[1][2];     // GOOD: address is only stored in another local variable
  s.p1 = x.a3[1][2];      // GOOD: address is only stored in another local variable
  s.p1 = &x.a3[1][2][3];  // GOOD: address is only stored in another local variable

  // Even though s is local, we don't know that s.pp is local because
  // there is a pointer indirection involved.
  s.pp[0] = x.a1;            // $ Alert // BAD: address of local variable stored in non-local memory.
  s.pp[0] = &x.a1[1];        // $ Alert // BAD: address of local variable stored in non-local memory.
  s.pp[0] = x.a2[1];         // $ Alert // BAD: address of local variable stored in non-local memory.
  s.pp[0] = &x.a2[1][2];     // $ Alert // BAD: address of local variable stored in non-local memory.
  s.pp[0] = x.a3[1][2];      // $ Alert // BAD: address of local variable stored in non-local memory.
  s.pp[0] = &x.a3[1][2][3];  // $ Alert // BAD: address of local variable stored in non-local memory.
}

struct S400 {
  int* p0;
  int* p1[10];
  int* p2[10][11];
  int** q1;
  int** q2[10];
  int** q3[10][11];
  int* (*r2)[11];
  int* (*r3)[11][12];

  S400() {
    q1 = new int*[10];
    for (int i = 0; i < 10; i++) {
      q2[i] = new int*[11];
    }
    for (int i = 0; i < 10; i++) {
      for (int j = 0; j < 11; j++) {
        q3[i][j] = new int*[12];
      }
    }
    r2 = new int*[10][11];
    r3 = new int*[10][11][12];
  }
};

int test400() {
  S400 s;
  int x = 0;
  s.p0 = &x;           // GOOD: s.p0 is on the stack.
  s.p1[1] = &x;        // GOOD: s.p1 is on the stack.
  s.p2[1][2] = &x;     // GOOD: s.p1 is on the stack.
  s.q1[1] = &x;        // $ Alert // BAD: pointer indirection to the heap.
  s.q2[1][2] = &x;     // $ Alert // BAD: pointer indirection to the heap.
  s.q3[1][2][3] = &x;  // $ Alert // BAD: pointer indirection to the heap.
  s.r2[1][2] = &x;     // $ Alert // BAD: pointer indirection to the heap.
  s.r3[1][2][3] = &x;  // $ Alert // BAD: pointer indirection to the heap.
  return x;
}

class ListOnStack {
  int i_;
  ListOnStack *parent1_;
  ListOnStack *parent2_;
public:
  ListOnStack(int i, ListOnStack *parent)
    : i_(i), parent1_(parent)
  {
    // The assignment below is safe, because ListOnStack is always
    // allocated on the stack, so it cannot outlive the pointer.
    parent2_ = parent; // GOOD.
  }
};

void test500_impl(int n, ListOnStack *parent) {
  if (n > 0) {
    ListOnStack curr(n, parent);
    test500_impl(n-1, &curr);
  }
}

void test500() {
  test500_impl(10, 0);
}

class BaseClass600 {
  int *p_;
public:
  BaseClass600(int* p) {
    p_ = p;
  }
};

class DerivedClass600 : public BaseClass600 {
public:
  DerivedClass600(int* p) : BaseClass600(p) {}
};

void test600() {
  int i = 0;
  DerivedClass600 x(&i);
}

class BaseClass601 {
  int *p_;
public:
  BaseClass601(int* p) {
    p_ = p;
  }
};

class DerivedClass601 : public virtual BaseClass601 {
public:
  DerivedClass601(int* p) : BaseClass601(p) {}
};

void test601() {
  int i = 0;
  DerivedClass601 x(&i);
}

class DelegatingClass602 {
  int *p_;
  DelegatingClass602(int* p) : p_(p) {}
public:
  DelegatingClass602(int* p, int, int) : DelegatingClass602(p) {}
};

void test602() {
  int i = 0;
  DelegatingClass602 x(&i, 0, 0);
}

class BaseClass602 {
  int *p_;
public:
  BaseClass602(int* p) {
    p_ = p;
  }
};

class FieldInitClass602 {
  BaseClass602 base;
public:
  FieldInitClass602(int* p) : base(p) {}
};

void test603() {
  int i = 0;
  FieldInitClass602 x(&i);
}
