| 1 | // FIXME: https://code.google.com/p/address-sanitizer/issues/detail?id=316 |
| 2 | // XFAIL: android |
| 3 | |
| 4 | // RUN: rm -rf %t-dir |
| 5 | // RUN: mkdir -p %t-dir |
| 6 | // |
| 7 | // RUN: %clangxx_asan -O0 %s -DTEMP_DIR='"'"%t-dir"'"' -o %t && %run %t 2>&1 | FileCheck %s |
| 8 | // RUN: %clangxx_asan -O1 %s -DTEMP_DIR='"'"%t-dir"'"' -o %t && %run %t 2>&1 | FileCheck %s |
| 9 | // RUN: %clangxx_asan -O2 %s -DTEMP_DIR='"'"%t-dir"'"' -o %t && %run %t 2>&1 | FileCheck %s |
| 10 | // RUN: %clangxx_asan -O3 %s -DTEMP_DIR='"'"%t-dir"'"' -o %t && %run %t 2>&1 | FileCheck %s |
| 11 | // |
| 12 | // RUN: %clangxx_asan -O0 %s -D_FILE_OFFSET_BITS=64 -DTEMP_DIR='"'"%t-dir"'"' -o %t && %run %t 2>&1 | FileCheck %s |
| 13 | // RUN: %clangxx_asan -O1 %s -D_FILE_OFFSET_BITS=64 -DTEMP_DIR='"'"%t-dir"'"' -o %t && %run %t 2>&1 | FileCheck %s |
| 14 | // RUN: %clangxx_asan -O2 %s -D_FILE_OFFSET_BITS=64 -DTEMP_DIR='"'"%t-dir"'"' -o %t && %run %t 2>&1 | FileCheck %s |
| 15 | // RUN: %clangxx_asan -O3 %s -D_FILE_OFFSET_BITS=64 -DTEMP_DIR='"'"%t-dir"'"' -o %t && %run %t 2>&1 | FileCheck %s |
| 16 | |
| 17 | #include <dirent.h> |
| 18 | #include <memory.h> |
| 19 | #include <stdio.h> |
| 20 | #include <stdlib.h> |
| 21 | #include <unistd.h> |
| 22 | |
| 23 | |
| 24 | int main() { |
| 25 | // Ensure the readdir_r interceptor doesn't erroneously mark the entire dirent |
| 26 | // as written when the end of the directory pointer is reached. |
| 27 | fputs("test1: reading the " TEMP_DIR " directory...\n" , stderr); |
| 28 | DIR *d = opendir(TEMP_DIR); |
| 29 | struct dirent *result = (struct dirent *)(0xfeedbeef); |
| 30 | // We assume the temp dir for this test doesn't have crazy long file names. |
| 31 | char entry_buffer[4096]; |
| 32 | memset(s: entry_buffer, c: 0xab, n: sizeof(entry_buffer)); |
| 33 | unsigned count = 0; |
| 34 | do { |
| 35 | // Stamp the entry struct to try to trick the interceptor. |
| 36 | ((struct dirent *)entry_buffer)->d_reclen = 9999; |
| 37 | if (readdir_r(dirp: d, entry: (struct dirent *)entry_buffer, result: &result) != 0) |
| 38 | abort(); |
| 39 | ++count; |
| 40 | } while (result != NULL); |
| 41 | fprintf(stderr, format: "read %d entries\n" , count); |
| 42 | closedir(dirp: d); |
| 43 | // CHECK: test1: reading the {{.*}} directory... |
| 44 | // CHECK-NOT: stack-buffer-overflow |
| 45 | // CHECK: read {{.*}} entries |
| 46 | |
| 47 | // Ensure the readdir64_r interceptor doesn't have the bug either. |
| 48 | fputs("test2: reading the " TEMP_DIR " directory...\n" , stderr); |
| 49 | d = opendir(TEMP_DIR); |
| 50 | struct dirent64 *result64; |
| 51 | memset(s: entry_buffer, c: 0xab, n: sizeof(entry_buffer)); |
| 52 | count = 0; |
| 53 | do { |
| 54 | // Stamp the entry struct to try to trick the interceptor. |
| 55 | ((struct dirent64 *)entry_buffer)->d_reclen = 9999; |
| 56 | if (readdir64_r(dirp: d, entry: (struct dirent64 *)entry_buffer, result: &result64) != 0) |
| 57 | abort(); |
| 58 | ++count; |
| 59 | } while (result64 != NULL); |
| 60 | fprintf(stderr, format: "read %d entries\n" , count); |
| 61 | closedir(dirp: d); |
| 62 | // CHECK: test2: reading the {{.*}} directory... |
| 63 | // CHECK-NOT: stack-buffer-overflow |
| 64 | // CHECK: read {{.*}} entries |
| 65 | } |
| 66 | |