Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

- Fixes warnings about minimum OS version being lower than Xcode supported version (#5591)
- Fix rendering method for fast view rendering (#6360)
- Fix crashed thread may not be included if there are more than 100 treads (#6377)

### Improvements

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,24 @@ getThreadList(SentryCrashMachineContext *context)
"Thread count %d is higher than maximum of %d", threadCount, maxThreadCount);
threadCount = maxThreadCount;
}

// Make sure we always include the crashed thread
const thread_t crashedThread = context->thisThread;
bool isCrashedThreadInList = false;
for (int i = 0; i < threadCount; i++) {
context->allThreads[i] = threads[i];
thread_t thread = threads[i];
context->allThreads[i] = thread;
if (thread == crashedThread) {
isCrashedThreadInList = true;
}
}
if (threadCount > 0 && !isCrashedThreadInList) {
// If the crashed thread isn't in our list put it in the last entry.
context->allThreads[threadCount - 1] = crashedThread;
}
context->threadCount = threadCount;

// Deallocate ALL mach ports and memory
for (mach_msg_type_number_t i = 0; i < actualThreadCount; i++) {
mach_port_deallocate(thisTask, threads[i]);
}
Expand Down
71 changes: 71 additions & 0 deletions Tests/SentryTests/SentryCrash/SentryCrashMachineContextTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -131,4 +131,75 @@ - (void)testGetContextForThread_WithManyThreads
[self waitForExpectations:finishExpectations timeout:10];
}

- (void)testGetContextForThread_WithMoreThan100Threads_IncludesCrashedThread
{
NSInteger numberOfThreads = SENTRY_CRASH_MAX_THREADS + 1;
NSMutableArray<TestThread *> *threads = [NSMutableArray arrayWithCapacity:numberOfThreads];
NSMutableArray<XCTestExpectation *> *expectations =
[NSMutableArray arrayWithCapacity:numberOfThreads];

for (int i = 0; i < numberOfThreads; i++) {
NSObject *notificationObject = [[NSObject alloc] init];
TestThread *thread = [[TestThread alloc] init];
thread.notificationObject = notificationObject;

XCTestExpectation *exp =
[self expectationWithDescription:[NSString stringWithFormat:@"thread %d started", i]];
[expectations addObject:exp];

[NSNotificationCenter.defaultCenter
addObserverForName:@"io.sentry.test.TestThread.main"
object:notificationObject
queue:nil
usingBlock:^(NSNotification *_Nonnull __unused notification) {
[NSNotificationCenter.defaultCenter
removeObserver:self
name:@"io.sentry.test.TestThread.main"
object:notificationObject];
[exp fulfill];
}];

[threads addObject:thread];
[thread start];
}

[self waitForExpectations:expectations timeout:2];

// Suspend the first thread and get its context
TestThread *crashedThread = threads[SENTRY_CRASH_MAX_THREADS];
kern_return_t kr = thread_suspend(crashedThread.thread);
XCTAssertTrue(kr == KERN_SUCCESS, @"Thread suspension failed");

// Get context for the crashed thread
SentryCrashMC_NEW_CONTEXT(machineContext);
bool result = sentrycrashmc_getContextForThread(crashedThread.thread, machineContext, YES);

XCTAssertTrue(result, @"Failed to get context for thread");

// Verify that thread list includes all our test threads
int threadCount = sentrycrashmc_getThreadCount(machineContext);
XCTAssertTrue(
threadCount >= 10, @"Thread count should include all test threads, got %d", threadCount);
XCTAssertTrue(threadCount <= SENTRY_CRASH_MAX_THREADS,
@"Thread count should not exceed maximum of SENTRY_CRASH_MAX_THREADS, got %d", threadCount);

// Verify that our crashed thread is in the list
int threadIndex = sentrycrashmc_indexOfThread(machineContext, crashedThread.thread);
XCTAssertTrue(threadIndex >= 0, @"Thread should be found in the list");

// Clean up
thread_resume(crashedThread.thread);
NSMutableArray<XCTestExpectation *> *finishExpectations =
[NSMutableArray arrayWithCapacity:threads.count];
for (TestThread *thread in threads) {
thread.endExpectation =
[[XCTestExpectation alloc] initWithDescription:@"Wait for thread to cancel"];
[finishExpectations addObject:thread.endExpectation];
[thread cancel];
}

// Wait for all threads to finish (up to 10 seconds)
[self waitForExpectations:finishExpectations timeout:10];
}

@end
Loading