Skip to content

Fix crash when parsing native stack frames without symbols#278

Open
BartoszLitwiniuk wants to merge 39 commits into
masterfrom
bugfix/native_stack_frames_fix
Open

Fix crash when parsing native stack frames without symbols#278
BartoszLitwiniuk wants to merge 39 commits into
masterfrom
bugfix/native_stack_frames_fix

Conversation

@BartoszLitwiniuk
Copy link
Copy Markdown
Contributor

@BartoszLitwiniuk BartoszLitwiniuk commented Mar 5, 2026

Summary

Fixes a crash in the native stack trace parser when frames are missing symbol information. Refactors BacktraceRawStackTraceParser for safer parsing and adds unit test coverage.

It's a follow up of changes made in #258 and bug BT-5953.

Changes

  • Added bounds checks in SetNativeStackTraceInformation to prevent out-of-range access when a native frame lacks symbol data
  • Extract parsing logic to BacktraceRawStackTraceParser for clearer, more defensive frame parsing
  • Added debug logging to aid future diagnosis of malformed frames
  • Added BacktraceRawStackTraceParserTests covering native frame parsing edge cases
  • Use BacktraceRawStackTraceParser in BacktraceUnhandledException instead of mixing unhandled exception handler with parsing logic

Testing

  • New unit tests validate safe parsing of native frames, including frames without symbols
  • Existing tests continue to pass

@BartoszLitwiniuk BartoszLitwiniuk changed the title Bugfix/native stack frames fix Draft: Bugfix/native stack frames fix Mar 5, 2026
@BartoszLitwiniuk BartoszLitwiniuk marked this pull request as draft March 5, 2026 21:04
@BartoszLitwiniuk BartoszLitwiniuk changed the base branch from bugfix/native_stack_frames to master April 11, 2026 07:07
@BartoszLitwiniuk BartoszLitwiniuk marked this pull request as ready for review April 15, 2026 10:37
@BartoszLitwiniuk BartoszLitwiniuk marked this pull request as draft April 15, 2026 10:57
@BartoszLitwiniuk BartoszLitwiniuk marked this pull request as ready for review April 21, 2026 18:02
Bartosz Litwiniuk added 3 commits April 21, 2026 20:09
…ve_stack_frames_fix

# Conflicts:
#	Runtime/Model/BacktraceRawStackTraceParser.cs
@BartoszLitwiniuk BartoszLitwiniuk changed the title Draft: Bugfix/native stack frames fix Fix crash when parsing native stack frames without symbols Apr 21, 2026
Bartosz Litwiniuk added 5 commits May 6, 2026 22:57
…mes_fix

# Conflicts:
#	Runtime/Model/BacktraceRawStackTraceParser.cs
#	Tests/Runtime/Model/BacktraceRawStackTraceParserTests.cs
@melekr melekr self-requested a review May 8, 2026 14:18
@melekr
Copy link
Copy Markdown
Collaborator

melekr commented May 8, 2026

can you link sample BT reports @BartoszLitwiniuk ?

Comment thread .gitignore Outdated

# Platforms
iOS/
Mac/ No newline at end of file
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what's the reason here?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reverted

@melekr melekr self-requested a review May 8, 2026 14:22
Comment on lines +44 to +45
int methodNameEndIndex = frameString.IndexOf(')');
int openParentIndex = frameString.LastIndexOf('(', methodNameEndIndex); // we require a '(' that appears before this ')'
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can throw before the invalid-frame check.

If frameString is non-empty and has no ), then methodNameEndIndex is -1,
and LastIndexOf('(', -1) throws ArgumentOutOfRangeException.

That changes behaviour from the previous implementation which preserved frames without )as raw BacktraceStackFrame instances.

With the current code, the catch returns null, and ConvertStackFrames drops the frame entirely.

I suggest something like this :

Suggested change
int methodNameEndIndex = frameString.IndexOf(')');
int openParentIndex = frameString.LastIndexOf('(', methodNameEndIndex); // we require a '(' that appears before this ')'
int methodNameEndIndex = frameString.IndexOf(')');
if (methodNameEndIndex == -1)
{
return new BacktraceStackFrame
{
FunctionName = frame,
InvalidFrame = true
};
}
int openParentIndex = frameString.LastIndexOf('(', methodNameEndIndex);
if (openParentIndex == -1 || openParentIndex > methodNameEndIndex)
{
return new BacktraceStackFrame
{
FunctionName = frame,
InvalidFrame = true
};
}

Comment on lines +58 to +59
Debug.LogError($"Exception while parsing stack frame: '{frame}'. Exception: {e}");
return null;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Returning null here causes the frame to be dropped.

I think parser failure should preserve the raw frame, not remove diagnostic data from the report.

Also, logging with Debug.LogError from report construction is risky in this SDK: Unity error logs are reportable, so a parser failure can create a secondary Backtrace report or another capture.

if (methodNameEndIndex == -1 || openParentIndex == -1 || openParentIndex > methodNameEndIndex)
{
// If either index is missing, it's an invalid frame
Debug.LogWarning($"Invalid stack frame format: '{frameString}'.");
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would avoid logging from the parser for the same reason.

return stackFrame;
}

frameString = frameString.Substring(frameString.IndexOf(' ')).Trim();
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This remains unsafe;

If a JIT frame starts with # but does not contain a space, IndexOf(' ') returns -1 and Substring(-1) throws.

With the current wrapper logic, that exception causes the frame to be dropped.

return stackFrame;
}

frameString = frameString.Substring(frameString.IndexOf(' ')).Trim();
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

something like :

Suggested change
frameString = frameString.Substring(frameString.IndexOf(' ')).Trim();
int firstSpace = frameString.IndexOf(' ');
if (firstSpace == -1 || firstSpace == frameString.Length - 1)
{
stackFrame.FunctionName = frameString;
return stackFrame;
}
frameString = frameString.Substring(firstSpace + 1).Trim();


namespace Backtrace.Unity.Tests.Runtime
{
public class BacktraceRawStackTraceParserTests
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

needs more coverage especially through ConvertStackFrames and ConvertStackFrames

namespace Backtrace.Unity.Types
{
enum BacktraceStackFrameType
public enum BacktraceStackFrameType
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does this need to become public ?


namespace Backtrace.Unity.Tests.Runtime
{
public class BacktraceRawStackTraceParserTests
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's add an end-to-end serialization test or attach a sample Backtrace report here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants