[Sanitizer] Teach ReadFileToBuffer to distinguish empty file from inaccessible file.

Summary:
This fixes https://code.google.com/p/address-sanitizer/issues/detail?id=399
(sanitizers crash with empty suppression files).

Reviewers: kcc

Subscribers: llvm-commits

Differential Revision: http://reviews.llvm.org/D11284

llvm-svn: 242594
This commit is contained in:
Alexey Samsonov 2015-07-17 23:50:08 +00:00
parent 2e309076f2
commit e6c614d48a
8 changed files with 45 additions and 35 deletions

View File

@ -140,40 +140,40 @@ void NORETURN CheckFailed(const char *file, int line, const char *cond,
Die();
}
uptr ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size,
uptr max_len, error_t *errno_p) {
bool ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size,
uptr *read_len, uptr max_len, error_t *errno_p) {
uptr PageSize = GetPageSizeCached();
uptr kMinFileLen = PageSize;
uptr read_len = 0;
*buff = 0;
*buff = nullptr;
*buff_size = 0;
*read_len = 0;
// The files we usually open are not seekable, so try different buffer sizes.
for (uptr size = kMinFileLen; size <= max_len; size *= 2) {
fd_t fd = OpenFile(file_name, RdOnly, errno_p);
if (fd == kInvalidFd) return 0;
if (fd == kInvalidFd) return false;
UnmapOrDie(*buff, *buff_size);
*buff = (char*)MmapOrDie(size, __func__);
*buff_size = size;
*read_len = 0;
// Read up to one page at a time.
read_len = 0;
bool reached_eof = false;
while (read_len + PageSize <= size) {
while (*read_len + PageSize <= size) {
uptr just_read;
if (!ReadFromFile(fd, *buff + read_len, PageSize, &just_read, errno_p)) {
if (!ReadFromFile(fd, *buff + *read_len, PageSize, &just_read, errno_p)) {
UnmapOrDie(*buff, *buff_size);
return 0;
return false;
}
if (just_read == 0) {
reached_eof = true;
break;
}
read_len += just_read;
*read_len += just_read;
}
CloseFile(fd);
if (reached_eof) // We've read the whole file.
break;
}
return read_len;
return true;
}
typedef bool UptrComparisonFunction(const uptr &a, const uptr &b);

View File

@ -228,10 +228,12 @@ bool SupportsColoredOutput(fd_t fd);
// Opens the file 'file_name" and reads up to 'max_len' bytes.
// The resulting buffer is mmaped and stored in '*buff'.
// The size of the mmaped region is stored in '*buff_size',
// Returns the number of read bytes or 0 if file can not be opened.
uptr ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size,
uptr max_len, error_t *errno_p = nullptr);
// The size of the mmaped region is stored in '*buff_size'.
// The total number of read bytes is stored in '*read_len'.
// Returns true if file was successfully opened and read.
bool ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size,
uptr *read_len, uptr max_len = 1 << 26,
error_t *errno_p = nullptr);
// Maps given file to virtual memory, and returns pointer to it
// (or NULL if mapping fails). Stores the size of mmaped region
// in '*buff_size'.

View File

