[sanitizer] Restore stderr when using forkpty() to spawn external symbolizer

In `AtosSymbolizer`, we're using `forkpty()` to create a new pseudo-terminal to communicate with the `atos` tool (we need that to avoid output buffering in interactive mode). This however redirects both stdout and stderr into a single stream, so when we read the output, we can't distinguish between errors and standard replies. Let's save&restore stderr to avoid that.

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

llvm-svn: 265923
This commit is contained in:
Kuba Brecka 2016-04-11 09:27:09 +00:00
parent 716a533a7f
commit 036d060044
2 changed files with 14 additions and 23 deletions

View File

@ -79,23 +79,6 @@ class AtosSymbolizerProcess : public SymbolizerProcess {
char pid_str_[16];
};
static const char *kAtosErrorMessages[] = {
"atos cannot examine process",
"unable to get permission to examine process",
"An admin user name and password is required",
"could not load inserted library",
"architecture mismatch between analysis process",
};
static bool IsAtosErrorMessage(const char *str) {
for (uptr i = 0; i < ARRAY_SIZE(kAtosErrorMessages); i++) {
if (internal_strstr(str, kAtosErrorMessages[i])) {
return true;
}
}
return false;
}
static bool ParseCommandOutput(const char *str, uptr addr, char **out_name,
char **out_module, char **out_file, uptr *line,
uptr *start_address) {
@ -112,12 +95,6 @@ static bool ParseCommandOutput(const char *str, uptr addr, char **out_name,
// 0xdeadbeef (in library.dylib)
// 0xdeadbeef
if (IsAtosErrorMessage(trim)) {
Report("atos returned an error: %s\n", trim);
InternalFree(trim);
return false;
}
const char *rest = trim;
char *symbol_name;
rest = ExtractTokenUpToDelimiter(rest, " (in ", &symbol_name);

View File

@ -74,6 +74,13 @@ bool SymbolizerProcess::StartSymbolizerSubprocess() {
if (use_forkpty_) {
#if SANITIZER_MAC
fd_t fd = kInvalidFd;
// forkpty redirects stdout and stderr into a single stream, so we would
// receive error messages as standard replies. To avoid that, let's dup
// stderr and restore it in the child.
int saved_stderr = dup(STDERR_FILENO);
CHECK_GE(saved_stderr, 0);
// Use forkpty to disable buffering in the new terminal.
pid = internal_forkpty(&fd);
if (pid == -1) {
@ -83,6 +90,11 @@ bool SymbolizerProcess::StartSymbolizerSubprocess() {
return false;
} else if (pid == 0) {
// Child subprocess.
// Restore stderr.
CHECK_GE(dup2(saved_stderr, STDERR_FILENO), 0);
close(saved_stderr);
const char *argv[kArgVMax];
GetArgV(path_, argv);
execv(path_, const_cast<char **>(&argv[0]));
@ -92,6 +104,8 @@ bool SymbolizerProcess::StartSymbolizerSubprocess() {
// Continue execution in parent process.
input_fd_ = output_fd_ = fd;
close(saved_stderr);
// Disable echo in the new terminal, disable CR.
struct termios termflags;
tcgetattr(fd, &termflags);