1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 12:37:44 +00:00

Calculator: Use Checked to ensure entered values do not overflow

This replaces the types of m_int_value and m_frac_value with
Checked<u64> which makes it possible to check if the value overflowed
when entering a digit. If that happens, the digit will just be ignored.

This fixes #1263.
This commit is contained in:
Max Wipfli 2021-05-23 21:23:07 +02:00 committed by Linus Groh
parent 7a5407982f
commit 7b53ca5309
2 changed files with 23 additions and 17 deletions

View file

@ -19,6 +19,7 @@ Keypad::~Keypad()
void Keypad::type_digit(int digit) void Keypad::type_digit(int digit)
{ {
u64 previous_value = 0;
switch (m_state) { switch (m_state) {
case State::External: case State::External:
m_state = State::TypingInteger; m_state = State::TypingInteger;
@ -28,17 +29,22 @@ void Keypad::type_digit(int digit)
m_frac_length = 0; m_frac_length = 0;
break; break;
case State::TypingInteger: case State::TypingInteger:
VERIFY(m_frac_value == 0); VERIFY(m_frac_value.value() == 0);
VERIFY(m_frac_length == 0); VERIFY(m_frac_length == 0);
previous_value = m_int_value.value();
m_int_value *= 10; m_int_value *= 10;
m_int_value += digit; m_int_value += digit;
if (m_int_value.has_overflow())
m_int_value = previous_value;
break; break;
case State::TypingDecimal: case State::TypingDecimal:
if (m_frac_length > 6) previous_value = m_frac_value.value();
break;
m_frac_value *= 10; m_frac_value *= 10;
m_frac_value += digit; m_frac_value += digit;
m_frac_length++; if (m_frac_value.has_overflow())
m_frac_value = previous_value;
else
m_frac_length++;
break; break;
} }
} }
@ -53,7 +59,7 @@ void Keypad::type_decimal_point()
m_frac_length = 0; m_frac_length = 0;
break; break;
case State::TypingInteger: case State::TypingInteger:
VERIFY(m_frac_value == 0); VERIFY(m_frac_value.value() == 0);
VERIFY(m_frac_length == 0); VERIFY(m_frac_length == 0);
m_state = State::TypingDecimal; m_state = State::TypingDecimal;
break; break;
@ -78,14 +84,14 @@ void Keypad::type_backspace()
m_frac_length--; m_frac_length--;
break; break;
} }
VERIFY(m_frac_value == 0); VERIFY(m_frac_value.value() == 0);
m_state = State::TypingInteger; m_state = State::TypingInteger;
[[fallthrough]]; [[fallthrough]];
case State::TypingInteger: case State::TypingInteger:
VERIFY(m_frac_value == 0); VERIFY(m_frac_value.value() == 0);
VERIFY(m_frac_length == 0); VERIFY(m_frac_length == 0);
m_int_value /= 10; m_int_value /= 10;
if (m_int_value == 0) if (m_int_value.value() == 0)
m_negative = false; m_negative = false;
break; break;
} }
@ -95,15 +101,15 @@ double Keypad::value() const
{ {
double res = 0.0; double res = 0.0;
long frac = m_frac_value; u64 frac = m_frac_value.value();
for (int i = 0; i < m_frac_length; i++) { for (int i = 0; i < m_frac_length; i++) {
int digit = frac % 10; u8 digit = frac % 10;
res += digit; res += digit;
res /= 10.0; res /= 10.0;
frac /= 10; frac /= 10;
} }
res += m_int_value; res += m_int_value.value();
if (m_negative) if (m_negative)
res = -res; res = -res;
@ -121,7 +127,7 @@ void Keypad::set_value(double value)
m_negative = false; m_negative = false;
m_int_value = value; m_int_value = value;
value -= m_int_value; value -= m_int_value.value();
m_frac_value = 0; m_frac_value = 0;
m_frac_length = 0; m_frac_length = 0;
@ -143,7 +149,7 @@ String Keypad::to_string() const
StringBuilder builder; StringBuilder builder;
if (m_negative) if (m_negative)
builder.append("-"); builder.append("-");
builder.appendff("{}", m_int_value); builder.appendff("{}", m_int_value.value());
// NOTE: This is so the decimal point appears on screen as soon as you type it. // NOTE: This is so the decimal point appears on screen as soon as you type it.
if (m_frac_length > 0 || m_state == State::TypingDecimal) if (m_frac_length > 0 || m_state == State::TypingDecimal)
@ -152,7 +158,7 @@ String Keypad::to_string() const
if (m_frac_length > 0) { if (m_frac_length > 0) {
// FIXME: This disables the compiletime format string check since we can't parse '}}' here correctly. // FIXME: This disables the compiletime format string check since we can't parse '}}' here correctly.
// remove the 'StringView { }' when that's fixed. // remove the 'StringView { }' when that's fixed.
builder.appendff(StringView { "{:0{}}" }, m_frac_value, m_frac_length); builder.appendff(StringView { "{:0{}}" }, m_frac_value.value(), m_frac_length);
} }
return builder.to_string(); return builder.to_string();

View file

@ -30,9 +30,9 @@ public:
private: private:
// Internal representation of the current decimal value. // Internal representation of the current decimal value.
bool m_negative { false }; bool m_negative { false };
long m_int_value { 0 }; Checked<u64> m_int_value { 0 };
long m_frac_value { 0 }; Checked<u64> m_frac_value { 0 };
int m_frac_length { 0 }; u8 m_frac_length { 0 };
// E.g. for -35.004200, // E.g. for -35.004200,
// m_negative = true // m_negative = true
// m_int_value = 35 // m_int_value = 35