@ -54,11 +54,10 @@ class FlagHandlerInclude : public FlagHandlerBase {
bool Parse(const char *value) final {
char *data;
uptr data_mapped_size;
uptr len;
error_t err;
uptr len =
ReadFileToBuffer(value, &data, &data_mapped_size,
Max(kMaxIncludeSize, GetPageSizeCached()), &err);
if (!len) {
if (!ReadFileToBuffer(value, &data, &data_mapped_size, &len,
Max(kMaxIncludeSize, GetPageSizeCached()), &err)) {
Printf("Failed to read options from '%s': error %d\n", value, err);
return false;
}

View File

@ -375,8 +375,8 @@ const char *GetEnv(const char *name) {
if (!inited) {
inited = true;
uptr environ_size;
len = ReadFileToBuffer("/proc/self/environ",
&environ, &environ_size, 1 << 26);
if (!ReadFileToBuffer("/proc/self/environ", &environ, &environ_size, &len))
environ = nullptr;
}
if (!environ || len == 0) return 0;
uptr namelen = internal_strlen(name);
@ -405,9 +405,13 @@ extern "C" {
static void ReadNullSepFileToArray(const char *path, char ***arr,
int arr_size) {
char *buff;
uptr buff_size = 0;
uptr buff_size;
uptr buff_len;
*arr = (char **)MmapOrDie(arr_size * sizeof(char *), "NullSepFileArray");
ReadFileToBuffer(path, &buff, &buff_size, 1024 * 1024);
if (!ReadFileToBuffer(path, &buff, &buff_size, &buff_len, 1024 * 1024)) {
(*arr)[0] = nullptr;
return;
}
(*arr)[0] = buff;
int count, i;
for (count = 1, i = 1; ; i++) {
@ -418,7 +422,7 @@ static void ReadNullSepFileToArray(const char *path, char ***arr,
count++;
}
}
(*arr)[count] = 0;
(*arr)[count] = nullptr;
}
#endif

View File

@ -153,8 +153,9 @@ uptr MemoryMappingLayout::DumpListOfModules(LoadedModule *modules,
void GetMemoryProfile(fill_profile_f cb, uptr *stats, uptr stats_size) {
char *smaps = 0;
uptr smaps_cap = 0;
uptr smaps_len = ReadFileToBuffer("/proc/self/smaps",
&smaps, &smaps_cap, 64<<20);
uptr smaps_len = 0;
if (!ReadFileToBuffer("/proc/self/smaps", &smaps, &smaps_cap, &smaps_len))
return;
uptr start = 0;
bool file = false;
const char *pos = smaps;

View File

@ -18,8 +18,8 @@
namespace __sanitizer {
void ReadProcMaps(ProcSelfMapsBuff *proc_maps) {
proc_maps->len = ReadFileToBuffer("/proc/self/maps", &proc_maps->data,
&proc_maps->mmaped_size, 1 << 26);
CHECK(ReadFileToBuffer("/proc/self/maps", &proc_maps->data,
&proc_maps->mmaped_size, &proc_maps->len));
}
static bool IsOneOf(char c, char c1, char c2) {

View File

@ -60,15 +60,13 @@ void SuppressionContext::ParseFromFile(const char *filename) {
}
// Read the file.
char *file_contents;
uptr buffer_size;
const uptr max_len = 1 << 26;
uptr contents_size =
ReadFileToBuffer(filename, &file_contents, &buffer_size, max_len);
VPrintf(1, "%s: reading suppressions file at %s\n",
SanitizerToolName, filename);
if (contents_size == 0) {
char *file_contents;
uptr buffer_size;
uptr contents_size;
if (!ReadFileToBuffer(filename, &file_contents, &buffer_size,
&contents_size)) {
Printf("%s: failed to read suppressions file '%s'\n", SanitizerToolName,
filename);
Die();

View File

@ -1,6 +1,10 @@
// RUN: LSAN_BASE="use_registers=0:use_stacks=0"
// RUN: %clangxx_lsan %s -o %t
// RUN: rm -f %t.supp
// RUN: touch %t.supp
// RUN: LSAN_OPTIONS="$LSAN_BASE:suppressions='%t.supp'" not %run %t 2>&1 | FileCheck %s --check-prefix=NOSUPP
// RUN: echo "leak:*LSanTestLeakingFunc*" > %t.supp
// RUN: LSAN_OPTIONS="$LSAN_BASE:suppressions='%t.supp'" not %run %t 2>&1 | FileCheck %s
@ -24,3 +28,5 @@ int main() {
// CHECK: Suppressions used:
// CHECK: 1 666 *LSanTestLeakingFunc*
// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer: 1337 byte(s) leaked in 1 allocation(s)
// NOSUPP: SUMMARY: {{(Leak|Address)}}Sanitizer: 2003 byte(s) leaked in 2 allocation(s).