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:
parent
7a5407982f
commit
7b53ca5309
2 changed files with 23 additions and 17 deletions
|
@ -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();
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue