Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 41e8d52

Browse files
authored
Make FML_LOG safe from static initialization (#42219)
I ran into this while trying to get some printing going for places where we're creating thread local keys. Supposedly, just including `<iostream>` should statically initialize `std::cout/cerr`, but it gets really hard to reason about whether your statically initialized code is going to be initialized before or after that happens. I tried making sure that the TU for `fml/logging.cc` did that initialization statically, but that also failed in the verison of the test included here (it passed in some other iterations that modified run_all_unittests.cc). We _could_ make sure it happens each and every time we touch `std::cerr` but ... we could also just use `fprintf(stderr, ...)` and it works just fine. /cc @flar who ran into problems around this a little while back and was asking about it.
1 parent a1101e9 commit 41e8d52

File tree

2 files changed

+40
-2
lines changed

2 files changed

+40
-2
lines changed

fml/logging.cc

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,8 +123,9 @@ LogMessage::~LogMessage() {
123123
fx_logger_log_with_source(fx_log_get_logger(), fx_severity, nullptr, file_,
124124
line_, stream_.str().c_str());
125125
#else
126-
std::cerr << stream_.str();
127-
std::cerr.flush();
126+
// Don't use std::cerr here, because it may not be initialized properly yet.
127+
fprintf(stderr, "%s", stream_.str().c_str());
128+
fflush(stderr);
128129
#endif
129130

130131
if (severity_ >= LOG_FATAL) {

fml/logging_unittests.cc

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5+
#include <signal.h>
6+
57
#include "flutter/fml/build_config.h"
68
#include "flutter/fml/log_settings.h"
79
#include "flutter/fml/logging.h"
@@ -19,6 +21,41 @@
1921
namespace fml {
2022
namespace testing {
2123

24+
#ifndef OS_FUCHSIA
25+
class MakeSureFmlLogDoesNotSegfaultWhenStaticallyCalled {
26+
public:
27+
MakeSureFmlLogDoesNotSegfaultWhenStaticallyCalled() {
28+
SegfaultCatcher catcher;
29+
// If this line causes a segfault, FML is using a method of logging that is
30+
// not safe from static initialization on your platform.
31+
FML_LOG(INFO)
32+
<< "This log exists to verify that static logging from FML works.";
33+
}
34+
35+
private:
36+
struct SegfaultCatcher {
37+
typedef void (*sighandler_t)(int);
38+
39+
SegfaultCatcher() {
40+
handler = ::signal(SIGSEGV, SegfaultHandler);
41+
FML_CHECK(handler != SIG_ERR);
42+
}
43+
44+
~SegfaultCatcher() { FML_CHECK(::signal(SIGSEGV, handler) != SIG_ERR); }
45+
46+
static void SegfaultHandler(int signal) {
47+
fprintf(stderr,
48+
"FML failed to handle logging from static initialization.\n");
49+
exit(signal);
50+
}
51+
52+
sighandler_t handler;
53+
};
54+
};
55+
56+
static MakeSureFmlLogDoesNotSegfaultWhenStaticallyCalled fml_log_static_check_;
57+
#endif // !defined(OS_FUCHSIA)
58+
2259
int UnreachableScopeWithoutReturnDoesNotMakeCompilerMad() {
2360
KillProcess();
2461
// return 0; <--- Missing but compiler is fine.

0 commit comments

Comments
 (0)