Fix critical undefined bit-shift length operation

Natural/Integer<T>.bit() (BitRange) was shifting by whatever type the source was to match the target bit length.
But this breaks when the target type is u64/s64 and the source type is u32/s32 or smaller. Shifting by >=32 becomes undefined behavior.
We have to cast the input source to the target type first, so that the source<<shift result is valid.
This is safe here regardless of source's signedness, because it's only used in =, &=, ^=, |= operations.
This commit is contained in:
Near 2021-04-14 08:18:25 -04:00 committed by Screwtapello
parent 4ea984b688
commit 55e05c89c2
1 changed files with 16 additions and 8 deletions

View File

@ -58,7 +58,8 @@ template<int Precision, int Lo, int Hi> struct BitRange<Precision, Lo, Hi> {
}
template<typename T> inline auto& operator=(const T& source) {
target = target & ~mask | source << shift & mask;
type value = source;
target = target & ~mask | value << shift & mask;
return *this;
}
@ -105,17 +106,20 @@ template<int Precision, int Lo, int Hi> struct BitRange<Precision, Lo, Hi> {
}
template<typename T> inline auto& operator&=(const T& source) {
target = target & (~mask | source << shift & mask);
type value = source;
target = target & (~mask | value << shift & mask);
return *this;
}
template<typename T> inline auto& operator^=(const T& source) {
target = target ^ source << shift & mask;
type value = source;
target = target ^ value << shift & mask;
return *this;
}
template<typename T> inline auto& operator|=(const T& source) {
target = target | source << shift & mask;
type value = source;
target = target | value << shift & mask;
return *this;
}
@ -185,7 +189,8 @@ template<int Precision> struct BitRange<Precision> {
}
template<typename T> inline auto& operator=(const T& source) {
target = target & ~mask | source << shift & mask;
type value = source;
target = target & ~mask | value << shift & mask;
return *this;
}
@ -232,17 +237,20 @@ template<int Precision> struct BitRange<Precision> {
}
template<typename T> inline auto& operator&=(const T& source) {
target = target & (~mask | source << shift & mask);
type value = source;
target = target & (~mask | value << shift & mask);
return *this;
}
template<typename T> inline auto& operator^=(const T& source) {
target = target ^ source << shift & mask;
type value = source;
target = target ^ value << shift & mask;
return *this;
}
template<typename T> inline auto& operator|=(const T& source) {
target = target | source << shift & mask;
type value = source;
target = target | value << shift & mask;
return *this;
}