// RUN: %clang_cc1  -analyze -analyzer-checker=alpha.security.taint,debug.TaintTest %s -verify

#include <stdarg.h>

int scanf(const char *restrict format, ...);
int getchar(void);
typedef __typeof(sizeof(int)) size_t;

#define BUFSIZE 10
int Buffer[BUFSIZE];

struct XYStruct {
  int x;
  int y;
  char z;
};

void taintTracking(int x) {
  int n;
  int *addr = &Buffer[0];
  scanf("%d", &n);
  addr += n;// expected-warning + {{tainted}}
  *addr = n; // expected-warning + {{tainted}}

  double tdiv = n / 30; // expected-warning+ {{tainted}}
  char *loc_cast = (char *) n; // expected-warning +{{tainted}}
  char tinc = tdiv++; // expected-warning + {{tainted}}
  int tincdec = (char)tinc--; // expected-warning+{{tainted}}

  // Tainted ptr arithmetic/array element address.
  int tprtarithmetic1 = *(addr+1); // expected-warning + {{tainted}}

  // Dereference.
  int *ptr;
  scanf("%p", &ptr);
  int ptrDeref = *ptr; // expected-warning + {{tainted}}
  int _ptrDeref = ptrDeref + 13; // expected-warning + {{tainted}}

  // Pointer arithmetic + dereferencing.
  // FIXME: We fail to propagate the taint here because RegionStore does not
  // handle ElementRegions with symbolic indexes.
  int addrDeref = *addr; // expected-warning + {{tainted}}
  int _addrDeref = addrDeref; // expected-warning + {{tainted}}

  // Tainted struct address, casts.
  struct XYStruct *xyPtr = 0;
  scanf("%p", &xyPtr);
  void *tXYStructPtr = xyPtr; // expected-warning + {{tainted}}
  struct XYStruct *xyPtrCopy = tXYStructPtr; // expected-warning + {{tainted}}
  int ptrtx = xyPtr->x;// expected-warning + {{tainted}}
  int ptrty = xyPtr->y;// expected-warning + {{tainted}}

  // Taint on fields of a struct.
  struct XYStruct xy = {2, 3, 11};
  scanf("%d", &xy.y);
  scanf("%d", &xy.x);
  int tx = xy.x; // expected-warning + {{tainted}}
  int ty = xy.y; // FIXME: This should be tainted as well.
  char ntz = xy.z;// no warning
  // Now, scanf scans both.
  scanf("%d %d", &xy.y, &xy.x);
  int ttx = xy.x; // expected-warning + {{tainted}}
  int tty = xy.y; // expected-warning + {{tainted}}
}

void BitwiseOp(int in, char inn) {
  // Taint on bitwise operations, integer to integer cast.
  int m;
  int x = 0;
  scanf("%d", &x);
  int y = (in << (x << in)) * 5;// expected-warning + {{tainted}}
  // The next line tests integer to integer cast.
  int z = y & inn; // expected-warning + {{tainted}}
  if (y == 5) // expected-warning + {{tainted}}
    m = z | z;// expected-warning + {{tainted}}
  else
    m = inn;
  int mm = m; // expected-warning + {{tainted}}
}

// Test getenv.
char *getenv(const char *name);
void getenvTest(char *home) {
  home = getenv("HOME"); // expected-warning + {{tainted}}
  if (home != 0) { // expected-warning + {{tainted}}
      char d = home[0]; // expected-warning + {{tainted}}
    }
}

typedef struct _FILE FILE;
extern FILE *stdin;
extern FILE *stdout;
extern FILE *stderr;
int fscanf(FILE *restrict stream, const char *restrict format, ...);
int fprintf(FILE *stream, const char *format, ...);
int fclose(FILE *stream);
FILE *fopen(const char *path, const char *mode);

int fscanfTest(void) {
  FILE *fp;
  char s[80];
  int t;

  // Check if stdin is treated as tainted.
  fscanf(stdin, "%s %d", s, &t);
  // Note, here, s is not tainted, but the data s points to is tainted.
  char *ts = s;
  char tss = s[0]; // expected-warning + {{tainted}}
  int tt = t; // expected-warning + {{tainted}}
  if((fp=fopen("test", "w")) == 0) // expected-warning + {{tainted}}
    return 1;
  fprintf(fp, "%s %d", s, t); // expected-warning + {{tainted}}
  fclose(fp); // expected-warning + {{tainted}}

  // Test fscanf and fopen.
  if((fp=fopen("test","r")) == 0) // expected-warning + {{tainted}}
    return 1;
  fscanf(fp, "%s%d", s, &t); // expected-warning + {{tainted}}
  fprintf(stdout, "%s %d", s, t); // expected-warning + {{tainted}}
  return 0;
}

// Check if we propagate taint from stdin when it's used in an assignment.
void stdinTest1() {
  int i;
  fscanf(stdin, "%d", &i);
  int j = i; // expected-warning + {{tainted}}
}
void stdinTest2(FILE *pIn) {
  FILE *p = stdin;
  FILE *pp = p;
  int ii;

  fscanf(pp, "%d", &ii);
  int jj = ii;// expected-warning + {{tainted}}

  fscanf(p, "%d", &ii);
  int jj2 = ii;// expected-warning + {{tainted}}

  ii = 3;
  int jj3 = ii;// no warning

  p = pIn;
  fscanf(p, "%d", &ii);
  int jj4 = ii;// no warning
}

void stdinTest3() {
  FILE **ppp = &stdin;
  int iii;
  fscanf(*ppp, "%d", &iii);
  int jjj = iii;// expected-warning + {{tainted}}
}

// Test that stdin does not get invalidated by calls.
void foo();
void stdinTest4() {
  int i;
  fscanf(stdin, "%d", &i);
  foo();
  int j = i; // expected-warning + {{tainted}}
}

int getw(FILE *);
void getwTest() {
  int i = getw(stdin); // expected-warning + {{tainted}}
}

typedef long ssize_t;
ssize_t getline(char ** __restrict, size_t * __restrict, FILE * __restrict);
int  printf(const char * __restrict, ...);
void free(void *ptr);
void getlineTest(void) {
  FILE *fp;
  char *line = 0;
  size_t len = 0;
  ssize_t read;
  while ((read = getline(&line, &len, stdin)) != -1) {
    printf("%s", line); // expected-warning + {{tainted}}
  }
  free(line); // expected-warning + {{tainted}}
}

// Test propagation functions - the ones that propagate taint from arguments to
// return value, ptr arguments.

int atoi(const char *nptr);
long atol(const char *nptr);
long long atoll(const char *nptr);

void atoiTest() {
  char s[80];
  scanf("%s", s);
  int d = atoi(s); // expected-warning + {{tainted}}
  int td = d; // expected-warning + {{tainted}}

  long l = atol(s); // expected-warning + {{tainted}}
  int tl = l; // expected-warning + {{tainted}}

  long long ll = atoll(s); // expected-warning + {{tainted}}
  int tll = ll; // expected-warning + {{tainted}}

}

