-
-
Notifications
You must be signed in to change notification settings - Fork 56
fix: Don't overwrite MainThreadId
#2165
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
SentryMainThreadData
MainThreadId
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not familiar with the sentry-unity codebase, so take it with a grain of salt. I fail to see a fix for the issue. Is making IsMainThreadId nullable somehow does it? I'm not entirely sure how overwriting an integer creates a racing condition in the first place. It's the same integer and writing int should be atomic, no? Read-write can be a racing condition, but in this case, we're writing the same integer value and not computing anything. From the problem statement, it seems that MainThreadId is probably not initialized in time, right? I wonder if it can be initialized even earlier.
=> MainThreadId.HasValue && Thread.CurrentThread.ManagedThreadId == MainThreadId; | ||
public static bool? IsMainThread() | ||
{ | ||
if (MainThreadId.HasValue) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since it’s an integer that should be set once and visible across threads, I think declaring it as volatile makes sense:
internal static volatile int _mainThreadId;
If you really need to make it nullable, then this should also work:
private static int? _mainThreadId;
internal static int? MainThreadId
{
get => Volatile.Read(ref _mainThreadId);
set => Volatile.Write(ref _mainThreadId, value);
}
Fixes #2164
The Issue
Based on #2164 the SDK seems to run into a race condition with
IsMainThread()
.I might have been able to reproduce it locally, once by:
RuntimeInitializeOnLoadMethod
as well.MainThreadData.CollectData
gets called twice. Once byAndroidNative.Configure
, once bySentyUnity.Init
IsMainThread
falsely resolves tofalse
andSentryJava
attempts to detach from the JNIMy assumption is that calling multiple calls to
CollectData
assign and overwrite the nullableMainThreadId
and the non-atomic checkcreates a race condition even if the same integer is getting set.
Proposal
The
MainThreadId
should not be overwritten once setThe current best practice for libraries to handle
IsMainThread
is to fetch the current thread ID at a place where it is guaranteed to be the main thread. Those are methods likeAwake
,Start
, and theRuntimeInitializeOnLoadMethod
.On Android, when setting up the ScopeObserver, the SDK already requires
IsMainThread
. Since we know it's getting called through theSentryInitialization
, we keep collecting it there.The subsequent call during
Init
does not overwrite it.Make
IsMainThread
nullable &&SentryJava
update forIsMainThread
In case of user manually setting up or initializing, the
SentryJava
needs to be able to be certain whether it is running on the main thread or not. A false positive and the attempt to detach on the main thread crashes the game.