blob: cbc9b781f3577653ef7a2949d4199c1545de4933 [file] [log] [blame]
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "./fuzztest/internal/logging.h"
#include <string.h>
#if defined(__linux__)
#include <unistd.h>
#endif
#include <cstdio>
#include <cstdlib>
#include <string>
namespace fuzztest::internal {
namespace {
FILE* stderr_file_ = stderr;
} // namespace
#if defined(__linux__)
namespace {
FILE* stdout_file_ = stdout;
void Silence(int fd) {
FILE* tmp = fopen("/dev/null", "w");
FUZZTEST_INTERNAL_CHECK(tmp, "fopen() error:", strerror(errno));
FUZZTEST_INTERNAL_CHECK(dup2(fileno(tmp), fd) != -1,
"dup2() error:", strerror(errno));
FUZZTEST_INTERNAL_CHECK(fclose(tmp) == 0, "fclose() error:", strerror(errno));
}
// Only accepts 1 or 2 (stdout or stderr).
// If it's stdout, silence it after duping it as a global temporary, which
// will be used when restoring the stdout.
// If it's a stderr, silence it after duping it as the global stderr, which
// will be used internally to log and be used when restoring the stderr.
void DupAndSilence(int fd) {
FUZZTEST_INTERNAL_CHECK(fd == STDOUT_FILENO || fd == STDERR_FILENO,
"DupAndSilence only accepts stderr or stdout.");
int new_fd = dup(fd);
FUZZTEST_INTERNAL_CHECK(new_fd != -1, "dup() error:", strerror(errno));
FILE* new_output_file = fdopen(new_fd, "w");
FUZZTEST_INTERNAL_CHECK(new_output_file, "fdopen error:", strerror(errno));
if (new_output_file) {
if (fd == STDOUT_FILENO) {
stdout_file_ = new_output_file;
} else {
stderr_file_ = new_output_file;
}
Silence(fd);
}
}
} // namespace
void SilenceTargetStdoutAndStderr() {
DupAndSilence(STDOUT_FILENO);
DupAndSilence(STDERR_FILENO);
}
void RestoreTargetStdoutAndStderr() {
FUZZTEST_INTERNAL_CHECK(stderr_file_ != stderr,
"Error, calling RestoreStderr without calling"
"DupandSilenceStderr first.");
FUZZTEST_INTERNAL_CHECK(stdout_file_ != stdout,
"Error, calling RestoreStdout without calling"
"DupandSilenceStdout first.");
FUZZTEST_INTERNAL_CHECK(dup2(fileno(stderr_file_), STDERR_FILENO) != -1,
"dup2 error:", strerror(errno));
FUZZTEST_INTERNAL_CHECK(close(fileno(stderr_file_)) == 0,
"close() error:", strerror(errno));
stderr_file_ = stderr;
FUZZTEST_INTERNAL_CHECK(dup2(fileno(stdout_file_), STDOUT_FILENO) != -1,
"dup2() error:", strerror(errno));
FUZZTEST_INTERNAL_CHECK(close(fileno(stdout_file_)) == 0,
"close() error:", strerror(errno));
stdout_file_ = stdout;
}
bool IsSilenceTargetEnabled() {
return absl::NullSafeStringView(getenv("FUZZTEST_SILENCE_TARGET")) == "1";
}
#else
void SilenceTargetStdoutAndStderr() { return; }
void RestoreTargetStdoutAndStderr() { return; }
bool IsSilenceTargetEnabled() { return false; }
#endif // defined(__linux__)
FILE* GetStderr() { return stderr_file_; }
void Abort(const char* file, int line, const std::string& message) {
fprintf(GetStderr(), "%s:%d: %s\n", file, line, message.c_str());
std::abort();
}
const std::string* volatile test_abort_message = nullptr;
void AbortInTest(const std::string& message) {
// When we are within a test, we set the message here and call abort().
// The signal handler will pickup the message and print it at the right time.
test_abort_message = &message;
std::abort();
}
} // namespace fuzztest::internal