diff --git a/core/vdbe/insn.rs b/core/vdbe/insn.rs index 1e2af1820..583a094b0 100644 --- a/core/vdbe/insn.rs +++ b/core/vdbe/insn.rs @@ -975,7 +975,27 @@ pub fn exec_shift_left(mut lhs: &OwnedValue, mut rhs: &OwnedValue) -> OwnedValue } fn compute_shl(lhs: i64, rhs: i64) -> i64 { - compute_shr(lhs, -rhs) + if rhs == 0 { + lhs + } else if rhs > 0 { + // for positive shifts, if it's too large return 0 + if rhs >= 64 { + 0 + } else { + lhs << rhs + } + } else { + // for negative shifts, check if it's i64::MIN to avoid overflow on negation + if rhs == i64::MIN || rhs <= -64 { + if lhs < 0 { + -1 + } else { + 0 + } + } else { + lhs >> (-rhs) + } + } } pub fn exec_shift_right(mut lhs: &OwnedValue, mut rhs: &OwnedValue) -> OwnedValue { @@ -1013,15 +1033,24 @@ pub fn exec_shift_right(mut lhs: &OwnedValue, mut rhs: &OwnedValue) -> OwnedValu fn compute_shr(lhs: i64, rhs: i64) -> i64 { if rhs == 0 { lhs - } else if rhs >= 64 && lhs >= 0 || rhs <= -64 { - 0 - } else if rhs >= 64 && lhs < 0 { - -1 - } else if rhs < 0 { - // if negative do left shift - lhs << (-rhs) + } else if rhs > 0 { + // for positive right shifts + if rhs >= 64 { + if lhs < 0 { + -1 + } else { + 0 + } + } else { + lhs >> rhs + } } else { - lhs >> rhs + // for negative right shifts, check if it's i64::MIN to avoid overflow + if rhs == i64::MIN || -rhs >= 64 { + 0 + } else { + lhs << (-rhs) + } } } diff --git a/testing/select.test b/testing/select.test index f10f33b24..f8b033077 100755 --- a/testing/select.test +++ b/testing/select.test @@ -165,3 +165,53 @@ do_execsql_test select-not-like-expression { do_execsql_test select-like-expression { select 2 % 0.5 } {} + +do_execsql_test select_shl_large_negative_float { + SELECT 1 << -1e19; + SELECT 1 << -9223372036854775808; -- i64::MIN + SELECT 1 << 9223372036854775807; -- i64::MAX +} {0 0 0} + +do_execsql_test select_shl_basic { + SELECT 1 << 0, 1 << 1, 1 << 2, 1 << 3; + SELECT 2 << 0, 2 << 1, 2 << 2, 2 << 3; +} {1|2|4|8 +2|4|8|16} + +do_execsql_test select_shl_negative_numbers { + SELECT -1 << 0, -1 << 1, -1 << 2, -1 << 3; + SELECT -2 << 0, -2 << 1, -2 << 2, -2 << 3; +} {-1|-2|-4|-8 +-2|-4|-8|-16} +do_execsql_test select_shl_negative_shifts { + SELECT 8 << -1, 8 << -2, 8 << -3, 8 << -4; + SELECT -8 << -1, -8 << -2, -8 << -3, -8 << -4; +} {4|2|1|0 +-4|-2|-1|-1} + +do_execsql_test select_shl_large_shifts { + SELECT 1 << 62, 1 << 63, 1 << 64; + SELECT -1 << 62, -1 << 63, -1 << 64; +} {4611686018427387904|-9223372036854775808|0 +-4611686018427387904|-9223372036854775808|0} + +do_execsql_test select_shl_text_conversion { + SELECT '1' << '2'; + SELECT '8' << '-2'; + SELECT '-4' << '2'; +} {4 2 -16} + +do_execsql_test select_shl_chained { + SELECT (1 << 2) << 3; + SELECT (2 << 1) << (1 << 1); +} {32 16} + +do_execsql_test select_shl_numeric_types { + SELECT CAST(1 AS INTEGER) << 2; + SELECT 1.0 << 2; + SELECT 1.5 << 2; +} {4 4 4} + +do_execsql_test select_fuzz_failure_case { + SELECT (-9 << ((-6) << (9)) >> ((5)) % -10 - + - (-9)); +} {-16} \ No newline at end of file