mirror of
https://github.com/nushell/nushell.git
synced 2025-08-09 09:55:42 +02:00
Fix bugs and UB in bit shifting ops (#13663)
# Description Fixes #11267 Shifting by a `shift >= num_bits` is undefined in the underlying operation. Previously we also had an overflow on negative shifts for the operators `bit-shl` and `bit-shr` Furthermore I found a severe bug in the implementation of shifting of `binary` data with the commands `bits shl` and `bits shr`, this categorically produced incorrect results with shifts that were not `shift % 4 == 0`. `bits shr` also was able to produce outputs with different size to the input if the shift was exceeding the length of the input data by more than a byte. # User-Facing Changes It is now an error trying to shift by more than the available bits with: - `bit-shl` operator - `bit-shr` operator - command `bits shl` - command `bits shr` # Tests + Formatting Added testing for all relevant cases
This commit is contained in:
committed by
GitHub
parent
9261c0c55a
commit
3ab9f0b90a
@ -3317,7 +3317,18 @@ impl Value {
|
||||
pub fn bit_shl(&self, op: Span, rhs: &Value, span: Span) -> Result<Value, ShellError> {
|
||||
match (self, rhs) {
|
||||
(Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => {
|
||||
Ok(Value::int(*lhs << rhs, span))
|
||||
// Currently we disallow negative operands like Rust's `Shl`
|
||||
// Cheap guarding with TryInto<u32>
|
||||
if let Some(val) = (*rhs).try_into().ok().and_then(|rhs| lhs.checked_shl(rhs)) {
|
||||
Ok(Value::int(val, span))
|
||||
} else {
|
||||
Err(ShellError::OperatorOverflow {
|
||||
msg: "right operand to bit-shl exceeds available bits in underlying data"
|
||||
.into(),
|
||||
span,
|
||||
help: format!("Limit operand to 0 <= rhs < {}", i64::BITS),
|
||||
})
|
||||
}
|
||||
}
|
||||
(Value::Custom { val: lhs, .. }, rhs) => {
|
||||
lhs.operation(span, Operator::Bits(Bits::ShiftLeft), op, rhs)
|
||||
@ -3335,7 +3346,18 @@ impl Value {
|
||||
pub fn bit_shr(&self, op: Span, rhs: &Value, span: Span) -> Result<Value, ShellError> {
|
||||
match (self, rhs) {
|
||||
(Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => {
|
||||
Ok(Value::int(*lhs >> rhs, span))
|
||||
// Currently we disallow negative operands like Rust's `Shr`
|
||||
// Cheap guarding with TryInto<u32>
|
||||
if let Some(val) = (*rhs).try_into().ok().and_then(|rhs| lhs.checked_shr(rhs)) {
|
||||
Ok(Value::int(val, span))
|
||||
} else {
|
||||
Err(ShellError::OperatorOverflow {
|
||||
msg: "right operand to bit-shr exceeds available bits in underlying data"
|
||||
.into(),
|
||||
span,
|
||||
help: format!("Limit operand to 0 <= rhs < {}", i64::BITS),
|
||||
})
|
||||
}
|
||||
}
|
||||
(Value::Custom { val: lhs, .. }, rhs) => {
|
||||
lhs.operation(span, Operator::Bits(Bits::ShiftRight), op, rhs)
|
||||
|
Reference in New Issue
Block a user