Skip to content

Commit

Permalink
[exec-ctx] Remove ScopedTimeCache from ExecCtx on iOS (#34416)
Browse files Browse the repository at this point in the history
Fix a crash on older iOS versions due to problematic thread-local
variable initialization.

See firebase/firebase-ios-sdk#11509

Basically, there appears to be a bug in Xcode where it generates
assembly for thread-local variable initialization that is susceptible to
a crash. For example, on arm64 the generated assembly relies on
registers like x8 and x10 being preserved by the thread-local variable
initialization routine; however, in some cases this thread-local
variable initialization calls functions like
`ImageLoaderMachOCompressed::doBindFastLazySymbol` which clobber these
registers, leaving their values indeterminate when the caller resumes.
When those indeterminate values are later used as memory addresses they
are invalid and result in a crash.

This PR works around this bug by removing the `ScopedTimeCache` member
variable from the `ExecCtx` class on iOS. This is a reasonable
workaround because `ScopedTimeCache` is only a slight optimization for
data centers that entirely doesn't matter for mobile.

See https://github.com/dconeybe/TlsCrashIos12 for a demo of this crash.

Googlers see b/300501963 for full details.
  • Loading branch information
dconeybe committed Sep 25, 2023
1 parent fe70af2 commit df4c0c6
Showing 1 changed file with 22 additions and 2 deletions.
24 changes: 22 additions & 2 deletions src/core/lib/iomgr/exec_ctx.h
Expand Up @@ -23,6 +23,11 @@

#include <limits>

#if __APPLE__
// Provides TARGET_OS_IPHONE
#include <TargetConditionals.h>
#endif

#include <grpc/impl/grpc_types.h>
#include <grpc/support/atm.h>
#include <grpc/support/cpu.h>
Expand Down Expand Up @@ -180,13 +185,26 @@ class GRPC_DLL ExecCtx {
void SetReadyToFinishFlag() { flags_ |= GRPC_EXEC_CTX_FLAG_IS_FINISHED; }

Timestamp Now() { return Timestamp::Now(); }
void InvalidateNow() { time_cache_.InvalidateCache(); }

void InvalidateNow() {
#if !TARGET_OS_IPHONE
time_cache_.InvalidateCache();
#endif
}

void SetNowIomgrShutdown() {
#if !TARGET_OS_IPHONE
// We get to do a test only set now on this path just because iomgr
// is getting removed and no point adding more interfaces for it.
time_cache_.TestOnlySetNow(Timestamp::InfFuture());
#endif
}

void TestOnlySetNow(Timestamp now) {
#if !TARGET_OS_IPHONE
time_cache_.TestOnlySetNow(now);
#endif
}
void TestOnlySetNow(Timestamp now) { time_cache_.TestOnlySetNow(now); }

/// Gets pointer to current exec_ctx.
static ExecCtx* Get() { return EXEC_CTX; }
Expand All @@ -211,7 +229,9 @@ class GRPC_DLL ExecCtx {
CombinerData combiner_data_ = {nullptr, nullptr};
uintptr_t flags_;

#if !TARGET_OS_IPHONE
ScopedTimeCache time_cache_;
#endif

#if !defined(_WIN32) || !defined(_DLL)
static thread_local ExecCtx* exec_ctx_;
Expand Down

0 comments on commit df4c0c6

Please sign in to comment.