Promote constant expression shift type based on both operands
The shift evaluation needs to use a promoted type for both operands in
case of a mismatch.
The number of bits to shift is now checked for the shift right
operation.
Test: aidl_parser_fuzzer large_shift_overflow && atest -p
Bug: 168285430
Change-Id: I8bbe7ea66415d380066bc68566601a35487ce764
diff --git a/aidl_const_expressions.cpp b/aidl_const_expressions.cpp
index 5626e40..48980f5 100644
--- a/aidl_const_expressions.cpp
+++ b/aidl_const_expressions.cpp
@@ -101,7 +101,7 @@
T operator==(T o) { return mValue == o; }
T operator!=(T o) { return mValue != o; }
T operator>>(T o) {
- if (o < 0) {
+ if (o < 0 || o > static_cast<T>(sizeof(T) * 8)) {
mOverflowed = true;
return 0;
}
@@ -217,8 +217,7 @@
}
template <class T>
-bool handleShift(const AidlConstantValue& context, T lval, const string& op, int64_t rval,
- int64_t* out) {
+bool handleShift(const AidlConstantValue& context, T lval, const string& op, T rval, int64_t* out) {
// just cast rval to int64_t and it should fit.
COMPUTE_BINARY(T, >>)
COMPUTE_BINARY(T, <<)
@@ -889,9 +888,10 @@
// CASE: << >>
string newOp = op_;
if (OP_IS_BIN_SHIFT) {
- final_type_ = IntegralPromotion(left_val_->final_type_);
- // instead of promoting rval, simply casting it to int64 should also be good.
- int64_t numBits = right_val_->cast<int64_t>();
+ // promoted kind for both operands.
+ final_type_ = UsualArithmeticConversion(IntegralPromotion(left_val_->final_type_),
+ IntegralPromotion(right_val_->final_type_));
+ auto numBits = right_val_->final_value_;
if (numBits < 0) {
// shifting with negative number of bits is undefined in C. In AIDL it
// is defined as shifting into the other direction.
@@ -899,9 +899,9 @@
numBits = -numBits;
}
-#define CASE_SHIFT(__type__) \
- return handleShift(*this, static_cast<__type__>(left_val_->final_value_), newOp, numBits, \
- &final_value_);
+#define CASE_SHIFT(__type__) \
+ return handleShift(*this, static_cast<__type__>(left_val_->final_value_), newOp, \
+ static_cast<__type__>(numBits), &final_value_);
SWITCH_KIND(final_type_, CASE_SHIFT, SHOULD_NOT_REACH(); final_type_ = Type::ERROR;
is_valid_ = false; return false;)