[exec-ctx] Remove ScopedTimeCache from ExecCtx on iOS (#34416)

Fix a crash on older iOS versions due to problematic thread-local
variable initialization.

See https://github.com/firebase/firebase-ios-sdk/issues/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.
pull/34475/head
Denver Coneybeare 1 year ago committed by GitHub
parent fe70af228b
commit df4c0c6325
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 24
      src/core/lib/iomgr/exec_ctx.h

@ -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>
@ -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; }
@ -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_;

Loading…
Cancel
Save