xref: /aosp_15_r20/external/abseil-cpp/absl/log/stripping_test.cc (revision 9356374a3709195abf420251b3e825997ff56c0f)
1*9356374aSAndroid Build Coastguard Worker //
2*9356374aSAndroid Build Coastguard Worker // Copyright 2022 The Abseil Authors.
3*9356374aSAndroid Build Coastguard Worker //
4*9356374aSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
5*9356374aSAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
6*9356374aSAndroid Build Coastguard Worker // You may obtain a copy of the License at
7*9356374aSAndroid Build Coastguard Worker //
8*9356374aSAndroid Build Coastguard Worker //      https://www.apache.org/licenses/LICENSE-2.0
9*9356374aSAndroid Build Coastguard Worker //
10*9356374aSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
11*9356374aSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
12*9356374aSAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*9356374aSAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
14*9356374aSAndroid Build Coastguard Worker // limitations under the License.
15*9356374aSAndroid Build Coastguard Worker //
16*9356374aSAndroid Build Coastguard Worker // Tests for stripping of literal strings.
17*9356374aSAndroid Build Coastguard Worker // ---------------------------------------
18*9356374aSAndroid Build Coastguard Worker //
19*9356374aSAndroid Build Coastguard Worker // When a `LOG` statement can be trivially proved at compile time to never fire,
20*9356374aSAndroid Build Coastguard Worker // e.g. due to `ABSL_MIN_LOG_LEVEL`, `NDEBUG`, or some explicit condition, data
21*9356374aSAndroid Build Coastguard Worker // streamed in can be dropped from the compiled program completely if they are
22*9356374aSAndroid Build Coastguard Worker // not used elsewhere.  This most commonly affects string literals, which users
23*9356374aSAndroid Build Coastguard Worker // often want to strip to reduce binary size and/or redact information about
24*9356374aSAndroid Build Coastguard Worker // their program's internals (e.g. in a release build).
25*9356374aSAndroid Build Coastguard Worker //
26*9356374aSAndroid Build Coastguard Worker // These tests log strings and then validate whether they appear in the compiled
27*9356374aSAndroid Build Coastguard Worker // binary.  This is done by opening the file corresponding to the running test
28*9356374aSAndroid Build Coastguard Worker // and running a simple string search on its contents.  The strings to be logged
29*9356374aSAndroid Build Coastguard Worker // and searched for must be unique, and we must take care not to emit them into
30*9356374aSAndroid Build Coastguard Worker // the binary in any other place, e.g. when searching for them.  The latter is
31*9356374aSAndroid Build Coastguard Worker // accomplished by computing them using base64; the source string appears in the
32*9356374aSAndroid Build Coastguard Worker // binary but the target string is computed at runtime.
33*9356374aSAndroid Build Coastguard Worker 
34*9356374aSAndroid Build Coastguard Worker #include <stdio.h>
35*9356374aSAndroid Build Coastguard Worker 
36*9356374aSAndroid Build Coastguard Worker #if defined(__MACH__)
37*9356374aSAndroid Build Coastguard Worker #include <mach-o/dyld.h>
38*9356374aSAndroid Build Coastguard Worker #elif defined(_WIN32)
39*9356374aSAndroid Build Coastguard Worker #include <Windows.h>
40*9356374aSAndroid Build Coastguard Worker #include <tchar.h>
41*9356374aSAndroid Build Coastguard Worker #endif
42*9356374aSAndroid Build Coastguard Worker 
43*9356374aSAndroid Build Coastguard Worker #include <algorithm>
44*9356374aSAndroid Build Coastguard Worker #include <functional>
45*9356374aSAndroid Build Coastguard Worker #include <memory>
46*9356374aSAndroid Build Coastguard Worker #include <ostream>
47*9356374aSAndroid Build Coastguard Worker #include <string>
48*9356374aSAndroid Build Coastguard Worker 
49*9356374aSAndroid Build Coastguard Worker #include "gmock/gmock.h"
50*9356374aSAndroid Build Coastguard Worker #include "gtest/gtest.h"
51*9356374aSAndroid Build Coastguard Worker #include "absl/base/internal/strerror.h"
52*9356374aSAndroid Build Coastguard Worker #include "absl/base/log_severity.h"
53*9356374aSAndroid Build Coastguard Worker #include "absl/flags/internal/program_name.h"
54*9356374aSAndroid Build Coastguard Worker #include "absl/log/check.h"
55*9356374aSAndroid Build Coastguard Worker #include "absl/log/internal/test_helpers.h"
56*9356374aSAndroid Build Coastguard Worker #include "absl/log/log.h"
57*9356374aSAndroid Build Coastguard Worker #include "absl/status/status.h"
58*9356374aSAndroid Build Coastguard Worker #include "absl/strings/escaping.h"
59*9356374aSAndroid Build Coastguard Worker #include "absl/strings/str_format.h"
60*9356374aSAndroid Build Coastguard Worker #include "absl/strings/string_view.h"
61*9356374aSAndroid Build Coastguard Worker 
62*9356374aSAndroid Build Coastguard Worker // Set a flag that controls whether we actually execute fatal statements, but
63*9356374aSAndroid Build Coastguard Worker // prevent the compiler from optimizing it out.
64*9356374aSAndroid Build Coastguard Worker static volatile bool kReallyDie = false;
65*9356374aSAndroid Build Coastguard Worker 
66*9356374aSAndroid Build Coastguard Worker namespace {
67*9356374aSAndroid Build Coastguard Worker using ::testing::_;
68*9356374aSAndroid Build Coastguard Worker using ::testing::Eq;
69*9356374aSAndroid Build Coastguard Worker using ::testing::NotNull;
70*9356374aSAndroid Build Coastguard Worker 
71*9356374aSAndroid Build Coastguard Worker using absl::log_internal::kAbslMinLogLevel;
72*9356374aSAndroid Build Coastguard Worker 
Base64UnescapeOrDie(absl::string_view data)73*9356374aSAndroid Build Coastguard Worker std::string Base64UnescapeOrDie(absl::string_view data) {
74*9356374aSAndroid Build Coastguard Worker   std::string decoded;
75*9356374aSAndroid Build Coastguard Worker   CHECK(absl::Base64Unescape(data, &decoded));
76*9356374aSAndroid Build Coastguard Worker   return decoded;
77*9356374aSAndroid Build Coastguard Worker }
78*9356374aSAndroid Build Coastguard Worker 
79*9356374aSAndroid Build Coastguard Worker // -----------------------------------------------------------------------------
80*9356374aSAndroid Build Coastguard Worker // A Googletest matcher which searches the running binary for a given string
81*9356374aSAndroid Build Coastguard Worker // -----------------------------------------------------------------------------
82*9356374aSAndroid Build Coastguard Worker 
83*9356374aSAndroid Build Coastguard Worker // This matcher is used to validate that literal strings streamed into
84*9356374aSAndroid Build Coastguard Worker // `LOG` statements that ought to be compiled out (e.g. `LOG_IF(INFO, false)`)
85*9356374aSAndroid Build Coastguard Worker // do not appear in the binary.
86*9356374aSAndroid Build Coastguard Worker //
87*9356374aSAndroid Build Coastguard Worker // Note that passing the string to be sought directly to `FileHasSubstr()` all
88*9356374aSAndroid Build Coastguard Worker // but forces its inclusion in the binary regardless of the logging library's
89*9356374aSAndroid Build Coastguard Worker // behavior. For example:
90*9356374aSAndroid Build Coastguard Worker //
91*9356374aSAndroid Build Coastguard Worker //   LOG_IF(INFO, false) << "you're the man now dog";
92*9356374aSAndroid Build Coastguard Worker //   // This will always pass:
93*9356374aSAndroid Build Coastguard Worker //   // EXPECT_THAT(fp, FileHasSubstr("you're the man now dog"));
94*9356374aSAndroid Build Coastguard Worker //   // So use this instead:
95*9356374aSAndroid Build Coastguard Worker //   EXPECT_THAT(fp, FileHasSubstr(
96*9356374aSAndroid Build Coastguard Worker //       Base64UnescapeOrDie("eW91J3JlIHRoZSBtYW4gbm93IGRvZw==")));
97*9356374aSAndroid Build Coastguard Worker 
98*9356374aSAndroid Build Coastguard Worker class FileHasSubstrMatcher final : public ::testing::MatcherInterface<FILE*> {
99*9356374aSAndroid Build Coastguard Worker  public:
FileHasSubstrMatcher(absl::string_view needle)100*9356374aSAndroid Build Coastguard Worker   explicit FileHasSubstrMatcher(absl::string_view needle) : needle_(needle) {}
101*9356374aSAndroid Build Coastguard Worker 
MatchAndExplain(FILE * fp,::testing::MatchResultListener * listener) const102*9356374aSAndroid Build Coastguard Worker   bool MatchAndExplain(
103*9356374aSAndroid Build Coastguard Worker       FILE* fp, ::testing::MatchResultListener* listener) const override {
104*9356374aSAndroid Build Coastguard Worker     std::string buf(
105*9356374aSAndroid Build Coastguard Worker         std::max<std::string::size_type>(needle_.size() * 2, 163840000), '\0');
106*9356374aSAndroid Build Coastguard Worker     size_t buf_start_offset = 0;  // The file offset of the byte at `buf[0]`.
107*9356374aSAndroid Build Coastguard Worker     size_t buf_data_size = 0;     // The number of bytes of `buf` which contain
108*9356374aSAndroid Build Coastguard Worker                                   // data.
109*9356374aSAndroid Build Coastguard Worker 
110*9356374aSAndroid Build Coastguard Worker     ::fseek(fp, 0, SEEK_SET);
111*9356374aSAndroid Build Coastguard Worker     while (true) {
112*9356374aSAndroid Build Coastguard Worker       // Fill the buffer to capacity or EOF:
113*9356374aSAndroid Build Coastguard Worker       while (buf_data_size < buf.size()) {
114*9356374aSAndroid Build Coastguard Worker         const size_t ret = fread(&buf[buf_data_size], sizeof(char),
115*9356374aSAndroid Build Coastguard Worker                                  buf.size() - buf_data_size, fp);
116*9356374aSAndroid Build Coastguard Worker         if (ret == 0) break;
117*9356374aSAndroid Build Coastguard Worker         buf_data_size += ret;
118*9356374aSAndroid Build Coastguard Worker       }
119*9356374aSAndroid Build Coastguard Worker       if (ferror(fp)) {
120*9356374aSAndroid Build Coastguard Worker         *listener << "error reading file";
121*9356374aSAndroid Build Coastguard Worker         return false;
122*9356374aSAndroid Build Coastguard Worker       }
123*9356374aSAndroid Build Coastguard Worker       const absl::string_view haystack(&buf[0], buf_data_size);
124*9356374aSAndroid Build Coastguard Worker       const auto off = haystack.find(needle_);
125*9356374aSAndroid Build Coastguard Worker       if (off != haystack.npos) {
126*9356374aSAndroid Build Coastguard Worker         *listener << "string found at offset " << buf_start_offset + off;
127*9356374aSAndroid Build Coastguard Worker         return true;
128*9356374aSAndroid Build Coastguard Worker       }
129*9356374aSAndroid Build Coastguard Worker       if (feof(fp)) {
130*9356374aSAndroid Build Coastguard Worker         *listener << "string not found";
131*9356374aSAndroid Build Coastguard Worker         return false;
132*9356374aSAndroid Build Coastguard Worker       }
133*9356374aSAndroid Build Coastguard Worker       // Copy the end of `buf` to the beginning so we catch matches that span
134*9356374aSAndroid Build Coastguard Worker       // buffer boundaries.  `buf` and `buf_data_size` are always large enough
135*9356374aSAndroid Build Coastguard Worker       // that these ranges don't overlap.
136*9356374aSAndroid Build Coastguard Worker       memcpy(&buf[0], &buf[buf_data_size - needle_.size()], needle_.size());
137*9356374aSAndroid Build Coastguard Worker       buf_start_offset += buf_data_size - needle_.size();
138*9356374aSAndroid Build Coastguard Worker       buf_data_size = needle_.size();
139*9356374aSAndroid Build Coastguard Worker     }
140*9356374aSAndroid Build Coastguard Worker   }
DescribeTo(std::ostream * os) const141*9356374aSAndroid Build Coastguard Worker   void DescribeTo(std::ostream* os) const override {
142*9356374aSAndroid Build Coastguard Worker     *os << "contains the string \"" << needle_ << "\" (base64(\""
143*9356374aSAndroid Build Coastguard Worker         << Base64UnescapeOrDie(needle_) << "\"))";
144*9356374aSAndroid Build Coastguard Worker   }
145*9356374aSAndroid Build Coastguard Worker 
DescribeNegationTo(std::ostream * os) const146*9356374aSAndroid Build Coastguard Worker   void DescribeNegationTo(std::ostream* os) const override {
147*9356374aSAndroid Build Coastguard Worker     *os << "does not ";
148*9356374aSAndroid Build Coastguard Worker     DescribeTo(os);
149*9356374aSAndroid Build Coastguard Worker   }
150*9356374aSAndroid Build Coastguard Worker 
151*9356374aSAndroid Build Coastguard Worker  private:
152*9356374aSAndroid Build Coastguard Worker   std::string needle_;
153*9356374aSAndroid Build Coastguard Worker };
154*9356374aSAndroid Build Coastguard Worker 
155*9356374aSAndroid Build Coastguard Worker class StrippingTest : public ::testing::Test {
156*9356374aSAndroid Build Coastguard Worker  protected:
SetUp()157*9356374aSAndroid Build Coastguard Worker   void SetUp() override {
158*9356374aSAndroid Build Coastguard Worker #ifndef NDEBUG
159*9356374aSAndroid Build Coastguard Worker     // Non-optimized builds don't necessarily eliminate dead code at all, so we
160*9356374aSAndroid Build Coastguard Worker     // don't attempt to validate stripping against such builds.
161*9356374aSAndroid Build Coastguard Worker     GTEST_SKIP() << "StrippingTests skipped since this build is not optimized";
162*9356374aSAndroid Build Coastguard Worker #elif defined(__EMSCRIPTEN__)
163*9356374aSAndroid Build Coastguard Worker     // These tests require a way to examine the running binary and look for
164*9356374aSAndroid Build Coastguard Worker     // strings; there's no portable way to do that.
165*9356374aSAndroid Build Coastguard Worker     GTEST_SKIP()
166*9356374aSAndroid Build Coastguard Worker         << "StrippingTests skipped since this platform is not optimized";
167*9356374aSAndroid Build Coastguard Worker #endif
168*9356374aSAndroid Build Coastguard Worker   }
169*9356374aSAndroid Build Coastguard Worker 
170*9356374aSAndroid Build Coastguard Worker   // Opens this program's executable file.  Returns `nullptr` and writes to
171*9356374aSAndroid Build Coastguard Worker   // `stderr` on failure.
OpenTestExecutable()172*9356374aSAndroid Build Coastguard Worker   std::unique_ptr<FILE, std::function<void(FILE*)>> OpenTestExecutable() {
173*9356374aSAndroid Build Coastguard Worker #if defined(__linux__)
174*9356374aSAndroid Build Coastguard Worker     std::unique_ptr<FILE, std::function<void(FILE*)>> fp(
175*9356374aSAndroid Build Coastguard Worker         fopen("/proc/self/exe", "rb"), [](FILE* fp) { fclose(fp); });
176*9356374aSAndroid Build Coastguard Worker     if (!fp) {
177*9356374aSAndroid Build Coastguard Worker       const std::string err = absl::base_internal::StrError(errno);
178*9356374aSAndroid Build Coastguard Worker       absl::FPrintF(stderr, "Failed to open /proc/self/exe: %s\n", err);
179*9356374aSAndroid Build Coastguard Worker     }
180*9356374aSAndroid Build Coastguard Worker     return fp;
181*9356374aSAndroid Build Coastguard Worker #elif defined(__Fuchsia__)
182*9356374aSAndroid Build Coastguard Worker     // TODO(b/242579714): We need to restore the test coverage on this platform.
183*9356374aSAndroid Build Coastguard Worker     std::unique_ptr<FILE, std::function<void(FILE*)>> fp(
184*9356374aSAndroid Build Coastguard Worker         fopen(absl::StrCat("/pkg/bin/",
185*9356374aSAndroid Build Coastguard Worker                            absl::flags_internal::ShortProgramInvocationName())
186*9356374aSAndroid Build Coastguard Worker                   .c_str(),
187*9356374aSAndroid Build Coastguard Worker               "rb"),
188*9356374aSAndroid Build Coastguard Worker         [](FILE* fp) { fclose(fp); });
189*9356374aSAndroid Build Coastguard Worker     if (!fp) {
190*9356374aSAndroid Build Coastguard Worker       const std::string err = absl::base_internal::StrError(errno);
191*9356374aSAndroid Build Coastguard Worker       absl::FPrintF(stderr, "Failed to open /pkg/bin/<binary name>: %s\n", err);
192*9356374aSAndroid Build Coastguard Worker     }
193*9356374aSAndroid Build Coastguard Worker     return fp;
194*9356374aSAndroid Build Coastguard Worker #elif defined(__MACH__)
195*9356374aSAndroid Build Coastguard Worker     uint32_t size = 0;
196*9356374aSAndroid Build Coastguard Worker     int ret = _NSGetExecutablePath(nullptr, &size);
197*9356374aSAndroid Build Coastguard Worker     if (ret != -1) {
198*9356374aSAndroid Build Coastguard Worker       absl::FPrintF(stderr,
199*9356374aSAndroid Build Coastguard Worker                     "Failed to get executable path: "
200*9356374aSAndroid Build Coastguard Worker                     "_NSGetExecutablePath(nullptr) returned %d\n",
201*9356374aSAndroid Build Coastguard Worker                     ret);
202*9356374aSAndroid Build Coastguard Worker       return nullptr;
203*9356374aSAndroid Build Coastguard Worker     }
204*9356374aSAndroid Build Coastguard Worker     std::string path(size, '\0');
205*9356374aSAndroid Build Coastguard Worker     ret = _NSGetExecutablePath(&path[0], &size);
206*9356374aSAndroid Build Coastguard Worker     if (ret != 0) {
207*9356374aSAndroid Build Coastguard Worker       absl::FPrintF(
208*9356374aSAndroid Build Coastguard Worker           stderr,
209*9356374aSAndroid Build Coastguard Worker           "Failed to get executable path: _NSGetExecutablePath(buffer) "
210*9356374aSAndroid Build Coastguard Worker           "returned %d\n",
211*9356374aSAndroid Build Coastguard Worker           ret);
212*9356374aSAndroid Build Coastguard Worker       return nullptr;
213*9356374aSAndroid Build Coastguard Worker     }
214*9356374aSAndroid Build Coastguard Worker     std::unique_ptr<FILE, std::function<void(FILE*)>> fp(
215*9356374aSAndroid Build Coastguard Worker         fopen(path.c_str(), "rb"), [](FILE* fp) { fclose(fp); });
216*9356374aSAndroid Build Coastguard Worker     if (!fp) {
217*9356374aSAndroid Build Coastguard Worker       const std::string err = absl::base_internal::StrError(errno);
218*9356374aSAndroid Build Coastguard Worker       absl::FPrintF(stderr, "Failed to open executable at %s: %s\n", path, err);
219*9356374aSAndroid Build Coastguard Worker     }
220*9356374aSAndroid Build Coastguard Worker     return fp;
221*9356374aSAndroid Build Coastguard Worker #elif defined(_WIN32)
222*9356374aSAndroid Build Coastguard Worker     std::basic_string<TCHAR> path(4096, _T('\0'));
223*9356374aSAndroid Build Coastguard Worker     while (true) {
224*9356374aSAndroid Build Coastguard Worker       const uint32_t ret = ::GetModuleFileName(nullptr, &path[0],
225*9356374aSAndroid Build Coastguard Worker                                                static_cast<DWORD>(path.size()));
226*9356374aSAndroid Build Coastguard Worker       if (ret == 0) {
227*9356374aSAndroid Build Coastguard Worker         absl::FPrintF(
228*9356374aSAndroid Build Coastguard Worker             stderr,
229*9356374aSAndroid Build Coastguard Worker             "Failed to get executable path: GetModuleFileName(buffer) "
230*9356374aSAndroid Build Coastguard Worker             "returned 0\n");
231*9356374aSAndroid Build Coastguard Worker         return nullptr;
232*9356374aSAndroid Build Coastguard Worker       }
233*9356374aSAndroid Build Coastguard Worker       if (ret < path.size()) break;
234*9356374aSAndroid Build Coastguard Worker       path.resize(path.size() * 2, _T('\0'));
235*9356374aSAndroid Build Coastguard Worker     }
236*9356374aSAndroid Build Coastguard Worker     std::unique_ptr<FILE, std::function<void(FILE*)>> fp(
237*9356374aSAndroid Build Coastguard Worker         _tfopen(path.c_str(), _T("rb")), [](FILE* fp) { fclose(fp); });
238*9356374aSAndroid Build Coastguard Worker     if (!fp) absl::FPrintF(stderr, "Failed to open executable\n");
239*9356374aSAndroid Build Coastguard Worker     return fp;
240*9356374aSAndroid Build Coastguard Worker #else
241*9356374aSAndroid Build Coastguard Worker     absl::FPrintF(stderr,
242*9356374aSAndroid Build Coastguard Worker                   "OpenTestExecutable() unimplemented on this platform\n");
243*9356374aSAndroid Build Coastguard Worker     return nullptr;
244*9356374aSAndroid Build Coastguard Worker #endif
245*9356374aSAndroid Build Coastguard Worker   }
246*9356374aSAndroid Build Coastguard Worker 
FileHasSubstr(absl::string_view needle)247*9356374aSAndroid Build Coastguard Worker   ::testing::Matcher<FILE*> FileHasSubstr(absl::string_view needle) {
248*9356374aSAndroid Build Coastguard Worker     return MakeMatcher(new FileHasSubstrMatcher(needle));
249*9356374aSAndroid Build Coastguard Worker   }
250*9356374aSAndroid Build Coastguard Worker };
251*9356374aSAndroid Build Coastguard Worker 
252*9356374aSAndroid Build Coastguard Worker // This tests whether out methodology for testing stripping works on this
253*9356374aSAndroid Build Coastguard Worker // platform by looking for one string that definitely ought to be there and one
254*9356374aSAndroid Build Coastguard Worker // that definitely ought not to.  If this fails, none of the `StrippingTest`s
255*9356374aSAndroid Build Coastguard Worker // are going to produce meaningful results.
TEST_F(StrippingTest,Control)256*9356374aSAndroid Build Coastguard Worker TEST_F(StrippingTest, Control) {
257*9356374aSAndroid Build Coastguard Worker   constexpr char kEncodedPositiveControl[] =
258*9356374aSAndroid Build Coastguard Worker       "U3RyaXBwaW5nVGVzdC5Qb3NpdGl2ZUNvbnRyb2w=";
259*9356374aSAndroid Build Coastguard Worker   const std::string encoded_negative_control =
260*9356374aSAndroid Build Coastguard Worker       absl::Base64Escape("StrippingTest.NegativeControl");
261*9356374aSAndroid Build Coastguard Worker 
262*9356374aSAndroid Build Coastguard Worker   // Verify this mainly so we can encode other strings and know definitely they
263*9356374aSAndroid Build Coastguard Worker   // won't encode to `kEncodedPositiveControl`.
264*9356374aSAndroid Build Coastguard Worker   EXPECT_THAT(Base64UnescapeOrDie("U3RyaXBwaW5nVGVzdC5Qb3NpdGl2ZUNvbnRyb2w="),
265*9356374aSAndroid Build Coastguard Worker               Eq("StrippingTest.PositiveControl"));
266*9356374aSAndroid Build Coastguard Worker 
267*9356374aSAndroid Build Coastguard Worker   auto exe = OpenTestExecutable();
268*9356374aSAndroid Build Coastguard Worker   ASSERT_THAT(exe, NotNull());
269*9356374aSAndroid Build Coastguard Worker   EXPECT_THAT(exe.get(), FileHasSubstr(kEncodedPositiveControl));
270*9356374aSAndroid Build Coastguard Worker   EXPECT_THAT(exe.get(), Not(FileHasSubstr(encoded_negative_control)));
271*9356374aSAndroid Build Coastguard Worker }
272*9356374aSAndroid Build Coastguard Worker 
TEST_F(StrippingTest,Literal)273*9356374aSAndroid Build Coastguard Worker TEST_F(StrippingTest, Literal) {
274*9356374aSAndroid Build Coastguard Worker   // We need to load a copy of the needle string into memory (so we can search
275*9356374aSAndroid Build Coastguard Worker   // for it) without leaving it lying around in plaintext in the executable file
276*9356374aSAndroid Build Coastguard Worker   // as would happen if we used a literal.  We might (or might not) leave it
277*9356374aSAndroid Build Coastguard Worker   // lying around later; that's what the tests are for!
278*9356374aSAndroid Build Coastguard Worker   const std::string needle = absl::Base64Escape("StrippingTest.Literal");
279*9356374aSAndroid Build Coastguard Worker   LOG(INFO) << "U3RyaXBwaW5nVGVzdC5MaXRlcmFs";
280*9356374aSAndroid Build Coastguard Worker   auto exe = OpenTestExecutable();
281*9356374aSAndroid Build Coastguard Worker   ASSERT_THAT(exe, NotNull());
282*9356374aSAndroid Build Coastguard Worker   if (absl::LogSeverity::kInfo >= kAbslMinLogLevel) {
283*9356374aSAndroid Build Coastguard Worker     EXPECT_THAT(exe.get(), FileHasSubstr(needle));
284*9356374aSAndroid Build Coastguard Worker   } else {
285*9356374aSAndroid Build Coastguard Worker     EXPECT_THAT(exe.get(), Not(FileHasSubstr(needle)));
286*9356374aSAndroid Build Coastguard Worker   }
287*9356374aSAndroid Build Coastguard Worker }
288*9356374aSAndroid Build Coastguard Worker 
TEST_F(StrippingTest,LiteralInExpression)289*9356374aSAndroid Build Coastguard Worker TEST_F(StrippingTest, LiteralInExpression) {
290*9356374aSAndroid Build Coastguard Worker   // We need to load a copy of the needle string into memory (so we can search
291*9356374aSAndroid Build Coastguard Worker   // for it) without leaving it lying around in plaintext in the executable file
292*9356374aSAndroid Build Coastguard Worker   // as would happen if we used a literal.  We might (or might not) leave it
293*9356374aSAndroid Build Coastguard Worker   // lying around later; that's what the tests are for!
294*9356374aSAndroid Build Coastguard Worker   const std::string needle =
295*9356374aSAndroid Build Coastguard Worker       absl::Base64Escape("StrippingTest.LiteralInExpression");
296*9356374aSAndroid Build Coastguard Worker   LOG(INFO) << absl::StrCat("secret: ",
297*9356374aSAndroid Build Coastguard Worker                             "U3RyaXBwaW5nVGVzdC5MaXRlcmFsSW5FeHByZXNzaW9u");
298*9356374aSAndroid Build Coastguard Worker   std::unique_ptr<FILE, std::function<void(FILE*)>> exe = OpenTestExecutable();
299*9356374aSAndroid Build Coastguard Worker   ASSERT_THAT(exe, NotNull());
300*9356374aSAndroid Build Coastguard Worker   if (absl::LogSeverity::kInfo >= kAbslMinLogLevel) {
301*9356374aSAndroid Build Coastguard Worker     EXPECT_THAT(exe.get(), FileHasSubstr(needle));
302*9356374aSAndroid Build Coastguard Worker   } else {
303*9356374aSAndroid Build Coastguard Worker     EXPECT_THAT(exe.get(), Not(FileHasSubstr(needle)));
304*9356374aSAndroid Build Coastguard Worker   }
305*9356374aSAndroid Build Coastguard Worker }
306*9356374aSAndroid Build Coastguard Worker 
TEST_F(StrippingTest,Fatal)307*9356374aSAndroid Build Coastguard Worker TEST_F(StrippingTest, Fatal) {
308*9356374aSAndroid Build Coastguard Worker   // We need to load a copy of the needle string into memory (so we can search
309*9356374aSAndroid Build Coastguard Worker   // for it) without leaving it lying around in plaintext in the executable file
310*9356374aSAndroid Build Coastguard Worker   // as would happen if we used a literal.  We might (or might not) leave it
311*9356374aSAndroid Build Coastguard Worker   // lying around later; that's what the tests are for!
312*9356374aSAndroid Build Coastguard Worker   const std::string needle = absl::Base64Escape("StrippingTest.Fatal");
313*9356374aSAndroid Build Coastguard Worker   // We don't care if the LOG statement is actually executed, we're just
314*9356374aSAndroid Build Coastguard Worker   // checking that it's stripped.
315*9356374aSAndroid Build Coastguard Worker   if (kReallyDie) LOG(FATAL) << "U3RyaXBwaW5nVGVzdC5GYXRhbA==";
316*9356374aSAndroid Build Coastguard Worker 
317*9356374aSAndroid Build Coastguard Worker   std::unique_ptr<FILE, std::function<void(FILE*)>> exe = OpenTestExecutable();
318*9356374aSAndroid Build Coastguard Worker   ASSERT_THAT(exe, NotNull());
319*9356374aSAndroid Build Coastguard Worker   if (absl::LogSeverity::kFatal >= kAbslMinLogLevel) {
320*9356374aSAndroid Build Coastguard Worker     EXPECT_THAT(exe.get(), FileHasSubstr(needle));
321*9356374aSAndroid Build Coastguard Worker   } else {
322*9356374aSAndroid Build Coastguard Worker     EXPECT_THAT(exe.get(), Not(FileHasSubstr(needle)));
323*9356374aSAndroid Build Coastguard Worker   }
324*9356374aSAndroid Build Coastguard Worker }
325*9356374aSAndroid Build Coastguard Worker 
TEST_F(StrippingTest,DFatal)326*9356374aSAndroid Build Coastguard Worker TEST_F(StrippingTest, DFatal) {
327*9356374aSAndroid Build Coastguard Worker   // We need to load a copy of the needle string into memory (so we can search
328*9356374aSAndroid Build Coastguard Worker   // for it) without leaving it lying around in plaintext in the executable file
329*9356374aSAndroid Build Coastguard Worker   // as would happen if we used a literal.  We might (or might not) leave it
330*9356374aSAndroid Build Coastguard Worker   // lying around later; that's what the tests are for!
331*9356374aSAndroid Build Coastguard Worker   const std::string needle = absl::Base64Escape("StrippingTest.DFatal");
332*9356374aSAndroid Build Coastguard Worker   // We don't care if the LOG statement is actually executed, we're just
333*9356374aSAndroid Build Coastguard Worker   // checking that it's stripped.
334*9356374aSAndroid Build Coastguard Worker   if (kReallyDie) LOG(DFATAL) << "U3RyaXBwaW5nVGVzdC5ERmF0YWw=";
335*9356374aSAndroid Build Coastguard Worker 
336*9356374aSAndroid Build Coastguard Worker   std::unique_ptr<FILE, std::function<void(FILE*)>> exe = OpenTestExecutable();
337*9356374aSAndroid Build Coastguard Worker   ASSERT_THAT(exe, NotNull());
338*9356374aSAndroid Build Coastguard Worker   // `DFATAL` can be `ERROR` or `FATAL`, and a compile-time optimizer doesn't
339*9356374aSAndroid Build Coastguard Worker   // know which, because `absl::kLogDebugFatal` is declared `extern` and defined
340*9356374aSAndroid Build Coastguard Worker   // in another TU.  Link-time optimization might do better.  We have six cases:
341*9356374aSAndroid Build Coastguard Worker   // |         `AMLL` is-> | `<=ERROR` | `FATAL` | `>FATAL` |
342*9356374aSAndroid Build Coastguard Worker   // | ------------------- | --------- | ------- | -------- |
343*9356374aSAndroid Build Coastguard Worker   // | `DFATAL` is `ERROR` |   present |       ? | stripped |
344*9356374aSAndroid Build Coastguard Worker   // | `DFATAL` is `FATAL` |   present | present | stripped |
345*9356374aSAndroid Build Coastguard Worker 
346*9356374aSAndroid Build Coastguard Worker   // These constexpr variables are used to suppress unreachable code warnings
347*9356374aSAndroid Build Coastguard Worker   // in the if-else statements below.
348*9356374aSAndroid Build Coastguard Worker 
349*9356374aSAndroid Build Coastguard Worker   // "present" in the table above: `DFATAL` exceeds `ABSL_MIN_LOG_LEVEL`, so
350*9356374aSAndroid Build Coastguard Worker   // `DFATAL` statements should not be stripped (and they should be logged
351*9356374aSAndroid Build Coastguard Worker   // when executed, but that's a different testsuite).
352*9356374aSAndroid Build Coastguard Worker   constexpr bool kExpectPresent = absl::kLogDebugFatal >= kAbslMinLogLevel;
353*9356374aSAndroid Build Coastguard Worker 
354*9356374aSAndroid Build Coastguard Worker   // "stripped" in the table above: even though the compiler may not know
355*9356374aSAndroid Build Coastguard Worker   // which value `DFATAL` has, it should be able to strip it since both
356*9356374aSAndroid Build Coastguard Worker   // possible values ought to be stripped.
357*9356374aSAndroid Build Coastguard Worker   constexpr bool kExpectStripped = kAbslMinLogLevel > absl::LogSeverity::kFatal;
358*9356374aSAndroid Build Coastguard Worker 
359*9356374aSAndroid Build Coastguard Worker   if (kExpectPresent) {
360*9356374aSAndroid Build Coastguard Worker     EXPECT_THAT(exe.get(), FileHasSubstr(needle));
361*9356374aSAndroid Build Coastguard Worker   } else if (kExpectStripped) {
362*9356374aSAndroid Build Coastguard Worker     EXPECT_THAT(exe.get(), Not(FileHasSubstr(needle)));
363*9356374aSAndroid Build Coastguard Worker   } else {
364*9356374aSAndroid Build Coastguard Worker     // "?" in the table above; may or may not be stripped depending on whether
365*9356374aSAndroid Build Coastguard Worker     // any link-time optimization is done.  Either outcome is ok.
366*9356374aSAndroid Build Coastguard Worker   }
367*9356374aSAndroid Build Coastguard Worker }
368*9356374aSAndroid Build Coastguard Worker 
TEST_F(StrippingTest,Level)369*9356374aSAndroid Build Coastguard Worker TEST_F(StrippingTest, Level) {
370*9356374aSAndroid Build Coastguard Worker   const std::string needle = absl::Base64Escape("StrippingTest.Level");
371*9356374aSAndroid Build Coastguard Worker   volatile auto severity = absl::LogSeverity::kWarning;
372*9356374aSAndroid Build Coastguard Worker   // Ensure that `severity` is not a compile-time constant to prove that
373*9356374aSAndroid Build Coastguard Worker   // stripping works regardless:
374*9356374aSAndroid Build Coastguard Worker   LOG(LEVEL(severity)) << "U3RyaXBwaW5nVGVzdC5MZXZlbA==";
375*9356374aSAndroid Build Coastguard Worker   std::unique_ptr<FILE, std::function<void(FILE*)>> exe = OpenTestExecutable();
376*9356374aSAndroid Build Coastguard Worker   ASSERT_THAT(exe, NotNull());
377*9356374aSAndroid Build Coastguard Worker   if (absl::LogSeverity::kFatal >= kAbslMinLogLevel) {
378*9356374aSAndroid Build Coastguard Worker     // This can't be stripped at compile-time because it might evaluate to a
379*9356374aSAndroid Build Coastguard Worker     // level that shouldn't be stripped.
380*9356374aSAndroid Build Coastguard Worker     EXPECT_THAT(exe.get(), FileHasSubstr(needle));
381*9356374aSAndroid Build Coastguard Worker   } else {
382*9356374aSAndroid Build Coastguard Worker #if (defined(_MSC_VER) && !defined(__clang__)) || defined(__APPLE__)
383*9356374aSAndroid Build Coastguard Worker     // Dead code elimination misses this case.
384*9356374aSAndroid Build Coastguard Worker #else
385*9356374aSAndroid Build Coastguard Worker     // All levels should be stripped, so it doesn't matter what the severity
386*9356374aSAndroid Build Coastguard Worker     // winds up being.
387*9356374aSAndroid Build Coastguard Worker     EXPECT_THAT(exe.get(), Not(FileHasSubstr(needle)));
388*9356374aSAndroid Build Coastguard Worker #endif
389*9356374aSAndroid Build Coastguard Worker   }
390*9356374aSAndroid Build Coastguard Worker }
391*9356374aSAndroid Build Coastguard Worker 
TEST_F(StrippingTest,Check)392*9356374aSAndroid Build Coastguard Worker TEST_F(StrippingTest, Check) {
393*9356374aSAndroid Build Coastguard Worker   // Here we also need a variable name with enough entropy that it's unlikely to
394*9356374aSAndroid Build Coastguard Worker   // appear in the binary by chance.  `volatile` keeps the tautological
395*9356374aSAndroid Build Coastguard Worker   // comparison (and the rest of the `CHECK`) from being optimized away.
396*9356374aSAndroid Build Coastguard Worker   const std::string var_needle = absl::Base64Escape("StrippingTestCheckVar");
397*9356374aSAndroid Build Coastguard Worker   const std::string msg_needle = absl::Base64Escape("StrippingTest.Check");
398*9356374aSAndroid Build Coastguard Worker   volatile int U3RyaXBwaW5nVGVzdENoZWNrVmFy = 0xCAFE;
399*9356374aSAndroid Build Coastguard Worker   // We don't care if the CHECK is actually executed, just that stripping works.
400*9356374aSAndroid Build Coastguard Worker   // Hiding it behind `kReallyDie` works around some overly aggressive
401*9356374aSAndroid Build Coastguard Worker   // optimizations in older versions of MSVC.
402*9356374aSAndroid Build Coastguard Worker   if (kReallyDie) {
403*9356374aSAndroid Build Coastguard Worker     CHECK(U3RyaXBwaW5nVGVzdENoZWNrVmFy != U3RyaXBwaW5nVGVzdENoZWNrVmFy)
404*9356374aSAndroid Build Coastguard Worker         << "U3RyaXBwaW5nVGVzdC5DaGVjaw==";
405*9356374aSAndroid Build Coastguard Worker   }
406*9356374aSAndroid Build Coastguard Worker 
407*9356374aSAndroid Build Coastguard Worker   std::unique_ptr<FILE, std::function<void(FILE*)>> exe = OpenTestExecutable();
408*9356374aSAndroid Build Coastguard Worker   ASSERT_THAT(exe, NotNull());
409*9356374aSAndroid Build Coastguard Worker   if (absl::LogSeverity::kFatal >= kAbslMinLogLevel) {
410*9356374aSAndroid Build Coastguard Worker     EXPECT_THAT(exe.get(), FileHasSubstr(var_needle));
411*9356374aSAndroid Build Coastguard Worker     EXPECT_THAT(exe.get(), FileHasSubstr(msg_needle));
412*9356374aSAndroid Build Coastguard Worker   } else {
413*9356374aSAndroid Build Coastguard Worker     EXPECT_THAT(exe.get(), Not(FileHasSubstr(var_needle)));
414*9356374aSAndroid Build Coastguard Worker     EXPECT_THAT(exe.get(), Not(FileHasSubstr(msg_needle)));
415*9356374aSAndroid Build Coastguard Worker   }
416*9356374aSAndroid Build Coastguard Worker }
417*9356374aSAndroid Build Coastguard Worker 
TEST_F(StrippingTest,CheckOp)418*9356374aSAndroid Build Coastguard Worker TEST_F(StrippingTest, CheckOp) {
419*9356374aSAndroid Build Coastguard Worker   // See `StrippingTest.Check` for some hairy implementation notes.
420*9356374aSAndroid Build Coastguard Worker   const std::string var_needle1 =
421*9356374aSAndroid Build Coastguard Worker       absl::Base64Escape("StrippingTestCheckOpVar1");
422*9356374aSAndroid Build Coastguard Worker   const std::string var_needle2 =
423*9356374aSAndroid Build Coastguard Worker       absl::Base64Escape("StrippingTestCheckOpVar2");
424*9356374aSAndroid Build Coastguard Worker   const std::string msg_needle = absl::Base64Escape("StrippingTest.CheckOp");
425*9356374aSAndroid Build Coastguard Worker   volatile int U3RyaXBwaW5nVGVzdENoZWNrT3BWYXIx = 0xFEED;
426*9356374aSAndroid Build Coastguard Worker   volatile int U3RyaXBwaW5nVGVzdENoZWNrT3BWYXIy = 0xCAFE;
427*9356374aSAndroid Build Coastguard Worker   if (kReallyDie) {
428*9356374aSAndroid Build Coastguard Worker     CHECK_EQ(U3RyaXBwaW5nVGVzdENoZWNrT3BWYXIx, U3RyaXBwaW5nVGVzdENoZWNrT3BWYXIy)
429*9356374aSAndroid Build Coastguard Worker         << "U3RyaXBwaW5nVGVzdC5DaGVja09w";
430*9356374aSAndroid Build Coastguard Worker   }
431*9356374aSAndroid Build Coastguard Worker 
432*9356374aSAndroid Build Coastguard Worker   std::unique_ptr<FILE, std::function<void(FILE*)>> exe = OpenTestExecutable();
433*9356374aSAndroid Build Coastguard Worker   ASSERT_THAT(exe, NotNull());
434*9356374aSAndroid Build Coastguard Worker 
435*9356374aSAndroid Build Coastguard Worker   if (absl::LogSeverity::kFatal >= kAbslMinLogLevel) {
436*9356374aSAndroid Build Coastguard Worker     EXPECT_THAT(exe.get(), FileHasSubstr(var_needle1));
437*9356374aSAndroid Build Coastguard Worker     EXPECT_THAT(exe.get(), FileHasSubstr(var_needle2));
438*9356374aSAndroid Build Coastguard Worker     EXPECT_THAT(exe.get(), FileHasSubstr(msg_needle));
439*9356374aSAndroid Build Coastguard Worker   } else {
440*9356374aSAndroid Build Coastguard Worker     EXPECT_THAT(exe.get(), Not(FileHasSubstr(var_needle1)));
441*9356374aSAndroid Build Coastguard Worker     EXPECT_THAT(exe.get(), Not(FileHasSubstr(var_needle2)));
442*9356374aSAndroid Build Coastguard Worker     EXPECT_THAT(exe.get(), Not(FileHasSubstr(msg_needle)));
443*9356374aSAndroid Build Coastguard Worker   }
444*9356374aSAndroid Build Coastguard Worker }
445*9356374aSAndroid Build Coastguard Worker 
TEST_F(StrippingTest,CheckStrOp)446*9356374aSAndroid Build Coastguard Worker TEST_F(StrippingTest, CheckStrOp) {
447*9356374aSAndroid Build Coastguard Worker   // See `StrippingTest.Check` for some hairy implementation notes.
448*9356374aSAndroid Build Coastguard Worker   const std::string var_needle1 =
449*9356374aSAndroid Build Coastguard Worker       absl::Base64Escape("StrippingTestCheckStrOpVar1");
450*9356374aSAndroid Build Coastguard Worker   const std::string var_needle2 =
451*9356374aSAndroid Build Coastguard Worker       absl::Base64Escape("StrippingTestCheckStrOpVar2");
452*9356374aSAndroid Build Coastguard Worker   const std::string msg_needle = absl::Base64Escape("StrippingTest.CheckStrOp");
453*9356374aSAndroid Build Coastguard Worker   const char *volatile U3RyaXBwaW5nVGVzdENoZWNrU3RyT3BWYXIx = "FEED";
454*9356374aSAndroid Build Coastguard Worker   const char *volatile U3RyaXBwaW5nVGVzdENoZWNrU3RyT3BWYXIy = "CAFE";
455*9356374aSAndroid Build Coastguard Worker   if (kReallyDie) {
456*9356374aSAndroid Build Coastguard Worker     CHECK_STREQ(U3RyaXBwaW5nVGVzdENoZWNrU3RyT3BWYXIx,
457*9356374aSAndroid Build Coastguard Worker                 U3RyaXBwaW5nVGVzdENoZWNrU3RyT3BWYXIy)
458*9356374aSAndroid Build Coastguard Worker         << "U3RyaXBwaW5nVGVzdC5DaGVja1N0ck9w";
459*9356374aSAndroid Build Coastguard Worker   }
460*9356374aSAndroid Build Coastguard Worker 
461*9356374aSAndroid Build Coastguard Worker   std::unique_ptr<FILE, std::function<void(FILE*)>> exe = OpenTestExecutable();
462*9356374aSAndroid Build Coastguard Worker   ASSERT_THAT(exe, NotNull());
463*9356374aSAndroid Build Coastguard Worker 
464*9356374aSAndroid Build Coastguard Worker   if (absl::LogSeverity::kFatal >= kAbslMinLogLevel) {
465*9356374aSAndroid Build Coastguard Worker     EXPECT_THAT(exe.get(), FileHasSubstr(var_needle1));
466*9356374aSAndroid Build Coastguard Worker     EXPECT_THAT(exe.get(), FileHasSubstr(var_needle2));
467*9356374aSAndroid Build Coastguard Worker     EXPECT_THAT(exe.get(), FileHasSubstr(msg_needle));
468*9356374aSAndroid Build Coastguard Worker   } else {
469*9356374aSAndroid Build Coastguard Worker     EXPECT_THAT(exe.get(), Not(FileHasSubstr(var_needle1)));
470*9356374aSAndroid Build Coastguard Worker     EXPECT_THAT(exe.get(), Not(FileHasSubstr(var_needle2)));
471*9356374aSAndroid Build Coastguard Worker     EXPECT_THAT(exe.get(), Not(FileHasSubstr(msg_needle)));
472*9356374aSAndroid Build Coastguard Worker   }
473*9356374aSAndroid Build Coastguard Worker }
474*9356374aSAndroid Build Coastguard Worker 
TEST_F(StrippingTest,CheckOk)475*9356374aSAndroid Build Coastguard Worker TEST_F(StrippingTest, CheckOk) {
476*9356374aSAndroid Build Coastguard Worker   // See `StrippingTest.Check` for some hairy implementation notes.
477*9356374aSAndroid Build Coastguard Worker   const std::string var_needle = absl::Base64Escape("StrippingTestCheckOkVar1");
478*9356374aSAndroid Build Coastguard Worker   const std::string msg_needle = absl::Base64Escape("StrippingTest.CheckOk");
479*9356374aSAndroid Build Coastguard Worker   volatile bool x = false;
480*9356374aSAndroid Build Coastguard Worker   auto U3RyaXBwaW5nVGVzdENoZWNrT2tWYXIx = absl::OkStatus();
481*9356374aSAndroid Build Coastguard Worker   if (x) {
482*9356374aSAndroid Build Coastguard Worker     U3RyaXBwaW5nVGVzdENoZWNrT2tWYXIx =
483*9356374aSAndroid Build Coastguard Worker         absl::InvalidArgumentError("Stripping this is not my job!");
484*9356374aSAndroid Build Coastguard Worker   }
485*9356374aSAndroid Build Coastguard Worker   if (kReallyDie) {
486*9356374aSAndroid Build Coastguard Worker     CHECK_OK(U3RyaXBwaW5nVGVzdENoZWNrT2tWYXIx)
487*9356374aSAndroid Build Coastguard Worker         << "U3RyaXBwaW5nVGVzdC5DaGVja09r";
488*9356374aSAndroid Build Coastguard Worker   }
489*9356374aSAndroid Build Coastguard Worker 
490*9356374aSAndroid Build Coastguard Worker   std::unique_ptr<FILE, std::function<void(FILE*)>> exe = OpenTestExecutable();
491*9356374aSAndroid Build Coastguard Worker   ASSERT_THAT(exe, NotNull());
492*9356374aSAndroid Build Coastguard Worker 
493*9356374aSAndroid Build Coastguard Worker   if (absl::LogSeverity::kFatal >= kAbslMinLogLevel) {
494*9356374aSAndroid Build Coastguard Worker     EXPECT_THAT(exe.get(), FileHasSubstr(var_needle));
495*9356374aSAndroid Build Coastguard Worker     EXPECT_THAT(exe.get(), FileHasSubstr(msg_needle));
496*9356374aSAndroid Build Coastguard Worker   } else {
497*9356374aSAndroid Build Coastguard Worker     EXPECT_THAT(exe.get(), Not(FileHasSubstr(var_needle)));
498*9356374aSAndroid Build Coastguard Worker     EXPECT_THAT(exe.get(), Not(FileHasSubstr(msg_needle)));
499*9356374aSAndroid Build Coastguard Worker   }
500*9356374aSAndroid Build Coastguard Worker }
501*9356374aSAndroid Build Coastguard Worker 
502*9356374aSAndroid Build Coastguard Worker }  // namespace
503