Skip to content

Make absl::InitializeLog() safe to call more than once (#1656)#2046

Open
Othmane-Ch wants to merge 1 commit intoabseil:masterfrom
Othmane-Ch:fix/log-initialize-idempotent
Open

Make absl::InitializeLog() safe to call more than once (#1656)#2046
Othmane-Ch wants to merge 1 commit intoabseil:masterfrom
Othmane-Ch:fix/log-initialize-idempotent

Conversation

@Othmane-Ch
Copy link
Copy Markdown

Fixes #1656.

Previously, calling absl::InitializeLog() more than once aborted the program: the underlying absl::log_internal::SetTimeZone() fires ABSL_RAW_LOG(FATAL, "...has already been called") on its second invocation. The header documented this as "an error to call this function twice", but in real-world systems multiple independent libraries each want to bring up the logging library and have no way to coordinate among themselves — Google's XLA project being the example cited in #1656.

Change

Wrap the body of InitializeLog() in absl::call_once. Exactly the first invocation runs the underlying initialization; all subsequent calls (including concurrent ones from other threads) become no-ops. The first caller's absl::LocalTimeZone() value wins, matching the documented "only the first call has effect" intent — just made safe instead of UB.

Net diff: +106 / −2 across 5 files.

  • absl/log/initialize.ccabsl::call_once guard around InitializeLogImpl(absl::LocalTimeZone()).
  • absl/log/initialize.h — docstring updated to document the new contract (safe to call repeatedly; concurrent callers block until the first call completes).
  • absl/log/initialize_test.cc — new gtest covering: first call initializes, second call is a no-op, concurrent calls from N threads are safe.
  • absl/log/BUILD.bazel, absl/log/CMakeLists.txt — wire the new test target and add the //absl/base (CMake: absl::base) dep to the log_initialize library for call_once.

Testing

Built and ran the new test locally with CMake/Ninja + MSVC 19.36 on Windows:

[==========] 3 tests from InitializeLogTest
[ RUN      ] InitializeLogTest.FirstCallInitializes      OK (0 ms)
[ RUN      ] InitializeLogTest.SecondCallIsNoOp          OK (0 ms)
[ RUN      ] InitializeLogTest.ConcurrentCallsAreSafe    OK (1 ms)
[==========] 3 tests from 1 test suite ran. (2 ms total)
[  PASSED  ] 3 tests.

Sibling regression check: absl_log_globals_test also passes after the BUILD/CMake edits.

Without the call_once guard, ConcurrentCallsAreSafe either races on the initialization globals or aborts via the FATAL raw log inside SetTimeZone(), so it doubles as a regression marker.

Notes

  • No public API surface change — same function name, same signature.
  • The cost on every InitializeLog() call is one absl::call_once flag check, which after the first call is a single relaxed atomic load on the fast path.
  • Out of scope: adding a ShutdownLog() / re-init capability (the issue does not request it)

Previously, calling absl::InitializeLog() more than once caused the
program to abort: the underlying absl::log_internal::SetTimeZone() call
fires ABSL_RAW_LOG(FATAL, "...has already been called") on its second
invocation. The header documented this as "an error to call this
function twice", but in real-world systems multiple independent
libraries each want to bring up the logging library and have no way
to coordinate among themselves -- Google's XLA project being the
example cited in abseil#1656.

This change wraps the body of InitializeLog() in absl::call_once so
that exactly the first invocation runs the underlying initialization
and all subsequent calls (including concurrent ones from other threads)
become no-ops. The first caller's absl::LocalTimeZone() value wins,
matching the existing "only the first call has effect" intent of the
documented behaviour, just made safe instead of UB.

initialize.h is updated to document the new contract. A new
initialize_test.cc covers the repeat-call and concurrent-call cases;
without the call_once guard the concurrent test races on the
initialization globals or aborts via the FATAL raw log inside
SetTimeZone(), which serves as a regression marker for the bug.

The new code path takes the call_once flag once on every InitializeLog()
call; the cost after the first call is a single relaxed atomic load.

Closes abseil#1656.
@google-cla
Copy link
Copy Markdown

google-cla Bot commented May 6, 2026

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@rmjoona27-create
Copy link
Copy Markdown

rmjoona27-create commented May 6, 2026 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Make absl::InitializeLog safe to be called multiple times

2 participants