[vm, compiler] Avoid undefined behavior when tracking induction variables wraps around.
TEST=ubsan Bug: https://github.com/dart-lang/sdk/issues/45511 Change-Id: Iaa5733dc048a811c87f479fa54fdb89bf64a0373 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/193443 Reviewed-by: Alexander Markov <alexmarkov@google.com> Commit-Queue: Ryan Macnak <rmacnak@google.com>
This commit is contained in:
committed by
commit-bot@chromium.org
parent
7b022a7f2f
commit
fbc25f3dff
@@ -292,6 +292,13 @@ class Utils {
|
||||
return static_cast<T>(static_cast<Unsigned>(a) * static_cast<Unsigned>(b));
|
||||
}
|
||||
|
||||
template <typename T = int64_t>
|
||||
static inline T NegWithWrapAround(T a) {
|
||||
// Avoid undefined behavior by doing arithmetic in the unsigned type.
|
||||
using Unsigned = typename std::make_unsigned<T>::type;
|
||||
return static_cast<T>(-static_cast<Unsigned>(a));
|
||||
}
|
||||
|
||||
// Shifts int64_t value left. Supports any non-negative number of bits and
|
||||
// silently discards shifted out bits.
|
||||
static inline int64_t ShiftLeftWithTruncation(int64_t a, int64_t b) {
|
||||
|
||||
@@ -723,13 +723,16 @@ InductionVar* InductionVarAnalysis::Add(InductionVar* x, InductionVar* y) {
|
||||
// Invariant + Invariant : only for same or just one instruction.
|
||||
if (x->def_ == y->def_) {
|
||||
return new (zone_)
|
||||
InductionVar(x->offset_ + y->offset_, x->mult_ + y->mult_, x->def_);
|
||||
InductionVar(Utils::AddWithWrapAround(x->offset_, y->offset_),
|
||||
Utils::AddWithWrapAround(x->mult_, y->mult_), x->def_);
|
||||
} else if (y->mult_ == 0) {
|
||||
return new (zone_)
|
||||
InductionVar(x->offset_ + y->offset_, x->mult_, x->def_);
|
||||
InductionVar(Utils::AddWithWrapAround(x->offset_, y->offset_),
|
||||
x->mult_, x->def_);
|
||||
} else if (x->mult_ == 0) {
|
||||
return new (zone_)
|
||||
InductionVar(x->offset_ + y->offset_, y->mult_, y->def_);
|
||||
InductionVar(Utils::AddWithWrapAround(x->offset_, y->offset_),
|
||||
y->mult_, y->def_);
|
||||
}
|
||||
} else if (y != nullptr) {
|
||||
// Invariant + Induction.
|
||||
@@ -768,13 +771,16 @@ InductionVar* InductionVarAnalysis::Sub(InductionVar* x, InductionVar* y) {
|
||||
// Invariant + Invariant : only for same or just one instruction.
|
||||
if (x->def_ == y->def_) {
|
||||
return new (zone_)
|
||||
InductionVar(x->offset_ - y->offset_, x->mult_ - y->mult_, x->def_);
|
||||
InductionVar(Utils::SubWithWrapAround(x->offset_, y->offset_),
|
||||
Utils::SubWithWrapAround(x->mult_, y->mult_), x->def_);
|
||||
} else if (y->mult_ == 0) {
|
||||
return new (zone_)
|
||||
InductionVar(x->offset_ - y->offset_, x->mult_, x->def_);
|
||||
InductionVar(Utils::SubWithWrapAround(x->offset_, y->offset_),
|
||||
x->mult_, x->def_);
|
||||
} else if (x->mult_ == 0) {
|
||||
return new (zone_)
|
||||
InductionVar(x->offset_ - y->offset_, -y->mult_, y->def_);
|
||||
InductionVar(Utils::SubWithWrapAround(x->offset_, y->offset_),
|
||||
Utils::NegWithWrapAround(y->mult_), y->def_);
|
||||
}
|
||||
} else if (y != nullptr) {
|
||||
// Invariant - Induction.
|
||||
@@ -823,7 +829,8 @@ InductionVar* InductionVarAnalysis::Mul(InductionVar* x, InductionVar* y) {
|
||||
if (InductionVar::IsConstant(x) && y != nullptr) {
|
||||
if (y->kind_ == InductionVar::kInvariant) {
|
||||
return new (zone_)
|
||||
InductionVar(x->offset_ * y->offset_, x->offset_ * y->mult_, y->def_);
|
||||
InductionVar(Utils::MulWithWrapAround(x->offset_, y->offset_),
|
||||
Utils::MulWithWrapAround(x->offset_, y->mult_), y->def_);
|
||||
}
|
||||
return new (zone_)
|
||||
InductionVar(y->kind_, Mul(x, y->initial_), Mul(x, y->next_));
|
||||
|
||||
Reference in New Issue
Block a user