diff --git a/lib/mathlib.cpp b/lib/mathlib.cpp index 403662f4df2..c7c055899fd 100644 --- a/lib/mathlib.cpp +++ b/lib/mathlib.cpp @@ -266,7 +266,7 @@ MathLib::value MathLib::value::shiftLeft(const MathLib::value &v) const if (!isInt() || !v.isInt()) throw InternalError(nullptr, "Shift operand is not integer"); MathLib::value ret(*this); - if (v.mIntValue >= MathLib::bigint_bits) { + if (v.mIntValue < 0 || v.mIntValue >= MathLib::bigint_bits || ret.mIntValue < 0) { return ret; } ret.mIntValue <<= v.mIntValue; @@ -278,7 +278,7 @@ MathLib::value MathLib::value::shiftRight(const MathLib::value &v) const if (!isInt() || !v.isInt()) throw InternalError(nullptr, "Shift operand is not integer"); MathLib::value ret(*this); - if (v.mIntValue >= MathLib::bigint_bits) { + if (v.mIntValue < 0 || v.mIntValue >= MathLib::bigint_bits) { return ret; } ret.mIntValue >>= v.mIntValue; diff --git a/test/testmathlib.cpp b/test/testmathlib.cpp index 8cbe5b50019..4133d710e4f 100644 --- a/test/testmathlib.cpp +++ b/test/testmathlib.cpp @@ -64,6 +64,7 @@ class TestMathLib : public TestFixture { TEST_CASE(tan); TEST_CASE(abs); TEST_CASE(toString); + TEST_CASE(valueShift); } void isGreater() const { @@ -1511,6 +1512,20 @@ class TestMathLib : public TestFixture { ASSERT_EQUALS("2.22507385851e-308", MathLib::toString(std::numeric_limits::min())); ASSERT_EQUALS("1.79769313486e+308", MathLib::toString(std::numeric_limits::max())); } + + void valueShift() const { + // ordinary shifts + ASSERT_EQUALS("16", (MathLib::value("1") << MathLib::value("4")).str()); + ASSERT_EQUALS("64", (MathLib::value("256") >> MathLib::value("2")).str()); + + // a large hex literal is not negative as a string but parses to a negative + // bigint; shifting it must not be performed (left shift of a negative value + // and shifting by a negative count are both undefined). the operand is + // returned unchanged, as already done for counts >= bigint_bits. + ASSERT_EQUALS("9223372036854775808U", (MathLib::value("0x8000000000000000") << MathLib::value("1")).str()); + ASSERT_EQUALS("1", (MathLib::value("1") << MathLib::value("0x8000000000000000")).str()); + ASSERT_EQUALS("1", (MathLib::value("1") >> MathLib::value("0x8000000000000000")).str()); + } }; REGISTER_TEST(TestMathLib)