From 0c2f512a9c2a98d00046ede2e1e665cd6e38052e Mon Sep 17 00:00:00 2001 From: fatadel Date: Wed, 18 Feb 2026 14:49:51 +0100 Subject: [PATCH 1/3] fix crash when nativeSymbol index is out of bounds in assembly view --- src/selectors/url-state.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/selectors/url-state.ts b/src/selectors/url-state.ts index 3045882da5..a584925126 100644 --- a/src/selectors/url-state.ts +++ b/src/selectors/url-state.ts @@ -88,7 +88,7 @@ export const getAssemblyViewNativeSymbol: Selector = ( const { nativeSymbols, currentNativeSymbol } = getProfileSpecificState(state).assemblyView; return currentNativeSymbol !== null - ? nativeSymbols[currentNativeSymbol] + ? (nativeSymbols[currentNativeSymbol] ?? null) : null; }; export const getAssemblyViewCurrentNativeSymbolEntryIndex: Selector< From 109f4256a8b24c60edab252911578f18cecdb62e Mon Sep 17 00:00:00 2001 From: fatadel Date: Wed, 18 Feb 2026 15:09:58 +0100 Subject: [PATCH 2/3] add test --- src/test/store/bottom-box.test.ts | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/test/store/bottom-box.test.ts b/src/test/store/bottom-box.test.ts index f410ee3a3c..32a6e1c1a4 100644 --- a/src/test/store/bottom-box.test.ts +++ b/src/test/store/bottom-box.test.ts @@ -345,6 +345,29 @@ describe('bottom box', function () { ).toBeOneOf([0x40, 0x45]); }); + it('returns null for getAssemblyViewNativeSymbol when nativeSymbols is empty but initialNativeSymbol is 0', function () { + // initialNativeSymbol = 0, even when nativeSymbols is empty + // (e.g., when the frame has no native symbol). + // The selector must return null (not undefined) + // to avoid a crash when downstream code accesses .libIndex on it. + const { dispatch, getState } = setup(); + + dispatch( + updateBottomBoxContentsAndMaybeOpen('calltree', { + libIndex: null, + sourceIndex: null, + nativeSymbols: [], + initialNativeSymbol: 0, + highlightedLineNumber: null, + highlightedInstructionAddress: null, + }) + ); + + expect( + UrlStateSelectors.getAssemblyViewNativeSymbol(getState()) + ).toBeNull(); + }); + // Further ideas for tests: // // - A test with multiple threads: Open the assembly view for a symbol, switch From e09282ca25238fb796463a800c6f5526e8b6412c Mon Sep 17 00:00:00 2001 From: fatadel Date: Wed, 18 Feb 2026 15:37:02 +0100 Subject: [PATCH 3/3] incorporate feedback --- src/reducers/url-state.ts | 11 ++++++++++- src/selectors/url-state.ts | 2 +- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/reducers/url-state.ts b/src/reducers/url-state.ts index 8903ea34b2..d307ce0b6e 100644 --- a/src/reducers/url-state.ts +++ b/src/reducers/url-state.ts @@ -606,12 +606,21 @@ const assemblyView: Reducer = ( const { nativeSymbols, currentNativeSymbol, shouldOpenAssemblyView } = action; const shouldScroll = action.scrollToInstructionAddress !== undefined; + + // Clamp currentNativeSymbol to null if it is out of bounds, so that + // "currentNativeSymbol is always in-bounds or null" holds. + const clampedNativeSymbol = + currentNativeSymbol !== null && + currentNativeSymbol < nativeSymbols.length + ? currentNativeSymbol + : null; + return { scrollGeneration: shouldScroll ? state.scrollGeneration + 1 : state.scrollGeneration, nativeSymbols, - currentNativeSymbol, + currentNativeSymbol: clampedNativeSymbol, isOpen: state.isOpen || shouldOpenAssemblyView, scrollToInstructionAddress: action.scrollToInstructionAddress, highlightedInstruction: action.highlightedInstructionAddress, diff --git a/src/selectors/url-state.ts b/src/selectors/url-state.ts index a584925126..3045882da5 100644 --- a/src/selectors/url-state.ts +++ b/src/selectors/url-state.ts @@ -88,7 +88,7 @@ export const getAssemblyViewNativeSymbol: Selector = ( const { nativeSymbols, currentNativeSymbol } = getProfileSpecificState(state).assemblyView; return currentNativeSymbol !== null - ? (nativeSymbols[currentNativeSymbol] ?? null) + ? nativeSymbols[currentNativeSymbol] : null; }; export const getAssemblyViewCurrentNativeSymbolEntryIndex: Selector<