Skip to content

Commit d61b289

Browse files
Tranceveralwx
andauthored
fix(core): preserve Hermes internal bytecode frames in Expo (#6848)
* fix(core): preserve Hermes internal bytecode frames in Expo * docs(core): link Hermes fix in changelog * Apply suggestion from @Trancever * Apply suggestion from @Trancever --------- Co-authored-by: Alexander <alex@apantiukhov.com>
1 parent c0bc3e1 commit d61b289

3 files changed

Lines changed: 66 additions & 4 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
### Fixes
1717

18+
- Preserve Hermes internal bytecode frames as non-application frames when rewriting Expo stack traces ([#6848](https://github.com/getsentry/sentry-react-native/pull/6848))
1819
- Fix stale `turbo_module.*` tags on Android native crashes ([#6823](https://github.com/getsentry/sentry-react-native/pull/6823))
1920
- Forward image attachments to Spotlight instead of stripping them from the envelope ([#6818](https://github.com/getsentry/sentry-react-native/pull/6818))
2021
- Don't crash the iOS app when Sentry is initialized with an invalid DSN ([#6825](https://github.com/getsentry/sentry-react-native/pull/6825))

‎packages/core/src/js/integrations/rewriteframes.ts‎

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,13 @@ export function createReactNativeRewriteFrames(): Integration {
4646
frame.colno += 1;
4747
}
4848

49+
// Hermes runtime bytecode is separate from the Expo application bundle.
50+
if (frame.filename === 'InternalBytecode.js' || frame.filename === '/InternalBytecode.js') {
51+
frame.in_app = false;
52+
frame.filename = 'app:///InternalBytecode.js';
53+
return frame;
54+
}
55+
4956
// Expo adds hash to the end of bundle names
5057
if (isExpo() && Platform.OS === 'android') {
5158
frame.filename = ANDROID_DEFAULT_BUNDLE_NAME;
@@ -58,10 +65,6 @@ export function createReactNativeRewriteFrames(): Integration {
5865
}
5966

6067
const appPrefix = 'app://';
61-
// https://github.com/getsentry/sentry-react-native/issues/3348
62-
if (frame.filename === '/InternalBytecode.js') {
63-
frame.in_app = false;
64-
}
6568
// We always want to have a triple slash
6669
frame.filename =
6770
frame.filename.indexOf('/') === 0 ? `${appPrefix}${frame.filename}` : `${appPrefix}/${frame.filename}`;

‎packages/core/test/integrations/rewriteframes.test.ts‎

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -865,6 +865,64 @@ describe('RewriteFrames', () => {
865865
});
866866
});
867867

868+
describe.each([
869+
{ platform: 'ios' as const, expo: true, bundle: 'app:///main.jsbundle' },
870+
{ platform: 'android' as const, expo: true, bundle: 'app:///index.android.bundle' },
871+
{ platform: 'ios' as const, expo: false, bundle: 'app:///entry.hbc' },
872+
{ platform: 'android' as const, expo: false, bundle: 'app:///entry.hbc' },
873+
])('Hermes on $platform with Expo=$expo', ({ platform, expo, bundle }) => {
874+
afterEach(() => {
875+
jest.restoreAllMocks();
876+
});
877+
878+
it.each(['InternalBytecode.js', '/InternalBytecode.js', '/build/hermes/lib/InternalBytecode/InternalBytecode.js'])(
879+
'keeps %s frames separate from the application bundle',
880+
async filename => {
881+
mockFunction(isExpo).mockReturnValue(expo);
882+
mockFunction(isHermesEnabled).mockReturnValue(true);
883+
jest.replaceProperty(Platform, 'OS', platform);
884+
885+
const error = {
886+
message: 'Network request failed',
887+
name: 'Error',
888+
stack:
889+
'Error: Network request failed\n' +
890+
' at fetchToken (address at /updates/entry.hbc:1:4344175)\n' +
891+
` at tryCallOne (address at ${filename}:1:1180)\n` +
892+
` at anonymous (address at ${filename}:1:1874)\n` +
893+
' at apply (native)',
894+
};
895+
896+
const exception = await exceptionFromError(error);
897+
898+
expect(exception?.stacktrace?.frames).toEqual([
899+
{ filename: 'native', function: 'apply', in_app: true },
900+
{
901+
filename: 'app:///InternalBytecode.js',
902+
function: 'anonymous',
903+
lineno: 1,
904+
colno: 1875,
905+
in_app: false,
906+
},
907+
{
908+
filename: 'app:///InternalBytecode.js',
909+
function: 'tryCallOne',
910+
lineno: 1,
911+
colno: 1181,
912+
in_app: false,
913+
},
914+
{
915+
filename: bundle,
916+
function: 'fetchToken',
917+
lineno: 1,
918+
colno: 4344176,
919+
in_app: true,
920+
},
921+
]);
922+
},
923+
);
924+
});
925+
868926
it('InternalBytecode should be flaged as not InApp', async () => {
869927
mockFunction(isHermesEnabled).mockReturnValue(true);
870928

0 commit comments

Comments
 (0)