// // Copyright 2022 The Abseil Authors. // // 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 // // https://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. // // Tests for stripping of literal strings. // --------------------------------------- // // When a `LOG` statement can be trivially proved at compile time to never fire, // e.g. due to `ABSL_MIN_LOG_LEVEL`, `NDEBUG`, or some explicit condition, data // streamed in can be dropped from the compiled program completely if they are // not used elsewhere. This most commonly affects string literals, which users // often want to strip to reduce binary size and/or redact information about // their program's internals (e.g. in a release build). // // These tests log strings and then validate whether they appear in the compiled // binary. This is done by opening the file corresponding to the running test // and running a simple string search on its contents. The strings to be logged // and searched for must be unique, and we must take care not to emit them into // the binary in any other place, e.g. when searching for them. The latter is // accomplished by computing them using base64; the source string appears in the // binary but the target string is computed at runtime. #include <stdio.h> #if defined(__MACH__) #include <mach-o/dyld.h> #elif defined(_WIN32) #include <Windows.h> #include <tchar.h> #endif #include <algorithm> #include <functional> #include <memory> #include <ostream> #include <string> #include "gmock/gmock.h" #include "gtest/gtest.h" #include "absl/base/internal/strerror.h" #include "absl/base/log_severity.h" #include "absl/flags/internal/program_name.h" #include "absl/log/check.h" #include "absl/log/internal/test_helpers.h" #include "absl/log/log.h" #include "absl/status/status.h" #include "absl/strings/escaping.h" #include "absl/strings/str_format.h" #include "absl/strings/string_view.h" // Set a flag that controls whether we actually execute fatal statements, but // prevent the compiler from optimizing it out. static volatile bool kReallyDie = …; namespace { _; Eq; NotNull; kAbslMinLogLevel; std::string Base64UnescapeOrDie(absl::string_view data) { … } // ----------------------------------------------------------------------------- // A Googletest matcher which searches the running binary for a given string // ----------------------------------------------------------------------------- // This matcher is used to validate that literal strings streamed into // `LOG` statements that ought to be compiled out (e.g. `LOG_IF(INFO, false)`) // do not appear in the binary. // // Note that passing the string to be sought directly to `FileHasSubstr()` all // but forces its inclusion in the binary regardless of the logging library's // behavior. For example: // // LOG_IF(INFO, false) << "you're the man now dog"; // // This will always pass: // // EXPECT_THAT(fp, FileHasSubstr("you're the man now dog")); // // So use this instead: // EXPECT_THAT(fp, FileHasSubstr( // Base64UnescapeOrDie("eW91J3JlIHRoZSBtYW4gbm93IGRvZw=="))); class FileHasSubstrMatcher final : public ::testing::MatcherInterface<FILE*> { … }; class StrippingTest : public ::testing::Test { … }; // This tests whether out methodology for testing stripping works on this // platform by looking for one string that definitely ought to be there and one // that definitely ought not to. If this fails, none of the `StrippingTest`s // are going to produce meaningful results. TEST_F(StrippingTest, Control) { … } TEST_F(StrippingTest, Literal) { … } TEST_F(StrippingTest, LiteralInExpression) { … } TEST_F(StrippingTest, Fatal) { … } TEST_F(StrippingTest, DFatal) { … } TEST_F(StrippingTest, Level) { … } TEST_F(StrippingTest, Check) { … } TEST_F(StrippingTest, CheckOp) { … } TEST_F(StrippingTest, CheckStrOp) { … } TEST_F(StrippingTest, CheckOk) { … } } // namespace