fix: guard role-to-enum casts in models to prevent RangeDefect crashes#21116
fix: guard role-to-enum casts in models to prevent RangeDefect crashes#21116jrainville wants to merge 1 commit into
Conversation
There was a problem hiding this comment.
This one is the main culprit, since the enum starts at UserRole + 1.
It has 37 entries.
So valid values are 257..293 (In Qt/Nim QAbstractItemModel roles, UserRole is typically 256).
The crash popoup says value out of range: 295 notin 257 .. 293, which is an exact match for this enum cast failure.
There was a problem hiding this comment.
Pull request overview
This PR addresses #21085 by hardening Nim/QML QAbstractListModel.data() implementations against RangeDefect crashes when Qt requests an unexpected (out-of-range) role integer and the code casts it directly to an enum.
Changes:
- Added
low(EnumType)..high(EnumType)bounds checks before role-to-enum casts across affected list models. - Ensured out-of-range roles are ignored early (returning an empty/invalid
QVariant) instead of raising exceptions. - Added a clarifying comment in
section_model.nimexplaining the Qt/proxy lifecycle motivation for ignoring unknown roles.
Reviewed changes
Copilot reviewed 69 out of 69 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| src/app/modules/main/activity_center/model.nim | Guard NotifRoles role-to-enum casting in data() |
| src/app/modules/main/app_search/models/chat_search_model.nim | Guard ModelRole role-to-enum casting in data() |
| src/app/modules/main/app_search/models/location_menu_model.nim | Guard ModelRole role-to-enum casting in data() |
| src/app/modules/main/app_search/models/location_menu_sub_model.nim | Guard SubModelRole role-to-enum casting in data() |
| src/app/modules/main/app_search/models/result_model.nim | Guard ModelRole role-to-enum casting in data() |
| src/app/modules/main/browser_section/bookmark/model.nim | Guard ModelRole role-to-enum casting in data() |
| src/app/modules/main/browser_section/dapps/accounts.nim | Guard ModelRole role-to-enum casting in data() |
| src/app/modules/main/browser_section/dapps/dapps.nim | Guard ModelRole role-to-enum casting in data() |
| src/app/modules/main/chat_section/chat_content/input_area/urls_model.nim | Guard ModelRole role-to-enum casting in data() |
| src/app/modules/main/chat_section/model.nim | Guard ModelRole role-to-enum casting in data() |
| src/app/modules/main/communities/models/curated_community_model.nim | Guard ModelRole role-to-enum casting in data() |
| src/app/modules/main/communities/models/discord_categories_model.nim | Guard ModelRole role-to-enum casting in data() |
| src/app/modules/main/communities/models/discord_channels_model.nim | Guard ModelRole role-to-enum casting in data() |
| src/app/modules/main/communities/models/discord_file_list_model.nim | Guard ModelRole role-to-enum casting in data() |
| src/app/modules/main/communities/models/discord_import_errors_model.nim | Guard ModelRole role-to-enum casting in data() |
| src/app/modules/main/communities/models/discord_import_tasks_model.nim | Guard ModelRole role-to-enum casting in data() |
| src/app/modules/main/communities/tokens/models/token_model.nim | Guard ModelRole role-to-enum casting in data() |
| src/app/modules/main/communities/tokens/models/token_owners_model.nim | Guard ModelRole role-to-enum casting in data() |
| src/app/modules/main/ephemeral_notification_model.nim | Guard ModelRole role-to-enum casting in data() |
| src/app/modules/main/market_section/market_leaderboard_model.nim | Guard ModelRole role-to-enum casting in data() |
| src/app/modules/main/profile_section/contacts/models/showcase_contact_accounts_model.nim | Guard ModelRole role-to-enum casting in data() |
| src/app/modules/main/profile_section/contacts/models/showcase_contact_generic_model.nim | Guard ModelRole role-to-enum casting in data() |
| src/app/modules/main/profile_section/contacts/models/showcase_contact_social_links_model.nim | Guard ModelRole role-to-enum casting in data() |
| src/app/modules/main/profile_section/devices/model.nim | Guard ModelRole role-to-enum casting in data() |
| src/app/modules/main/profile_section/ens_usernames/model.nim | Guard ModelRole role-to-enum casting in data() |
| src/app/modules/main/profile_section/notifications/model.nim | Guard ModelRole role-to-enum casting in data() |
| src/app/modules/main/profile_section/profile/models/showcase_preferences_generic_model.nim | Guard ModelRole role-to-enum casting in data() |
| src/app/modules/main/profile_section/profile/models/showcase_preferences_social_links_model.nim | Guard ModelRole role-to-enum casting in data() |
| src/app/modules/main/profile_section/sync/model.nim | Guard ModelRole role-to-enum casting in data() |
| src/app/modules/main/profile_section/wallet/accounts/model.nim | Guard ModelRole role-to-enum casting in data() |
| src/app/modules/main/stickers/models/sticker_list.nim | Guard StickerRoles role-to-enum casting in data() |
| src/app/modules/main/stickers/models/sticker_pack_list.nim | Guard StickerPackRoles role-to-enum casting in data() |
| src/app/modules/main/wallet_section/accounts/model.nim | Guard ModelRole role-to-enum casting in data() |
| src/app/modules/main/wallet_section/activity/collectibles_model.nim | Guard CollectibleRole role-to-enum casting in data() |
| src/app/modules/main/wallet_section/activity/model.nim | Guard ModelRole role-to-enum casting in data() |
| src/app/modules/main/wallet_section/activity/recipients_model.nim | Guard ModelRole role-to-enum casting in data() |
| src/app/modules/main/wallet_section/all_tokens/token_groups_model.nim | Guard ModelRole role-to-enum casting in data() |
| src/app/modules/main/wallet_section/all_tokens/token_lists_model.nim | Guard ModelRole role-to-enum casting in data() |
| src/app/modules/main/wallet_section/all_tokens/tokens_model.nim | Guard ModelRole role-to-enum casting in data() |
| src/app/modules/main/wallet_section/assets/balances_model.nim | Guard ModelRole role-to-enum casting in data() |
| src/app/modules/main/wallet_section/assets/grouped_account_assets_model.nim | Guard ModelRole role-to-enum casting in data() |
| src/app/modules/main/wallet_section/buy_sell_crypto/model.nim | Guard ModelRole role-to-enum casting in data() |
| src/app/modules/main/wallet_section/following_addresses/model.nim | Guard ModelRole role-to-enum casting in data() |
| src/app/modules/main/wallet_section/networks/model.nim | Guard ModelRole role-to-enum casting in data() |
| src/app/modules/main/wallet_section/networks/rpc_providers_model.nim | Guard ModelRole role-to-enum casting in data() |
| src/app/modules/main/wallet_section/saved_addresses/model.nim | Guard ModelRole role-to-enum casting in data() |
| src/app/modules/main/wallet_section/send/network_route_model.nim | Guard ModelRole role-to-enum casting in data() |
| src/app/modules/main/wallet_section/send/suggested_route_model.nim | Guard ModelRole role-to-enum casting in data() |
| src/app/modules/main/wallet_section/send_new/path_model.nim | Guard ModelRole role-to-enum casting in data() |
| src/app/modules/onboarding/models/login_account_model.nim | Guard ModelRole role-to-enum casting in data() |
| src/app/modules/shared_models/collectible_ownership_model.nim | Guard ModelRole role-to-enum casting in data() |
| src/app/modules/shared_models/collectible_trait_model.nim | Guard ModelRole role-to-enum casting in data() |
| src/app/modules/shared_models/collectibles_model.nim | Guard CollectibleRole role-to-enum casting in data() |
| src/app/modules/shared_models/contract_model.nim | Guard ModelRole role-to-enum casting in data() |
| src/app/modules/shared_models/derived_address_model.nim | Guard ModelRole role-to-enum casting in data() |
| src/app/modules/shared_models/keypair_account_model.nim | Guard ModelRole role-to-enum casting in data() |
| src/app/modules/shared_models/keypair_model.nim | Guard ModelRole role-to-enum casting in data() |
| src/app/modules/shared_models/link_preview_model.nim | Guard ModelRole role-to-enum casting in data() |
| src/app/modules/shared_models/member_model.nim | Guard ModelRole role-to-enum casting in data() |
| src/app/modules/shared_models/message_model.nim | Guard ModelRole role-to-enum casting in data() |
| src/app/modules/shared_models/message_reaction_model.nim | Guard ModelRole role-to-enum casting in data() |
| src/app/modules/shared_models/payment_request_model.nim | Guard ModelRole role-to-enum casting in data() |
| src/app/modules/shared_models/section_model.nim | Guard ModelRole role-to-enum casting in data() (with explanatory comment) |
| src/app/modules/shared_models/token_criteria_model.nim | Guard ModelRole role-to-enum casting in data() |
| src/app/modules/shared_models/token_list_model.nim | Guard ModelRole role-to-enum casting in data() |
| src/app/modules/shared_models/token_permission_chat_list_model.nim | Guard ModelRole role-to-enum casting in data() |
| src/app/modules/shared_models/token_permissions_model.nim | Guard ModelRole role-to-enum casting in data() |
| src/app/modules/shared_models/user_model.nim | Guard ModelRole role-to-enum casting in data() |
| src/app/modules/shared_modules/keycard_popup/models/keycard_model.nim | Guard ModelRole role-to-enum casting in data() |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Jenkins BuildsClick to see older builds (5)
|
Fixes #21085 Add defensive bounds checks before converting Qt role integers to Nim enum roles across list-model data methods. Return early when role is outside low(EnumRole)..high(EnumRole) Prevent RangeDefect from bubbling through Qt event handlers during model/delegate lifecycle and tab switches Apply the same protection pattern consistently across main, shared, onboarding, and keycard popup models Includes the SectionModel hotspot and all other detected role-to-enum cast sites
c89ca23 to
83b4893
Compare
caybro
left a comment
There was a problem hiding this comment.
Great, I'd just extract the repeating function into some global one like:
proc checkModelIndex(enum: any, role: int): bool|
Or, just wrap and expose |
What does the PR do
Fixes #21085
Summary
This PR hardens QML list-model role handling to prevent crashes caused by out-of-range role-to-enum conversions.
The crash signature reported was a Nim RangeDefect:
This was consistent with enum casting in model data methods when Qt requested an unexpected role during view/model lifecycle transitions.
Root Cause
Several model data methods converted an incoming integer role directly to an enum type without validating bounds first, for example:
When role fell outside low(EnumType)..high(EnumType), Nim raised RangeDefect, which propagated through Qt event handling and triggered app shutdown.
What Changed
Added defensive guards before all detected role-to-enum casts in the touched module scope:
This keeps behavior unchanged for valid roles and safely ignores unknown/out-of-range roles.
Scope
Key hotspot addressed
Also covered
Why This Is Safe
Validation
Testing
Risk
Low