mirror of
https://github.com/bsnes-emu/bsnes.git
synced 2025-08-16 10:04:28 +02:00
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:
@@ -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;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user