Skip to content

Commit 8b68380

Browse files
derekmaurocopybara-github
authored andcommitted
Fix a use-after-free bug in which the string passed to AtLocation may be
referenced after it is destroyed. While the string does live until the end of the full statement, logging (previously occurred) in the destructor of the `LogMessage` which may be constructed before the temporary string (and thus destroyed after the temporary string's destructor). This change moves logging to occur inside the internal `Voidify`. This does not affect when logging occurs relative to any other observable, other than the fact that it runs later than any temporary destructors in the log statement. PiperOrigin-RevId: 729708145 Change-Id: I9b90367d7a5f4ed3cf091d4d33756262acc03ec6
1 parent 9a41f7c commit 8b68380

8 files changed

+40
-32
lines changed

Diff for: absl/log/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,7 @@ absl_cc_library(
379379
${ABSL_DEFAULT_LINKOPTS}
380380
DEPS
381381
absl::config
382+
absl::core_headers
382383
)
383384

384385
absl_cc_library(

Diff for: absl/log/internal/BUILD.bazel

+4-1
Original file line numberDiff line numberDiff line change
@@ -415,7 +415,10 @@ cc_library(
415415
hdrs = ["voidify.h"],
416416
copts = ABSL_DEFAULT_COPTS,
417417
linkopts = ABSL_DEFAULT_LINKOPTS,
418-
deps = ["//absl/base:config"],
418+
deps = [
419+
"//absl/base:config",
420+
"//absl/base:core_headers",
421+
],
419422
)
420423

421424
cc_library(

Diff for: absl/log/internal/conditions.h

+3-2
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@
6565
switch (0) \
6666
case 0: \
6767
default: \
68-
!(condition) ? (void)0 : ::absl::log_internal::Voidify()&&
68+
!(condition) ? (void)0 : ::absl::log_internal::Voidify() &&
6969

7070
// `ABSL_LOG_INTERNAL_STATEFUL_CONDITION` applies a condition like
7171
// `ABSL_LOG_INTERNAL_STATELESS_CONDITION` but adds to that a series of variable
@@ -96,7 +96,8 @@
9696
for (const uint32_t COUNTER ABSL_ATTRIBUTE_UNUSED = \
9797
absl_log_internal_stateful_condition_state.counter(); \
9898
absl_log_internal_stateful_condition_do_log; \
99-
absl_log_internal_stateful_condition_do_log = false)
99+
absl_log_internal_stateful_condition_do_log = false) \
100+
::absl::log_internal::Voidify() &&
100101

101102
// `ABSL_LOG_INTERNAL_CONDITION_*` serve to combine any conditions from the
102103
// macro (e.g. `LOG_IF` or `VLOG`) with inherent conditions (e.g.

Diff for: absl/log/internal/log_message.cc

+2-14
Original file line numberDiff line numberDiff line change
@@ -291,16 +291,8 @@ LogMessage::LogMessage(absl::Nonnull<const char*> file, int line, WarningTag)
291291
LogMessage::LogMessage(absl::Nonnull<const char*> file, int line, ErrorTag)
292292
: LogMessage(file, line, absl::LogSeverity::kError) {}
293293

294-
LogMessage::~LogMessage() {
295-
#ifdef ABSL_MIN_LOG_LEVEL
296-
if (data_->entry.log_severity() <
297-
static_cast<absl::LogSeverity>(ABSL_MIN_LOG_LEVEL) &&
298-
data_->entry.log_severity() < absl::LogSeverity::kFatal) {
299-
return;
300-
}
301-
#endif
302-
Flush();
303-
}
294+
// This cannot go in the header since LogMessageData is defined in this file.
295+
LogMessage::~LogMessage() = default;
304296

305297
LogMessage& LogMessage::AtLocation(absl::string_view file, int line) {
306298
data_->entry.full_filename_ = file;
@@ -691,7 +683,6 @@ LogMessageFatal::LogMessageFatal(absl::Nonnull<const char*> file, int line,
691683
}
692684

693685
LogMessageFatal::~LogMessageFatal() {
694-
Flush();
695686
FailWithoutStackTrace();
696687
}
697688

@@ -700,7 +691,6 @@ LogMessageDebugFatal::LogMessageDebugFatal(absl::Nonnull<const char*> file,
700691
: LogMessage(file, line, absl::LogSeverity::kFatal) {}
701692

702693
LogMessageDebugFatal::~LogMessageDebugFatal() {
703-
Flush();
704694
FailWithoutStackTrace();
705695
}
706696

@@ -711,7 +701,6 @@ LogMessageQuietlyDebugFatal::LogMessageQuietlyDebugFatal(
711701
}
712702

713703
LogMessageQuietlyDebugFatal::~LogMessageQuietlyDebugFatal() {
714-
Flush();
715704
FailQuietly();
716705
}
717706

@@ -729,7 +718,6 @@ LogMessageQuietlyFatal::LogMessageQuietlyFatal(
729718
}
730719

731720
LogMessageQuietlyFatal::~LogMessageQuietlyFatal() {
732-
Flush();
733721
FailQuietly();
734722
}
735723
#if defined(_MSC_VER) && !defined(__clang__)

Diff for: absl/log/internal/log_message.h

+9-11
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,12 @@
1717
// -----------------------------------------------------------------------------
1818
//
1919
// This file declares `class absl::log_internal::LogMessage`. This class more or
20-
// less represents a particular log message. LOG/CHECK macros create a
21-
// temporary instance of `LogMessage` and then stream values to it. At the end
22-
// of the LOG/CHECK statement, LogMessage instance goes out of scope and
23-
// `~LogMessage` directs the message to the registered log sinks.
24-
// Heap-allocation of `LogMessage` is unsupported. Construction outside of a
25-
// `LOG` macro is unsupported.
20+
// less represents a particular log message. LOG/CHECK macros create a temporary
21+
// instance of `LogMessage` and then stream values to it. At the end of the
22+
// LOG/CHECK statement, the LogMessage is voidified by operator&&, and `Flush()`
23+
// directs the message to the registered log sinks. Heap-allocation of
24+
// `LogMessage` is unsupported. Construction outside of a `LOG` macro is
25+
// unsupported.
2626

2727
#ifndef ABSL_LOG_INTERNAL_LOG_MESSAGE_H_
2828
#define ABSL_LOG_INTERNAL_LOG_MESSAGE_H_
@@ -188,6 +188,9 @@ class LogMessage {
188188
template <typename T>
189189
LogMessage& operator<<(const T& v) ABSL_ATTRIBUTE_NOINLINE;
190190

191+
// Dispatches the completed `absl::LogEntry` to applicable `absl::LogSink`s.
192+
void Flush();
193+
191194
// Note: We explicitly do not support `operator<<` for non-const references
192195
// because it breaks logging of non-integer bitfield types (i.e., enums).
193196

@@ -200,11 +203,6 @@ class LogMessage {
200203
// the process with an error exit code.
201204
[[noreturn]] static void FailQuietly();
202205

203-
// Dispatches the completed `absl::LogEntry` to applicable `absl::LogSink`s.
204-
// This might as well be inlined into `~LogMessage` except that
205-
// `~LogMessageFatal` needs to call it early.
206-
void Flush();
207-
208206
// After this is called, failures are done as quiet as possible for this log
209207
// message.
210208
void SetFailQuietly();

Diff for: absl/log/internal/nullstream.h

+1
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ class NullStream {
7979
return *this;
8080
}
8181
NullStream& InternalStream() { return *this; }
82+
void Flush() {}
8283
};
8384
template <typename T>
8485
inline NullStream& operator<<(NullStream& str, const T&) {

Diff for: absl/log/internal/voidify.h

+10-4
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,15 @@
1616
// File: log/internal/voidify.h
1717
// -----------------------------------------------------------------------------
1818
//
19-
// This class is used to explicitly ignore values in the conditional logging
20-
// macros. This avoids compiler warnings like "value computed is not used" and
21-
// "statement has no effect".
19+
// This class does the dispatching of the completed `absl::LogEntry` to
20+
// applicable `absl::LogSink`s, and is used to explicitly ignore values in the
21+
// conditional logging macros. This avoids compiler warnings like "value
22+
// computed is not used" and "statement has no effect".
2223

2324
#ifndef ABSL_LOG_INTERNAL_VOIDIFY_H_
2425
#define ABSL_LOG_INTERNAL_VOIDIFY_H_
2526

27+
#include "absl/base/attributes.h"
2628
#include "absl/base/config.h"
2729

2830
namespace absl {
@@ -34,7 +36,11 @@ class Voidify final {
3436
// This has to be an operator with a precedence lower than << but higher than
3537
// ?:
3638
template <typename T>
37-
void operator&&(const T&) const&& {}
39+
ABSL_ATTRIBUTE_COLD void operator&&(T&& message) const&& {
40+
// The dispatching of the completed `absl::LogEntry` to applicable
41+
// `absl::LogSink`s happens here.
42+
message.Flush();
43+
}
3844
};
3945

4046
} // namespace log_internal

Diff for: absl/log/log_modifier_methods_test.cc

+10
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515

1616
#include <errno.h>
1717

18+
#include <string>
19+
1820
#include "gmock/gmock.h"
1921
#include "gtest/gtest.h"
2022
#include "absl/log/internal/test_actions.h"
@@ -77,6 +79,14 @@ TEST(TailCallsModifiesTest, AtLocationFileLine) {
7779
<< "hello world";
7880
}
7981

82+
TEST(TailCallsModifiesTest, AtLocationFileLineLifetime) {
83+
// The macro takes care to not use this temporary after its lifetime.
84+
// The only salient expectation is "no sanitizer diagnostics".
85+
LOG(INFO).AtLocation(std::string("/my/very/very/very_long_source_file.cc"),
86+
777)
87+
<< "hello world";
88+
}
89+
8090
TEST(TailCallsModifiesTest, NoPrefix) {
8191
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
8292

0 commit comments

Comments
 (0)