From 4e788aa2f5e8768eddad109d9cdc838c4c3dde11 Mon Sep 17 00:00:00 2001 From: matejcik Date: Mon, 17 Jun 2024 10:44:54 +0200 Subject: [PATCH] fix(core/rust): more careful management of ShortString capacity --- core/embed/rust/src/ui/component/text/common.rs | 10 +++++----- .../ui/model_mercury/component/keyboard/bip39.rs | 4 ++-- .../component/keyboard/passphrase.rs | 2 +- .../ui/model_mercury/component/keyboard/pin.rs | 3 +-- .../ui/model_mercury/component/keyboard/slip39.rs | 6 ++---- .../component/input_methods/passphrase.rs | 15 +++++++++------ .../ui/model_tr/component/input_methods/pin.rs | 13 ++++++++----- .../model_tr/component/input_methods/wordlist.rs | 6 +++--- .../src/ui/model_tt/component/keyboard/bip39.rs | 4 ++-- .../ui/model_tt/component/keyboard/passphrase.rs | 2 +- .../src/ui/model_tt/component/keyboard/pin.rs | 7 ++++--- .../src/ui/model_tt/component/keyboard/slip39.rs | 7 +++---- core/embed/rust/src/ui/util.rs | 9 +++------ 13 files changed, 44 insertions(+), 44 deletions(-) diff --git a/core/embed/rust/src/ui/component/text/common.rs b/core/embed/rust/src/ui/component/text/common.rs index 19ea2a54d8..34d5015cd5 100644 --- a/core/embed/rust/src/ui/component/text/common.rs +++ b/core/embed/rust/src/ui/component/text/common.rs @@ -2,7 +2,6 @@ use crate::{ strutil::ShortString, ui::{component::EventCtx, util::ResultExt}, }; -use heapless::String; /// Reified editing operations of `TextBox`. /// @@ -22,14 +21,15 @@ pub struct TextBox { impl TextBox { /// Create a new `TextBox` with content `text`. - pub fn new(text: &str) -> Self { - let text = unwrap!(String::try_from(text)); + pub fn new(text: &str, max_len: usize) -> Self { + let text = unwrap!(ShortString::try_from(text)); + debug_assert!(text.capacity() >= max_len); Self { text } } /// Create an empty `TextBox`. - pub fn empty() -> Self { - Self::new("") + pub fn empty(max_len: usize) -> Self { + Self::new("", max_len) } pub fn content(&self) -> &str { diff --git a/core/embed/rust/src/ui/model_mercury/component/keyboard/bip39.rs b/core/embed/rust/src/ui/model_mercury/component/keyboard/bip39.rs index a26604f177..f7519a52ce 100644 --- a/core/embed/rust/src/ui/model_mercury/component/keyboard/bip39.rs +++ b/core/embed/rust/src/ui/model_mercury/component/keyboard/bip39.rs @@ -176,7 +176,7 @@ impl Bip39Input { pub fn new() -> Self { Self { button: Button::empty(), - textbox: TextBox::empty(), + textbox: TextBox::empty(MAX_LENGTH), multi_tap: MultiTapKeyboard::new(), options_num: None, suggested_word: None, @@ -193,7 +193,7 @@ impl Bip39Input { // Styling the input to reflect already filled word Self { button: Button::empty().styled(theme::button_recovery_confirm()), - textbox: TextBox::new(word), + textbox: TextBox::new(word, MAX_LENGTH), multi_tap: MultiTapKeyboard::new(), options_num: bip39::options_num(word), suggested_word: bip39::complete_word(word), diff --git a/core/embed/rust/src/ui/model_mercury/component/keyboard/passphrase.rs b/core/embed/rust/src/ui/model_mercury/component/keyboard/passphrase.rs index abe8454bbc..1fc88cb8a9 100644 --- a/core/embed/rust/src/ui/model_mercury/component/keyboard/passphrase.rs +++ b/core/embed/rust/src/ui/model_mercury/component/keyboard/passphrase.rs @@ -414,7 +414,7 @@ impl Input { fn new() -> Self { Self { area: Rect::zero(), - textbox: TextBox::empty(), + textbox: TextBox::empty(MAX_LENGTH), multi_tap: MultiTapKeyboard::new(), } } diff --git a/core/embed/rust/src/ui/model_mercury/component/keyboard/pin.rs b/core/embed/rust/src/ui/model_mercury/component/keyboard/pin.rs index b82d56b0d3..da99c7c3c9 100644 --- a/core/embed/rust/src/ui/model_mercury/component/keyboard/pin.rs +++ b/core/embed/rust/src/ui/model_mercury/component/keyboard/pin.rs @@ -1,5 +1,4 @@ use core::mem; -use heapless::String; use crate::{ strutil::{ShortString, TString}, @@ -294,7 +293,7 @@ impl PinDots { area: Rect::zero(), pad: Pad::with_background(style.background_color), style, - digits: String::new(), + digits: ShortString::new(), display_digits: false, } } diff --git a/core/embed/rust/src/ui/model_mercury/component/keyboard/slip39.rs b/core/embed/rust/src/ui/model_mercury/component/keyboard/slip39.rs index a854f336f1..614470444b 100644 --- a/core/embed/rust/src/ui/model_mercury/component/keyboard/slip39.rs +++ b/core/embed/rust/src/ui/model_mercury/component/keyboard/slip39.rs @@ -1,7 +1,5 @@ use core::iter; -use heapless::String; - use crate::{ strutil::ShortString, trezorhal::slip39, @@ -204,7 +202,7 @@ impl Slip39Input { Self { // Button has the same style the whole time button: Button::empty().styled(theme::button_recovery_confirm()), - textbox: TextBox::empty(), + textbox: TextBox::empty(MAX_LENGTH), multi_tap: MultiTapKeyboard::new(), final_word: None, input_mask: Slip39Mask::full(), @@ -222,7 +220,7 @@ impl Slip39Input { Self { // Button has the same style the whole time button: Button::empty().styled(theme::button_recovery_confirm()), - textbox: TextBox::new(&buff), + textbox: TextBox::new(&buff, MAX_LENGTH), multi_tap: MultiTapKeyboard::new(), final_word, input_mask, diff --git a/core/embed/rust/src/ui/model_tr/component/input_methods/passphrase.rs b/core/embed/rust/src/ui/model_tr/component/input_methods/passphrase.rs index f71d30878e..9fb05a2b5a 100644 --- a/core/embed/rust/src/ui/model_tr/component/input_methods/passphrase.rs +++ b/core/embed/rust/src/ui/model_tr/component/input_methods/passphrase.rs @@ -11,8 +11,6 @@ use crate::{ }, }; -use heapless::String; - use super::super::{ theme, ButtonDetails, ButtonLayout, CancelConfirmMsg, ChangingTextLine, ChoiceFactory, ChoiceItem, ChoicePage, @@ -286,19 +284,24 @@ impl PassphraseEntry { passphrase_dots: Child::new(ChangingTextLine::center_mono("", MAX_PASSPHRASE_LENGTH)), show_plain_passphrase: false, show_last_digit: false, - textbox: TextBox::empty(), + textbox: TextBox::empty(MAX_PASSPHRASE_LENGTH), current_category: ChoiceCategory::Menu, } } fn update_passphrase_dots(&mut self, ctx: &mut EventCtx) { + debug_assert!({ + let s = ShortString::new(); + s.capacity() >= MAX_PASSPHRASE_LENGTH + }); + let text_to_show = if self.show_plain_passphrase { - unwrap!(String::try_from(self.passphrase())) + unwrap!(ShortString::try_from(self.passphrase())) } else if self.is_empty() { - unwrap!(String::try_from("")) + unwrap!(ShortString::try_from("")) } else { // Showing asterisks and possibly the last digit. - let mut dots: ShortString = String::new(); + let mut dots = ShortString::new(); for _ in 0..self.textbox.len() - 1 { unwrap!(dots.push('*')); } diff --git a/core/embed/rust/src/ui/model_tr/component/input_methods/pin.rs b/core/embed/rust/src/ui/model_tr/component/input_methods/pin.rs index 63d7ecce7e..ab2de7be0e 100644 --- a/core/embed/rust/src/ui/model_tr/component/input_methods/pin.rs +++ b/core/embed/rust/src/ui/model_tr/component/input_methods/pin.rs @@ -14,7 +14,6 @@ use super::super::{ theme, ButtonDetails, ButtonLayout, CancelConfirmMsg, ChangingTextLine, ChoiceFactory, ChoiceItem, ChoicePage, }; -use heapless::String; #[derive(Clone, Copy)] enum PinAction { @@ -179,7 +178,7 @@ impl<'a> PinEntry<'a> { showing_real_prompt, show_real_pin: false, show_last_digit: false, - textbox: TextBox::empty(), + textbox: TextBox::empty(MAX_PIN_LENGTH), } } @@ -192,15 +191,19 @@ impl<'a> PinEntry<'a> { /// Show updated content in the changing line. /// Many possibilities, according to the PIN state. fn update_pin_line(&mut self, ctx: &mut EventCtx) { + debug_assert!({ + let s = ShortString::new(); + s.capacity() >= MAX_PIN_LENGTH + }); let mut used_font = Font::BOLD; let pin_line_text = if self.is_empty() && !self.subprompt.is_empty() { // Showing the subprompt in NORMAL font used_font = Font::NORMAL; - self.subprompt.map(|s| unwrap!(String::try_from(s))) + self.subprompt.map(|s| unwrap!(ShortString::try_from(s))) } else if self.is_empty() { - unwrap!(String::try_from(EMPTY_PIN_STR)) + unwrap!(ShortString::try_from(EMPTY_PIN_STR)) } else if self.show_real_pin { - unwrap!(String::try_from(self.pin())) + unwrap!(ShortString::try_from(self.pin())) } else { // Showing asterisks and possibly the last digit. let mut dots = ShortString::new(); diff --git a/core/embed/rust/src/ui/model_tr/component/input_methods/wordlist.rs b/core/embed/rust/src/ui/model_tr/component/input_methods/wordlist.rs index 50f13c325d..df622a01d5 100644 --- a/core/embed/rust/src/ui/model_tr/component/input_methods/wordlist.rs +++ b/core/embed/rust/src/ui/model_tr/component/input_methods/wordlist.rs @@ -10,7 +10,7 @@ use crate::{ }; use super::super::{theme, ButtonLayout, ChangingTextLine, ChoiceFactory, ChoiceItem, ChoicePage}; -use heapless::{String, Vec}; +use heapless::Vec; enum WordlistAction { Letter(char), @@ -176,7 +176,7 @@ impl WordlistEntry { .with_carousel(true) .with_initial_page_counter(get_random_position(choices_count)), chosen_letters: Child::new(ChangingTextLine::center_mono(PROMPT, LINE_CAPACITY)), - textbox: TextBox::empty(), + textbox: TextBox::empty(MAX_WORD_LENGTH), offer_words: false, wordlist_type, can_go_back, @@ -196,7 +196,7 @@ impl WordlistEntry { .with_incomplete(true) .with_initial_page_counter(1), chosen_letters: Child::new(ChangingTextLine::center_mono(word, LINE_CAPACITY)), - textbox: TextBox::new(word), + textbox: TextBox::new(word, MAX_WORD_LENGTH), offer_words: false, wordlist_type, can_go_back, diff --git a/core/embed/rust/src/ui/model_tt/component/keyboard/bip39.rs b/core/embed/rust/src/ui/model_tt/component/keyboard/bip39.rs index f3efc15515..850fb01948 100644 --- a/core/embed/rust/src/ui/model_tt/component/keyboard/bip39.rs +++ b/core/embed/rust/src/ui/model_tt/component/keyboard/bip39.rs @@ -210,7 +210,7 @@ impl Bip39Input { pub fn new() -> Self { Self { button: Button::empty(), - textbox: TextBox::empty(), + textbox: TextBox::empty(MAX_LENGTH), multi_tap: MultiTapKeyboard::new(), options_num: None, suggested_word: None, @@ -227,7 +227,7 @@ impl Bip39Input { // Styling the input to reflect already filled word Self { button: Button::with_icon(theme::ICON_LIST_CHECK).styled(theme::button_pin_confirm()), - textbox: TextBox::new(word), + textbox: TextBox::new(word, MAX_LENGTH), multi_tap: MultiTapKeyboard::new(), options_num: bip39::options_num(word), suggested_word: bip39::complete_word(word), diff --git a/core/embed/rust/src/ui/model_tt/component/keyboard/passphrase.rs b/core/embed/rust/src/ui/model_tt/component/keyboard/passphrase.rs index 9b652fe060..6482cc6aa7 100644 --- a/core/embed/rust/src/ui/model_tt/component/keyboard/passphrase.rs +++ b/core/embed/rust/src/ui/model_tt/component/keyboard/passphrase.rs @@ -337,7 +337,7 @@ impl Input { fn new() -> Self { Self { area: Rect::zero(), - textbox: TextBox::empty(), + textbox: TextBox::empty(MAX_LENGTH), multi_tap: MultiTapKeyboard::new(), } } diff --git a/core/embed/rust/src/ui/model_tt/component/keyboard/pin.rs b/core/embed/rust/src/ui/model_tt/component/keyboard/pin.rs index 582a6c70cc..819d51f968 100644 --- a/core/embed/rust/src/ui/model_tt/component/keyboard/pin.rs +++ b/core/embed/rust/src/ui/model_tt/component/keyboard/pin.rs @@ -1,5 +1,4 @@ -use core::{char::MAX, mem}; -use heapless::String; +use core::mem; use crate::{ strutil::{ShortString, TString}, @@ -316,11 +315,13 @@ impl PinDots { const TWITCH: i16 = 4; fn new(style: TextStyle) -> Self { + let digits = ShortString::new(); + debug_assert!(digits.capacity() >= MAX_LENGTH); Self { area: Rect::zero(), pad: Pad::with_background(style.background_color), style, - digits: String::new(), + digits, display_digits: false, } } diff --git a/core/embed/rust/src/ui/model_tt/component/keyboard/slip39.rs b/core/embed/rust/src/ui/model_tt/component/keyboard/slip39.rs index 1b7d909b3e..866f481d45 100644 --- a/core/embed/rust/src/ui/model_tt/component/keyboard/slip39.rs +++ b/core/embed/rust/src/ui/model_tt/component/keyboard/slip39.rs @@ -1,7 +1,5 @@ use core::iter; -use heapless::String; - use crate::{ strutil::ShortString, trezorhal::slip39, @@ -263,7 +261,7 @@ impl Slip39Input { Self { // Button has the same style the whole time button: Button::empty().styled(theme::button_pin_confirm()), - textbox: TextBox::empty(), + textbox: TextBox::empty(MAX_LENGTH), multi_tap: MultiTapKeyboard::new(), final_word: None, input_mask: Slip39Mask::full(), @@ -281,7 +279,7 @@ impl Slip39Input { Self { // Button has the same style the whole time button: Button::empty().styled(theme::button_pin_confirm()), - textbox: TextBox::new(&buff), + textbox: TextBox::new(&buff, MAX_LENGTH), multi_tap: MultiTapKeyboard::new(), final_word, input_mask, @@ -290,6 +288,7 @@ impl Slip39Input { fn setup_from_prefilled_word(word: &str) -> (ShortString, Slip39Mask, Option<&'static str>) { let mut buff = ShortString::new(); + debug_assert!(buff.capacity() >= MAX_LENGTH); // Gradually appending encoded key digits to the buffer and checking if // have not already formed a final word. diff --git a/core/embed/rust/src/ui/util.rs b/core/embed/rust/src/ui/util.rs index dddf059dc7..c330eee000 100644 --- a/core/embed/rust/src/ui/util.rs +++ b/core/embed/rust/src/ui/util.rs @@ -9,8 +9,6 @@ use crate::{ }, }; -use heapless::String; - use super::display::Font; pub trait ResultExt { @@ -129,7 +127,7 @@ pub fn icon_text_center( /// Convert char to a ShortString. pub fn char_to_string(ch: char) -> ShortString { - let mut s = String::new(); + let mut s = ShortString::new(); unwrap!(s.push(ch)); s } @@ -137,8 +135,7 @@ pub fn char_to_string(ch: char) -> ShortString { /// Returns text to be fit on one line of a given length. /// When the text is too long to fit, it is truncated with ellipsis /// on the left side. -/// Hardcoding 50 (via ShortString) as the length of the returned String - -/// there should not be any lines as long as this. +/// This assumes no lines are longer than 50 chars (ShortString limit) pub fn long_line_content_with_ellipsis( text: &str, ellipsis: &str, @@ -146,7 +143,7 @@ pub fn long_line_content_with_ellipsis( available_width: i16, ) -> ShortString { if text_font.text_width(text) <= available_width { - unwrap!(String::try_from(text)) // whole text can fit + unwrap!(ShortString::try_from(text)) // whole text can fit } else { // Text is longer, showing its right end with ellipsis at the beginning. // Finding out how many additional text characters will fit in,