[sanitizer] Support running without fd 0,1,2.

Summary:
Support running with no open file descriptors (as may happen to
"init" process on linux).
* Remove a check that writing to stderr succeeds.
* When opening a file (ex. for log_path option), dup the new fd out of
[0, 2] range to avoid confusing the program.

(2nd attempt, this time without the sanitizer_rtems change)

Reviewers: pcc, vitalybuka

Subscribers: kubamracek, llvm-commits

Differential Revision: https://reviews.llvm.org/D55801

llvm-svn: 349817
This commit is contained in:
Evgeniy Stepanov 2018-12-20 20:36:33 +00:00
parent 0e44ffdb0e
commit 3b7e8b2dbb
7 changed files with 75 additions and 9 deletions

View File

@ -381,6 +381,10 @@ uptr internal_filesize(fd_t fd) {
return (uptr)st.st_size;
}
uptr internal_dup(int oldfd) {
return internal_syscall(SYSCALL(dup), oldfd);
}
uptr internal_dup2(int oldfd, int newfd) {
#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
return internal_syscall(SYSCALL(dup3), oldfd, newfd, 0);

View File

@ -174,6 +174,10 @@ uptr internal_filesize(fd_t fd) {
return (uptr)st.st_size;
}
uptr internal_dup(int oldfd) {
return dup(oldfd);
}
uptr internal_dup2(int oldfd, int newfd) {
return dup2(oldfd, newfd);
}

View File

@ -169,6 +169,11 @@ uptr internal_filesize(fd_t fd) {
return (uptr)st.st_size;
}
uptr internal_dup(int oldfd) {
DEFINE__REAL(int, dup, int a);
return _REAL(dup, oldfd);
}
uptr internal_dup2(int oldfd, int newfd) {
DEFINE__REAL(int, dup2, int a, int b);
return _REAL(dup2, oldfd, newfd);

View File

@ -166,7 +166,7 @@ fd_t OpenFile(const char *filename, FileAccessMode mode, error_t *errno_p) {
fd_t res = internal_open(filename, flags, 0660);
if (internal_iserror(res, errno_p))
return kInvalidFd;
return res;
return ReserveStandardFds(res);
}
void CloseFile(fd_t fd) {
@ -269,13 +269,8 @@ bool IsAbsolutePath(const char *path) {
void ReportFile::Write(const char *buffer, uptr length) {
SpinMutexLock l(mu);
static const char *kWriteError =
"ReportFile::Write() can't output requested buffer!\n";
ReopenIfNecessary();
if (length != internal_write(fd, buffer, length)) {
internal_write(fd, kWriteError, internal_strlen(kWriteError));
Die();
}
internal_write(fd, buffer, length);
}
bool GetCodeRangeForFile(const char *module, uptr *start, uptr *end) {
@ -323,6 +318,21 @@ const char *SignalContext::Describe() const {
return "UNKNOWN SIGNAL";
}
fd_t ReserveStandardFds(fd_t fd) {
CHECK_GE(fd, 0);
if (fd > 2)
return fd;
bool used[3] = {false, false, false};
while (fd <= 2) {
used[fd] = true;
fd = internal_dup(fd);
}
for (int i = 0; i <= 2; ++i)
if (used[i])
internal_close(i);
return fd;
}
} // namespace __sanitizer
#endif // SANITIZER_POSIX

View File

@ -49,6 +49,7 @@ uptr internal_filesize(fd_t fd); // -1 on error.
uptr internal_stat(const char *path, void *buf);
uptr internal_lstat(const char *path, void *buf);
uptr internal_fstat(fd_t fd, void *buf);
uptr internal_dup(int oldfd);
uptr internal_dup2(int oldfd, int newfd);
uptr internal_readlink(const char *path, char *buf, uptr bufsize);
uptr internal_unlink(const char *path);
@ -99,6 +100,9 @@ uptr internal_execve(const char *filename, char *const argv[],
bool IsStateDetached(int state);
// Move the fd out of {0, 1, 2} range.
fd_t ReserveStandardFds(fd_t fd);
} // namespace __sanitizer
#endif // SANITIZER_POSIX_H

View File

@ -88,8 +88,8 @@ uptr internal_open(const char *filename, int flags, u32 mode) {
}
uptr OpenFile(const char *filename, bool write) {
return internal_open(filename,
write ? O_WRONLY | O_CREAT : O_RDONLY, 0660);
return ReserveStandardFds(
internal_open(filename, write ? O_WRONLY | O_CREAT : O_RDONLY, 0660));
}
DECLARE__REAL_AND_INTERNAL(uptr, read, fd_t fd, void *buf, uptr count) {

View File

@ -0,0 +1,39 @@
// RUN: %clangxx_asan -O0 %s -o %t
// RUN: %run %t 2>&1 | FileCheck %s
// RUN: %env_asan_opts=debug=1,verbosity=2 %run %t 2>&1 | FileCheck %s
// Test ASan initialization
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void parent(int argc, char **argv) {
fprintf(stderr, "hello\n");
// CHECK: hello
close(0);
close(1);
dup2(2, 3);
close(2);
char *const newargv[] = {argv[0], (char *)"x", nullptr};
execv(argv[0], newargv);
perror("execve");
exit(1);
}
void child() {
assert(dup(3) == 0);
assert(dup(3) == 1);
assert(dup(3) == 2);
fprintf(stderr, "world\n");
// CHECK: world
}
int main(int argc, char **argv) {
if (argc == 1) {
parent(argc, argv);
} else {
child();
}
}