Skip to content
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

Increase the maximum stacktrace frame length #1923

Open
brustolin opened this issue Jun 29, 2022 · 12 comments
Open

Increase the maximum stacktrace frame length #1923

brustolin opened this issue Jun 29, 2022 · 12 comments

Comments

@brustolin
Copy link
Contributor

brustolin commented Jun 29, 2022

Description

We are using 100 as a constant to create C arrays of Stacktrace frames.
The App hangs PR #1906 do this in a context that is not possible to allocate more memory.
We already received a few complaints that the Stacktrace is truncated and this may be the cause.

The first idea to improve this is to increase the value, with the obvious downside that we need to pre-allocate more memory every time we need to create the stack trace.

@philipphofmann
Copy link
Member

@Swatinem and @armcknight , can you maybe help us here?

We allocate a struct with a maximum of 100 stack entries before suspending the threads. Here we are walking the stack cursor after suspending the threads. Do you have any recommendations on what to do when the stack has more than 100 entries? Now we ignore this, and the stacktrace would miss a few entries. We can't allocate memory either.

sentrycrashmc_suspendEnvironment(&suspendedThreads, &numSuspendedThreads);
// DANGER: Do not try to allocate memory in the heap or call Objective-C code in this
// section Doing so when the threads are suspended may lead to deadlocks or crashes.
SentryThreadInfo threadsInfos[numSuspendedThreads];
for (int i = 0; i < numSuspendedThreads; i++) {
if (suspendedThreads[i] != currentThread) {
int numberOfEntries = getStackEntriesFromThread(suspendedThreads[i], context,
threadsInfos[i].stackEntries, MAX_STACKTRACE_LENGTH);
threadsInfos[i].stackLength = numberOfEntries;
} else {
// We can't use 'getStackEntriesFromThread' to retrieve stack frames from the
// current thread. We are using the stackTraceBuilder to retrieve this information
// later.
threadsInfos[i].stackLength = 0;
}
threadsInfos[i].thread = suspendedThreads[i];
}
sentrycrashmc_resumeEnvironment(suspendedThreads, numSuspendedThreads);

@Swatinem
Copy link
Member

I can’t think of anything, except increase the maximum length ;-)
We have the same limitations in native, and there we reserve space for 256 frames.

@philipphofmann
Copy link
Member

philipphofmann commented Jun 30, 2022

Thanks, @Swatinem, for your reply. I thought so, but worth a shot. @brustolin, I think we could increase the value to 256 then.

@philipphofmann
Copy link
Member

Do you do anything special when you exceed the maximum, like adding a special entry or making sure you cut from the bottom or top, or do you just ignore it, @Swatinem?

@Swatinem
Copy link
Member

It just truncates at the bottom and stops unwinding when it reaches the limit.

@armcknight
Copy link
Member

armcknight commented Jul 1, 2022

An alternative approach is to not keep the stack trace in memory, and write it out to disk (it can be deserialized back into memory outside of the thread-suspended sector). This is how Crashlytics does it: https://github.com/firebase/firebase-ios-sdk/blob/e2542c7932b0277bb4f5c6a9e0affa7076065481/Crashlytics/Crashlytics/Components/FIRCLSProcess.c#L389

They record a maximum of 600,000 frames on iOS: https://github.com/firebase/firebase-ios-sdk/blob/e2542c7932b0277bb4f5c6a9e0affa7076065481/Crashlytics/Crashlytics/Unwind/FIRCLSUnwind.c#L26-L34

This has an additional bonus that some data is preserved if for whatever reason we are terminated while doing this work. But, it comes at a cost of some additional implementation, and working with fds and write ain't that fun 🙃

@philipphofmann
Copy link
Member

We also write stacktrace to disk when we crash, but this one we use when not crashing. So for App Hangs and in the future when calling captureMessage or captureError. Writing to disk when not crashing is definitely a tradeoff, which might not be worth it.

@brustolin
Copy link
Contributor Author

brustolin commented Jul 13, 2022

Since this is only used for ANR, we are fine with increasing the maximum stack frame size to 256.

@brustolin brustolin moved this from Needs Discussion to Backlog in Mobile & Cross Platform SDK Jul 13, 2022
@philipphofmann
Copy link
Member

For most SentryCrash monitors we use SentryCrashSC_STACK_OVERFLOW_THRESHOLD

#define SentryCrashSC_STACK_OVERFLOW_THRESHOLD 150

and for some others we use MAX_STACKTRACE_LENGTH

We advance the cursor while writing a report to disk in here

writeBacktrace(const SentryCrashReportWriter *const writer, const char *const key,
SentryCrashStackCursor *stackCursor)
{
writer->beginObject(writer, key);
{
writer->beginArray(writer, SentryCrashField_Contents);
{
while (stackCursor->advanceCursor(stackCursor)) {
writer->beginObject(writer, NULL);
{
if (stackCursor->symbolicate(stackCursor)) {
if (stackCursor->stackEntry.imageName != NULL) {
writer->addStringElement(writer, SentryCrashField_ObjectName,
sentrycrashfu_lastPathEntry(stackCursor->stackEntry.imageName));
}
writer->addUIntegerElement(writer, SentryCrashField_ObjectAddr,
stackCursor->stackEntry.imageAddress);
if (stackCursor->stackEntry.symbolName != NULL) {
writer->addStringElement(writer, SentryCrashField_SymbolName,
stackCursor->stackEntry.symbolName);
}
writer->addUIntegerElement(writer, SentryCrashField_SymbolAddr,
stackCursor->stackEntry.symbolAddress);
}
writer->addUIntegerElement(
writer, SentryCrashField_InstructionAddr, stackCursor->stackEntry.address);
}
writer->endContainer(writer);
}
}
writer->endContainer(writer);
writer->addIntegerElement(writer, SentryCrashField_Skipped, 0);
}
writer->endContainer(writer);
}

So I think for hard crashes we could increase the limit easily, but that's not the purpose of this issue. FYI, @armcknight.

@philipphofmann
Copy link
Member

Just to be safe, we could only increase the stacktrace size for App Hangs to avoid possible side effects.

@github-actions
Copy link

github-actions bot commented Aug 4, 2022

This issue has gone three weeks without activity. In another week, I will close it.

But! If you comment or otherwise update it, I will reset the clock, and if you label it Status: Backlog or Status: In Progress, I will leave it alone ... forever!


"A weed is but an unloved flower." ― Ella Wheeler Wilcox 🥀

@github-actions
Copy link

This issue has gone three weeks without activity. In another week, I will close it.

But! If you comment or otherwise update it, I will reset the clock, and if you label it Status: Backlog or Status: In Progress, I will leave it alone ... forever!


"A weed is but an unloved flower." ― Ella Wheeler Wilcox 🥀

@philipphofmann philipphofmann changed the title Validate the maximum Stacktrace frames length Increase the maximum stacktrace frame length Dec 4, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Backlog
Development

No branches or pull requests

6 participants