Summary
When C# exception auto-tracking is enabled with TDAutoTrackEventType.AppCrash, TDExceptionHandler._LogHandler synchronously calls TDAnalytics.Track("ta_app_crash", ...) from Unity's global log callback.
If the Error log is emitted while IL2CPP/HybridCLR is already handling a native crash, this performs an Android JNI call in an unstable crash context. The JNI call can throw a secondary AndroidJavaException; formatting/printing that Java exception then reports java.lang.StackOverflowError thrown while calling printStackTrace, obscuring or amplifying the original crash.
This issue is intermittent because it requires the Unity Error callback and an unhealthy JNI/native runtime state to overlap.
Environment
- Unity: 2022.3.62f2
- Platform: Android 12, arm64
- Backend: IL2CPP + HybridCLR 8.3.0
- Device observed: OPPO PFVM10
- ThinkingData Unity SDK: reproduced with 3.4.8
- Latest checked version: 3.5.0
Relevant SDK code
In v3.5.0, the handler still reports synchronously:
private static void _LogHandler(string logString, string stackTrace, LogType type)
{
if (type == LogType.Error || type == LogType.Exception || type == LogType.Assert)
{
// Build properties...
TDAnalytics.Track("ta_app_crash", properties);
}
}
Source:
https://github.com/ThinkingDataAnalytics/unity-sdk/blob/v3.5.0/ThinkingAnalytics/Exception/TDException.cs#L80-L96
The Android wrapper catches the JNI exception but logs the complete exception object:
catch (Exception e)
{
TDLog.w("ThinkingAnalytics: unexpected exception: " + e);
}
Source:
https://github.com/ThinkingDataAnalytics/unity-sdk/blob/v3.5.0/ThinkingAnalytics/Wrapper/TDAndroidWrapper.cs#L133-L143
Sanitized log excerpt
[ThinkingData] Warning: ThinkingAnalytics: unexpected exception:
UnityEngine.AndroidJavaException
at UnityEngine._AndroidJNIHelper.GetMethodID(...)
at UnityEngine.AndroidJavaObject._CallStatic(...)
at ThinkingData.Analytics.Wrapper.TDWrapper.track(...)
at ThinkingData.Analytics.TDException.TDExceptionHandler._LogHandler(...)
at UnityEngine.Application.CallLogCallback(...)
JNI WARNING: java.lang.StackOverflowError thrown while calling printStackTrace
[hybridclr] ========== CRASH!!! IL2CPP+HYBRIDCLR STACK TRACE ==================
Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0
Cause: null pointer dereference
Normal analytics events, including events immediately before this crash, were successfully queued and uploaded. Therefore this does not appear to be caused by late ThinkingData initialization.
The product-fetch failure occurring earlier was logged as LogType.Warning, while _LogHandler only processes Error/Exception/Assert, so that warning alone does not invoke the crash handler.
Expected behavior
The crash/error collector should not synchronously perform JNI/native analytics work from Application.logMessageReceived or AppDomain.UnhandledException, especially during a fatal native crash.
Actual behavior
The exception handler immediately calls the Android bridge. A secondary JNI exception is produced while the runtime is already failing, and its stack printing can produce an additional StackOverflowError warning before the final SIGSEGV.
Suggested fix
Please consider:
- Add a thread-safe reentrancy guard to the exception handler.
- Only copy/enqueue crash information inside the Unity log callback; upload it later from a safe update loop.
- Persist fatal-crash information locally and upload it on the next launch instead of calling JNI during crash handling.
- Avoid logging or formatting the complete
AndroidJavaException from within the crash-reporting path.
- Filter SDK-generated logs from C# exception auto-tracking.
Current workaround
Setting:
TDPublicConfig.DisableCSharpException = true;
avoids this C# callback path, but it also disables Unity C# exception auto-collection. We would prefer to keep exception collection enabled with a crash-safe reporting implementation.
Summary
When C# exception auto-tracking is enabled with
TDAutoTrackEventType.AppCrash,TDExceptionHandler._LogHandlersynchronously callsTDAnalytics.Track("ta_app_crash", ...)from Unity's global log callback.If the Error log is emitted while IL2CPP/HybridCLR is already handling a native crash, this performs an Android JNI call in an unstable crash context. The JNI call can throw a secondary
AndroidJavaException; formatting/printing that Java exception then reportsjava.lang.StackOverflowError thrown while calling printStackTrace, obscuring or amplifying the original crash.This issue is intermittent because it requires the Unity Error callback and an unhealthy JNI/native runtime state to overlap.
Environment
Relevant SDK code
In v3.5.0, the handler still reports synchronously:
Source:
https://github.com/ThinkingDataAnalytics/unity-sdk/blob/v3.5.0/ThinkingAnalytics/Exception/TDException.cs#L80-L96
The Android wrapper catches the JNI exception but logs the complete exception object:
Source:
https://github.com/ThinkingDataAnalytics/unity-sdk/blob/v3.5.0/ThinkingAnalytics/Wrapper/TDAndroidWrapper.cs#L133-L143
Sanitized log excerpt
Normal analytics events, including events immediately before this crash, were successfully queued and uploaded. Therefore this does not appear to be caused by late ThinkingData initialization.
The product-fetch failure occurring earlier was logged as
LogType.Warning, while_LogHandleronly processes Error/Exception/Assert, so that warning alone does not invoke the crash handler.Expected behavior
The crash/error collector should not synchronously perform JNI/native analytics work from
Application.logMessageReceivedorAppDomain.UnhandledException, especially during a fatal native crash.Actual behavior
The exception handler immediately calls the Android bridge. A secondary JNI exception is produced while the runtime is already failing, and its stack printing can produce an additional
StackOverflowErrorwarning before the final SIGSEGV.Suggested fix
Please consider:
AndroidJavaExceptionfrom within the crash-reporting path.Current workaround
Setting:
avoids this C# callback path, but it also disables Unity C# exception auto-collection. We would prefer to keep exception collection enabled with a crash-safe reporting implementation.