Skip to content

Commit b7e707e

Browse files
fix(profiling): Prevent crash on iOS when debug images are missing on profiling end (#4738)
1 parent baad1d9 commit b7e707e

File tree

5 files changed

+48
-4
lines changed

5 files changed

+48
-4
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
### Fixes
1212

1313
- Avoid silent failure when JS bundle was not created due to Sentry Xcode scripts failure ([#4690](https://github.com/getsentry/sentry-react-native/pull/4690))
14+
- Prevent crash on iOS during profiling stop when debug images are missing ([#4738](https://github.com/getsentry/sentry-react-native/pull/4738))
1415

1516
### Dependencies
1617

packages/core/src/js/profiling/integration.ts

+1-3
Original file line numberDiff line numberDiff line change
@@ -315,9 +315,7 @@ export function addNativeProfileToHermesProfile(
315315
return {
316316
...hermes,
317317
profile: addNativeThreadCpuProfileToHermes(hermes.profile, native.profile, hermes.transaction.active_thread_id),
318-
debug_meta: {
319-
images: native.debug_meta.images,
320-
},
318+
...(native.debug_meta?.images ? { debug_meta: { images: native.debug_meta.images } } : {}),
321319
measurements: native.measurements,
322320
};
323321
}

packages/core/src/js/profiling/nativeTypes.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ export interface NativeProfileEvent {
3939
unit: string;
4040
}
4141
>;
42-
debug_meta: {
42+
debug_meta?: {
4343
images: {
4444
type: 'macho';
4545
debug_id: string;

packages/core/test/profiling/fixtures.ts

+9
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,15 @@ export function createMockMinimalValidHermesProfileEvent(): HermesProfileEvent {
8080
};
8181
}
8282

83+
/**
84+
* Create a mock native (iOS/Apple) profile.
85+
*/
86+
export function createMockMinimalValidAppleProfileWithoutDebugMeta(): NativeProfileEvent {
87+
const profile = createMockMinimalValidAppleProfile();
88+
delete profile.debug_meta;
89+
return profile;
90+
}
91+
8392
/**
8493
* Create a mock native (iOS/Apple) profile.
8594
*/

packages/core/test/profiling/integration.test.ts

+36
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import { envelopeItemPayload, envelopeItems } from '../testutils';
1717
import {
1818
createMockMinimalValidAndroidProfile,
1919
createMockMinimalValidAppleProfile,
20+
createMockMinimalValidAppleProfileWithoutDebugMeta,
2021
createMockMinimalValidHermesProfile,
2122
} from './fixtures';
2223

@@ -155,6 +156,41 @@ describe('profiling integration', () => {
155156
});
156157

157158
describe('with native profiling', () => {
159+
test('should create a new mixed profile and add it to the transaction envelope with missing debug_meta', () => {
160+
mockWrapper.NATIVE.stopProfiling.mockReturnValue({
161+
hermesProfile: createMockMinimalValidHermesProfile(),
162+
nativeProfile: createMockMinimalValidAppleProfileWithoutDebugMeta(),
163+
});
164+
165+
const transaction = Sentry.startSpan({ name: 'test-name' }, span => span);
166+
167+
jest.runAllTimers();
168+
169+
const envelope: Envelope | undefined = mock.transportSendMock.mock.lastCall?.[0];
170+
expectEnvelopeToContainProfile(envelope, 'test-name', spanToJSON(transaction).trace_id);
171+
// Expect merged profile
172+
expect(getProfileFromEnvelope(envelope)).toEqual(
173+
expect.objectContaining(<Partial<Profile>>{
174+
profile: expect.objectContaining(<Partial<ThreadCpuProfile>>{
175+
frames: [
176+
{
177+
function: '[root]',
178+
in_app: false,
179+
},
180+
{
181+
instruction_addr: '0x0000000000000003',
182+
platform: 'cocoa',
183+
},
184+
{
185+
instruction_addr: '0x0000000000000004',
186+
platform: 'cocoa',
187+
},
188+
],
189+
}),
190+
}),
191+
);
192+
});
193+
158194
test('should create a new mixed profile and add it to the transaction envelope', () => {
159195
mockWrapper.NATIVE.stopProfiling.mockReturnValue({
160196
hermesProfile: createMockMinimalValidHermesProfile(),

0 commit comments

Comments
 (0)