Fix a bug in the readdir_r interceptor: when we reach the end of the
directory stream, the entry is not written to, instead *result is set to NULL and the entry is not written to at all. I'm still somewhat suspicious of the correct instrumention here -- I feel like it should be marking the written range as the pointer in *result and the length (*result)->d_reclen in case the implementation decides not to use the passed-in entry (if that's even allowed). Finally, the definition of 'struct dirent' analog used in the interceptor is wrong in 32-bit mode with _FILE_OFFSET_BITS=64 as it hard codes the use of a pointer-sized offset. I've added a somewhat goofy test for the bug I fixed via ASan -- suggestions on how to better test the interceptor logic itself welcome. llvm-svn: 185998
This commit is contained in:
parent
ed5fe90bb8
commit
28c1b294b8
|
@ -0,0 +1,30 @@
|
|||
// RUN: %clangxx_asan -O0 %s -DTEMP_DIR='"'"%T"'"' -o %t && %t 2>&1 | FileCheck %s
|
||||
// RUN: %clangxx_asan -O1 %s -DTEMP_DIR='"'"%T"'"' -o %t && %t 2>&1 | FileCheck %s
|
||||
// RUN: %clangxx_asan -O2 %s -DTEMP_DIR='"'"%T"'"' -o %t && %t 2>&1 | FileCheck %s
|
||||
// RUN: %clangxx_asan -O3 %s -DTEMP_DIR='"'"%T"'"' -o %t && %t 2>&1 | FileCheck %s
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
|
||||
|
||||
int main() {
|
||||
// Ensure the readdir_r interceptor doesn't erroneously mark the entire dirent
|
||||
// as written when the end of the directory pointer is reached.
|
||||
fputs("reading the " TEMP_DIR " directory...\n", stderr);
|
||||
DIR *d = opendir(TEMP_DIR);
|
||||
struct dirent entry, *result;
|
||||
unsigned count = 0;
|
||||
do {
|
||||
// Stamp the entry struct to try to trick the interceptor.
|
||||
entry.d_reclen = 9999;
|
||||
if (readdir_r(d, &entry, &result) != 0)
|
||||
abort();
|
||||
++count;
|
||||
} while (result != NULL);
|
||||
fprintf(stderr, "read %d entries\n", count);
|
||||
// CHECK: reading the {{.*}} directory...
|
||||
// CHECK-NOT: stack-buffer-overflow
|
||||
// CHECK: read {{.*}} entries
|
||||
}
|
|
@ -1374,7 +1374,7 @@ INTERCEPTOR(int, readdir_r, void *dirp, __sanitizer_dirent *entry,
|
|||
if (!res) {
|
||||
if (result)
|
||||
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
|
||||
if (entry)
|
||||
if (entry && *result)
|
||||
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, entry, entry->d_reclen);
|
||||
}
|
||||
return res;
|
||||
|
|
Loading…
Reference in New Issue