brintos

brintos / llvm-project-archived public Read only

0
0
Text · 17.3 KiB · e3463bc Raw
476 lines · c
1// RUN: %clang_analyze_cc1 -verify %s \2// RUN:   -triple x86_64-linux-gnu  \3// RUN:   -analyzer-checker=core,unix.Stream,optin.taint \4// RUN:   -analyzer-checker=debug.ExprInspection5 6#include "Inputs/system-header-simulator-for-simple-stream.h"7 8#define EOF (-1)9 10void clang_analyzer_dump(int);11void clang_analyzer_dump_char(char);12void clang_analyzer_isTainted(int);13void clang_analyzer_warnIfReached(void);14 15// A stream is only tracked by StreamChecker if it results from a call to "fopen".16// Otherwise, there is no specific modelling of "fread".17void untracked_stream(FILE *fp) {18  char c;19  if (1 == fread(&c, 1, 1, fp)) {20    char p = c; // Unknown value but not garbage and not modeled by checker.21  } else {22    char p = c; // Possibly indeterminate value but not modeled by checker.23  }24}25 26void fgetc_props_taint(void) {27  FILE *fp = fopen("/home/test", "rb+");28  if (fp) {29    int c = fgetc(fp); // c is tainted.30    if (c != EOF) {31      clang_analyzer_isTainted(c); // expected-warning{{YES}}32    }33    fclose(fp);34  }35}36 37void fread_props_taint(void) {38  FILE *fp = fopen("/home/test", "rb+");39  if (fp) {40    char buffer[10];41    int c = fread(buffer, 1, 10, fp); // c is tainted.42    if (c != 10) {43      // If the read failed, then the number of bytes successfully read should be tainted.44      clang_analyzer_isTainted(c); // expected-warning{{YES}}45    }46    fclose(fp);47  }48}49 50void read_one_byte1(void) {51  FILE *fp = fopen("/home/test", "rb+");52  if (fp) {53    char c;54    if (1 == fread(&c, 1, 1, fp)) {55      char p = c; // Unknown value but not garbage.56      clang_analyzer_isTainted(p); // expected-warning{{YES}}57    } else {58      char p = c; // Possibly indeterminate value but not modeled by checker.59      clang_analyzer_isTainted(p); // expected-warning{{YES}}60    }61    fclose(fp);62  }63}64 65void read_one_byte2(char *buffer) {66  FILE *fp = fopen("/home/test", "rb+");67  if (fp) {68    if (1 == fread(buffer, 1, 1, fp)) {69      char p = buffer[0]; // Unknown value but not garbage.70      clang_analyzer_isTainted(p); // expected-warning{{YES}}71    } else {72      char p = buffer[0]; // Possibly indeterminate value but not modeled by checker.73      clang_analyzer_isTainted(p); // expected-warning{{YES}}74    }75    fclose(fp);76  }77}78 79void read_one_byte3(char *buffer) {80  buffer[1] = 10;81  FILE *fp = fopen("/home/test", "rb+");82  if (fp) {83    // buffer[1] is not mutated by fread and remains not tainted.84    fread(buffer, 1, 1, fp);85    char p = buffer[1];86    clang_analyzer_isTainted(p); // expected-warning{{NO}}87    clang_analyzer_dump(buffer[1]); // expected-warning{{10 S32b}}88    fclose(fp);89  }90}91 92void read_many_bytes(char *buffer) {93  FILE *fp = fopen("/home/test", "rb+");94  if (fp) {95    if (42 == fread(buffer, 1, 42, fp)) {96      char p = buffer[0]; // Unknown value but not garbage.97      clang_analyzer_isTainted(p); // expected-warning{{YES}}98    } else {99      char p = buffer[0]; // Possibly indeterminate value but not modeled.100      clang_analyzer_isTainted(p); // expected-warning{{YES}}101    }102    fclose(fp);103  }104}105 106void random_access_read1(int index) {107  FILE *fp = fopen("/home/test", "rb+");108  if (fp) {109    long c[4];110    int success = 2 == fread(c + 1, sizeof(long), 2, fp);111 112    switch (index) {113    case 0:114      // c[0] is not mutated by fread.115      if (success) {116        char p = c[0]; // expected-warning {{Assigned value is uninitialized}} We kept the first byte intact.117      } else {118        char p = c[0]; // expected-warning {{Assigned value is uninitialized}} We kept the first byte intact.119      }120      break;121 122    case 1:123      if (success) {124        // Unknown value but not garbage.125        clang_analyzer_isTainted(c[1]); // expected-warning {{YES}}126        clang_analyzer_dump(c[1]); // expected-warning {{conj_}}127      } else {128        // Possibly indeterminate value but not modeled.129        clang_analyzer_isTainted(c[1]); // expected-warning {{YES}}130        clang_analyzer_dump(c[1]); // expected-warning {{conj_}}131      }132      break;133 134    case 2:135      if (success) {136        long p = c[2]; // Unknown value but not garbage.137        // FIXME: Taint analysis only marks the first byte of a memory region. See getPointeeOf in GenericTaintChecker.cpp.138        clang_analyzer_isTainted(c[2]); // expected-warning {{NO}}139        clang_analyzer_dump(c[2]); // expected-warning {{conj_}}140      } else {141        // Possibly indeterminate value but not modeled.142        clang_analyzer_isTainted(c[2]); // expected-warning {{NO}} // FIXME: See above.143        clang_analyzer_dump(c[2]); // expected-warning {{conj_}}144      }145      break;146 147    case 3:148      // c[3] is not mutated by fread.149      if (success) {150        long p = c[3]; // expected-warning {{Assigned value is uninitialized}}151      } else {152        long p = c[3]; // expected-warning {{Assigned value is uninitialized}}153      }154      break;155    }156 157    fclose(fp);158  }159}160 161void random_access_read2(int b) {162  FILE *fp = fopen("/home/test", "rb+");163  if (fp) {164    int buffer[10];165    int *ptr = buffer + 2;166    if (5 == fread(ptr - 1, sizeof(int), 5, fp)) {167      if (b) {168        int p = buffer[1]; // Unknown value but not garbage.169        clang_analyzer_isTainted(p); // expected-warning {{YES}}170        clang_analyzer_dump(p); // expected-warning {{conj_}}171      } else {172        int p = buffer[0]; // expected-warning {{Assigned value is uninitialized}}173      }174    } else {175      int p = buffer[0]; // expected-warning {{Assigned value is uninitialized}}176    }177    fclose(fp);178  }179}180 181void random_access_read_symbolic_count(size_t count) {182  // Cover a case that used to crash (symbolic count).183  if (count > 2)184    return;185 186  FILE *fp = fopen("/home/test", "rb+");187  if (fp) {188    long c[4];189    fread(c + 1, sizeof(long), count, fp);190 191    // c[0] and c[3] are never mutated by fread, but because "count" is a symbolic value, the checker doesn't know that.192    long p = c[0];193    clang_analyzer_isTainted(p); // expected-warning {{NO}}194    clang_analyzer_dump(p); // expected-warning {{derived_}}195 196    p = c[3];197    clang_analyzer_isTainted(p); // expected-warning {{NO}}198    clang_analyzer_dump(p); // expected-warning {{derived_}}199 200    p = c[1];201    clang_analyzer_isTainted(p); // expected-warning {{YES}}202    clang_analyzer_dump(p); // expected-warning {{derived_}}203 204    fclose(fp);205  }206}207 208void dynamic_random_access_read(int startIndex) {209  FILE *fp = fopen("/home/test", "rb+");210  if (fp) {211    long buffer[10];212    // Cannot reason about index.213    size_t res = fread(buffer + startIndex, sizeof(long), 5, fp);214    long *p = &buffer[startIndex];215    long v = 0;216 217    // If all 5 elements were successfully read, then all 5 elements should be tainted and considered initialized.218    if (5 == res) {219      // FIXME: These should be tainted.220      clang_analyzer_isTainted((v = p[0])); // expected-warning {{NO}}221      clang_analyzer_isTainted((v = p[1])); // expected-warning {{NO}}222      clang_analyzer_isTainted((v = p[2])); // expected-warning {{NO}}223      clang_analyzer_isTainted((v = p[3])); // expected-warning {{NO}}224      clang_analyzer_isTainted((v = p[4])); // expected-warning {{NO}}225      clang_analyzer_dump((v = p[0])); // expected-warning {{conj_}} ok226      clang_analyzer_dump((v = p[1])); // expected-warning {{conj_}} ok227      clang_analyzer_dump((v = p[2])); // expected-warning {{conj_}} ok228      clang_analyzer_dump((v = p[3])); // expected-warning {{conj_}} ok229      clang_analyzer_dump((v = p[4])); // expected-warning {{conj_}} ok230      clang_analyzer_dump((v = p[5])); // expected-warning {{conj_}} FIXME: This should raise an uninit read.231    } else if (res == 4) {232      // If only the first 4 elements were successfully read,233      // then only the first 4 elements should be tainted and considered initialized.234      // FIXME: These should be tainted.235      clang_analyzer_isTainted((v = p[0])); // expected-warning {{NO}}236      clang_analyzer_isTainted((v = p[1])); // expected-warning {{NO}}237      clang_analyzer_isTainted((v = p[2])); // expected-warning {{NO}}238      clang_analyzer_isTainted((v = p[3])); // expected-warning {{NO}}239      clang_analyzer_dump((v = p[0])); // expected-warning {{conj_}} ok240      clang_analyzer_dump((v = p[1])); // expected-warning {{conj_}} ok241      clang_analyzer_dump((v = p[2])); // expected-warning {{conj_}} ok242      clang_analyzer_dump((v = p[3])); // expected-warning {{conj_}} ok243      clang_analyzer_dump((v = p[4])); // expected-warning {{conj_}} FIXME: This should raise an uninit read.244    } else {245      // Neither 5, or 4 elements were successfully read, so we must have read from 0 up to 3 elements.246      // FIXME: These should be tainted.247      clang_analyzer_isTainted((v = p[0])); // expected-warning {{NO}}248      clang_analyzer_isTainted((v = p[1])); // expected-warning {{NO}}249      clang_analyzer_isTainted((v = p[2])); // expected-warning {{NO}}250      clang_analyzer_dump((v = p[0])); // expected-warning {{conj_}} ok251      clang_analyzer_dump((v = p[1])); // expected-warning {{conj_}} ok252      clang_analyzer_dump((v = p[2])); // expected-warning {{conj_}} ok253      clang_analyzer_dump((v = p[3])); // expected-warning {{conj_}} FIXME: This should raise an uninit read.254    }255    fclose(fp);256  }257}258 259struct S {260  int a;261  long b;262};263 264void compound_read1(void) {265  FILE *fp = fopen("/home/test", "rb+");266  if (fp) {267    struct S s; // s.a is not touched by fread.268    if (1 == fread(&s.b, sizeof(s.b), 1, fp)) {269      long p = s.b;270      clang_analyzer_isTainted(p); // expected-warning {{YES}}271      clang_analyzer_dump(p); // expected-warning {{conj_}}272    } else {273      long p = s.b;274      clang_analyzer_isTainted(p); // expected-warning {{YES}}275      clang_analyzer_dump(p); // expected-warning {{conj_}}276    }277    fclose(fp);278  }279}280 281void compound_read2(void) {282  FILE *fp = fopen("/home/test", "rb+");283  if (fp) {284    struct S s; // s.a is not touched by fread.285    if (1 == fread(&s.b, sizeof(s.b), 1, fp)) {286      long p = s.a; // expected-warning {{Assigned value is uninitialized}}287    } else {288      long p = s.a; // expected-warning {{Assigned value is uninitialized}}289    }290    fclose(fp);291  }292}293 294void var_read(void) {295  FILE *fp = fopen("/home/test", "rb+");296  if (fp) {297    int a, b; // 'a' is not touched by fread.298    if (1 == fread(&b, sizeof(b), 1, fp)) {299      long p = a; // expected-warning{{Assigned value is uninitialized}}300    } else {301      long p = a; // expected-warning{{Assigned value is uninitialized}}302    }303    fclose(fp);304  }305}306 307// When reading a lot of data, invalidating all elements is too time-consuming.308// Instead, the knowledge of the whole array is lost.309#define MaxInvalidatedElementRegion 64 // See StreamChecker::evalFreadFwrite in StreamChecker.cpp.310#define PastMaxComplexity MaxInvalidatedElementRegion + 1311void test_large_read(void) {312  int buffer[PastMaxComplexity + 1];313  buffer[PastMaxComplexity] = 42;314  FILE *fp = fopen("/home/test", "rb+");315  if (fp) {316    if (buffer[PastMaxComplexity] != 42) {317      clang_analyzer_warnIfReached(); // Unreachable.318    }319    if (1 == fread(buffer, sizeof(int), PastMaxComplexity, fp)) {320      if (buffer[PastMaxComplexity] != 42) {321        clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}322      }323    }324    fclose(fp);325  }326}327 328void test_small_read(void) {329  int buffer[10];330  buffer[5] = 42;331  FILE *fp = fopen("/home/test", "rb+");332  if (fp) {333    clang_analyzer_dump(buffer[5]); // expected-warning{{42 S32b}}334    if (1 == fread(buffer, sizeof(int), 5, fp)) {335      clang_analyzer_dump(buffer[5]); // expected-warning{{42 S32b}}336    }337    fclose(fp);338  }339}340 341void test_partial_elements_read(void) {342  clang_analyzer_dump(sizeof(int)); // expected-warning {{4 S32b}}343 344  int buffer[100];345  buffer[0] = 1;346  buffer[1] = 2;347  buffer[2] = 3;348  buffer[3] = 4;349  buffer[4] = 5;350  buffer[5] = 6;351  FILE *fp = fopen("/home/test", "rb+");352  if (fp) {353    // 3*5: 15 bytes read; which is not exactly 4 integers, but we still invalidate the first 4 ints.354    if (5 == fread(buffer + 1, 3, 5, fp)) {355      clang_analyzer_dump(buffer[0]); // expected-warning{{1 S32b}}356      clang_analyzer_dump(buffer[1]); // expected-warning{{conj_}}357      clang_analyzer_dump(buffer[2]); // expected-warning{{conj_}}358      clang_analyzer_dump(buffer[3]); // expected-warning{{conj_}}359      clang_analyzer_dump(buffer[4]); // expected-warning{{conj_}}360      clang_analyzer_dump(buffer[5]); // expected-warning{{6 S32b}}361 362      char *c = (char*)buffer;363      clang_analyzer_dump(c[4+12]); // expected-warning{{conj_}} 16th byte of buffer, which is the beginning of the 4th 'int' in the buffer.364 365      // FIXME: The store should have returned a partial binding for the 17th byte of the buffer, which is the 2nd byte of the previous int.366      // This byte should have been initialized by the 'fread' earlier. However, the Store lies to us and says it's uninitialized.367      clang_analyzer_dump(c[4+13]); // expected-warning{{1st function call argument is an uninitialized value}} should be initialized.368      clang_analyzer_dump(c[4+16]); // This should be the first byte that 'fread' leaves uninitialized. This should raise the uninit read diag.369    } else {370      clang_analyzer_dump(buffer[0]); // expected-warning{{1 S32b}} ok371      clang_analyzer_dump(buffer[1]); // expected-warning{{conj_}} ok372      clang_analyzer_dump(buffer[2]); // expected-warning{{conj_}} ok373      clang_analyzer_dump(buffer[3]); // expected-warning{{conj_}} ok374      clang_analyzer_dump(buffer[4]); // expected-warning{{conj_}} ok, but an uninit warning would be also fine.375      clang_analyzer_dump(buffer[5]); // expected-warning{{6 S32b}} ok376      clang_analyzer_dump(buffer[6]); // expected-warning{{1st function call argument is an uninitialized value}} ok377    }378    fclose(fp);379  }380}381 382void test_whole_elements_read(void) {383  clang_analyzer_dump(sizeof(int)); // expected-warning {{4 S32b}}384 385  int buffer[100];386  buffer[0] = 1;387  buffer[15] = 2;388  buffer[16] = 3;389  FILE *fp = fopen("/home/test", "rb+");390  if (fp) {391    // 3*20: 60 bytes read; which is basically 15 integers.392    if (20 == fread(buffer + 1, 3, 20, fp)) {393      clang_analyzer_dump(buffer[0]);  // expected-warning{{1 S32b}}394      clang_analyzer_dump(buffer[15]); // expected-warning{{conj_}}395      clang_analyzer_dump(buffer[16]); // expected-warning{{3 S32b}}396      clang_analyzer_dump(buffer[17]); // expected-warning{{1st function call argument is an uninitialized value}}397    } else {398      clang_analyzer_dump(buffer[0]);  // expected-warning{{1 S32b}}399      clang_analyzer_dump(buffer[15]); // expected-warning{{conj_}}400      clang_analyzer_dump(buffer[16]); // expected-warning{{3 S32b}}401      clang_analyzer_dump(buffer[17]); // expected-warning{{1st function call argument is an uninitialized value}}402    }403    fclose(fp);404  }405}406 407void test_unaligned_start_read(void) {408  clang_analyzer_dump(sizeof(int)); // expected-warning {{4 S32b}}409 410  int buffer[100];411  buffer[0] = 3;412  buffer[1] = 4;413  buffer[2] = 5;414  char *asChar = (char*)buffer;415 416  FILE *fp = fopen("/home/test", "rb+");417  if (fp) {418    // We have an 'int' binding at offset 0 of value 3.419    // We read 4 bytes at byte offset: 1,2,3,4.420    if (4 == fread(asChar + 1, 1, 4, fp)) {421      clang_analyzer_dump(buffer[0]); // expected-warning{{3 S32b}} FIXME: The int binding should have been partially overwritten by the read call. This definitely should not be 3.422      clang_analyzer_dump(buffer[1]); // expected-warning{{conj_}}423      clang_analyzer_dump(buffer[2]); // expected-warning{{5 S32b}}424 425      clang_analyzer_dump_char(asChar[0]); // expected-warning{{3 S8b}} This is technically true assuming x86 (little-endian) architecture.426      clang_analyzer_dump_char(asChar[1]); // expected-warning{{conj_}} 1427      clang_analyzer_dump_char(asChar[2]); // expected-warning{{conj_}} 2428      clang_analyzer_dump_char(asChar[3]); // expected-warning{{conj_}} 3429      clang_analyzer_dump_char(asChar[4]); // expected-warning{{conj_}} 4430      clang_analyzer_dump_char(asChar[5]); // expected-warning{{1st function call argument is an uninitialized value}}431    } else {432      clang_analyzer_dump(buffer[0]); // expected-warning{{3 S32b}} FIXME: The int binding should have been partially overwritten by the read call. This definitely should not be 3.433      clang_analyzer_dump(buffer[1]); // expected-warning{{conj_}}434      clang_analyzer_dump(buffer[2]); // expected-warning{{5 S32b}}435 436      clang_analyzer_dump_char(asChar[0]); // expected-warning{{3 S8b}} This is technically true assuming x86 (little-endian) architecture.437      clang_analyzer_dump_char(asChar[1]); // expected-warning{{conj_}} 1438      clang_analyzer_dump_char(asChar[2]); // expected-warning{{conj_}} 2439      clang_analyzer_dump_char(asChar[3]); // expected-warning{{conj_}} 3440      clang_analyzer_dump_char(asChar[4]); // expected-warning{{conj_}} 4441      clang_analyzer_dump_char(asChar[5]); // expected-warning{{1st function call argument is an uninitialized value}}442    }443    fclose(fp);444  }445}446 447void no_crash_if_count_is_negative(long l, long r, unsigned char *buffer) {448  FILE *fp = fopen("path", "r");449  if (fp) {450    if (l * r == -1) {451      fread(buffer, 1, l * r, fp); // no-crash452    }453    fclose(fp);454  }455}456 457void no_crash_if_size_is_negative(long l, long r, unsigned char *buffer) {458  FILE *fp = fopen("path", "r");459  if (fp) {460    if (l * r == -1) {461      fread(buffer, l * r, 1, fp); // no-crash462    }463    fclose(fp);464  }465}466 467void no_crash_if_size_and_count_are_negative(long l, long r, unsigned char *buffer) {468  FILE *fp = fopen("path", "r");469  if (fp) {470    if (l * r == -1) {471      fread(buffer, l * r, l * r, fp); // no-crash472    }473    fclose(fp);474  }475}476