Skip to content

Commit 2729809

Browse files
Fix deadlock if ensure event captured during garbage collection (#860)
* Fix deadlock if ensure captured durig garbage collection * Add GC check for mobile * Update README.md Co-authored-by: Stefan Jandl <[email protected]> --------- Co-authored-by: Stefan Jandl <[email protected]>
1 parent 58425af commit 2729809

File tree

5 files changed

+47
-28
lines changed

5 files changed

+47
-28
lines changed

CHANGELOG.md

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,6 @@
1414
### Fixes
1515

1616
- Fix crash during garbage collection if SentryId was instantiated outside of game thread ([#857](https://github.com/getsentry/sentry-unreal/pull/857))
17-
18-
### Fixes
19-
2017
- Fix ensure when log message from non-game thread ([#845](https://github.com/getsentry/sentry-unreal/pull/845))
2118

2219
### Dependencies

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ Blog posts:
5353

5454
- Only crash events captured on Android contain the full callstack. Events that were captured manually won't have the native C++ part there.
5555

56-
- On Windows/Linux if crash event was captured during the garbage collection the `BeforeSendHandler` will not be invoked.
56+
- If an event was captured during the garbage collection, the `BeforeSendHandler` will not be invoked.
5757

5858
- It may be required to upgrade the C++ standard library (`libstdc++`) on older Linux distributions (such as Ubuntu 18.04 and 20.04) to ensure crashpad handler proper functionality within the deployment environment. This can be achieved with something like this:
5959
```

plugin-dev/Source/Sentry/Private/Android/Jni/SentryJniAndroid.cpp

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,18 @@ JNI_METHOD void Java_io_sentry_unreal_SentryBridgeJava_onConfigureScope(JNIEnv*
4141

4242
JNI_METHOD jobject Java_io_sentry_unreal_SentryBridgeJava_onBeforeSend(JNIEnv* env, jclass clazz, jlong objAddr, jobject event, jobject hint)
4343
{
44-
FGCScopeGuard GCScopeGuard;
45-
4644
if (FUObjectThreadContext::Get().IsRoutingPostLoad)
4745
{
48-
UE_LOG(LogSentrySdk, Log, TEXT("Executing `beforeSend` handler is not allowed when post-loading."));
46+
UE_LOG(LogSentrySdk, Log, TEXT("Executing `beforeSend` handler is not allowed during object post-loading."));
47+
return event;
48+
}
49+
50+
if (IsGarbageCollecting())
51+
{
52+
// If event is captured during garbage collection we can't instantiate UObjects safely or obtain a GC lock
53+
// since it will cause a deadlock (see https://github.com/getsentry/sentry-unreal/issues/850).
54+
// In this case event will be reported without calling a `beforeSend` handler.
55+
UE_LOG(LogSentrySdk, Log, TEXT("Executing `beforeSend` handler is not allowed during garbage collection."));
4956
return event;
5057
}
5158

plugin-dev/Source/Sentry/Private/Apple/AppleSentrySubsystem.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,14 +67,21 @@ void FAppleSentrySubsystem::InitWithSettings(const USentrySettings* settings, US
6767
return scope;
6868
};
6969
options.beforeSend = ^SentryEvent* (SentryEvent* event) {
70-
FGCScopeGuard GCScopeGuard;
71-
7270
if (FUObjectThreadContext::Get().IsRoutingPostLoad)
7371
{
7472
UE_LOG(LogSentrySdk, Log, TEXT("Executing `beforeSend` handler is not allowed when post-loading."));
7573
return event;
7674
}
7775

76+
if (IsGarbageCollecting())
77+
{
78+
// If event is captured during garbage collection we can't instantiate UObjects safely or obtain a GC lock
79+
// since it will cause a deadlock (see https://github.com/getsentry/sentry-unreal/issues/850).
80+
// In this case event will be reported without calling a `beforeSend` handler.
81+
UE_LOG(LogSentrySdk, Log, TEXT("Executing `beforeSend` handler is not allowed during garbage collection."));
82+
return event;
83+
}
84+
7885
USentryEvent* EventToProcess = USentryEvent::Create(MakeShareable(new SentryEventApple(event)));
7986

8087
USentryEvent* ProcessedEvent = beforeSendHandler->HandleBeforeSend(EventToProcess, nullptr);

plugin-dev/Source/Sentry/Private/GenericPlatform/GenericPlatformSentrySubsystem.cpp

Lines changed: 27 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -92,16 +92,23 @@ sentry_value_t FGenericPlatformSentrySubsystem::OnBeforeSend(sentry_value_t even
9292

9393
GetCurrentScope()->Apply(Event);
9494

95-
FGCScopeGuard GCScopeGuard;
96-
9795
if (FUObjectThreadContext::Get().IsRoutingPostLoad)
9896
{
99-
UE_LOG(LogSentrySdk, Log, TEXT("Executing `beforeSend` handler is not allowed when post-loading."));
97+
UE_LOG(LogSentrySdk, Log, TEXT("Executing `beforeSend` handler is not allowed during object post-loading."));
98+
return event;
99+
}
100+
101+
if (IsGarbageCollecting())
102+
{
103+
// If event is captured during garbage collection we can't instantiate UObjects safely or obtain a GC lock
104+
// since it will cause a deadlock (see https://github.com/getsentry/sentry-unreal/issues/850).
105+
// In this case event will be reported without calling a `beforeSend` handler.
106+
UE_LOG(LogSentrySdk, Log, TEXT("Executing `beforeSend` handler is not allowed during garbage collection."));
100107
return event;
101108
}
102109

103110
USentryEvent* EventToProcess = USentryEvent::Create(Event);
104-
111+
105112
USentryEvent* ProcessedEvent = GetBeforeSendHandler()->HandleBeforeSend(EventToProcess, nullptr);
106113

107114
return ProcessedEvent ? event : sentry_value_new_null();
@@ -127,26 +134,27 @@ sentry_value_t FGenericPlatformSentrySubsystem::OnCrash(const sentry_ucontext_t*
127134

128135
GetCurrentScope()->Apply(Event);
129136

130-
if (!IsGarbageCollecting())
137+
if (FUObjectThreadContext::Get().IsRoutingPostLoad)
131138
{
132-
USentryEvent* EventToProcess = USentryEvent::Create(Event);
133-
134-
USentryEvent* ProcessedEvent = EventToProcess;
135-
if (!FUObjectThreadContext::Get().IsRoutingPostLoad)
136-
{
137-
// Executing UFUNCTION is allowed only when not post-loading
138-
ProcessedEvent = GetBeforeSendHandler()->HandleBeforeSend(EventToProcess, nullptr);
139-
}
140-
141-
return ProcessedEvent ? event : sentry_value_new_null();
139+
UE_LOG(LogSentrySdk, Log, TEXT("Executing `beforeSend` handler is not allowed when post-loading."));
140+
return event;
142141
}
143-
else
142+
143+
if (IsGarbageCollecting())
144144
{
145-
// If crash occurred during garbage collection we can't just obtain a GC lock like with normal events
146-
// since there is no guarantee it will be ever freed. In this case crash event will be reported
147-
// without calling a `beforeSend` handler.
145+
// If crash occurred during garbage collection we can't instantiate UObjects safely or obtain a GC lock
146+
// since there is no guarantee it will be ever freed.
147+
// In this case crash event will be reported without calling a `beforeSend` handler.
148+
UE_LOG(LogSentrySdk, Log, TEXT("Executing `beforeSend` handler is not allowed during garbage collection."));
148149
return event;
149150
}
151+
152+
USentryEvent* EventToProcess = USentryEvent::Create(Event);
153+
154+
USentryEvent* ProcessedEvent = GetBeforeSendHandler()->HandleBeforeSend(EventToProcess, nullptr);
155+
156+
return ProcessedEvent ? event : sentry_value_new_null();
157+
150158
}
151159

152160
FGenericPlatformSentrySubsystem::FGenericPlatformSentrySubsystem()

0 commit comments

Comments
 (0)