[VM] Catch errors for integer operations in kernel2kernel constant evaluator
Issue https://github.com/dart-lang/sdk/issues/33481
Closes https://github.com/dart-lang/sdk/issues/33469
Change-Id: I7ca9825a0aa5f062732a759b4dd116e716a0d1b3
Reviewed-on: https://dart-review.googlesource.com/60580
Reviewed-by: Vyacheslav Egorov <vegorov@google.com>
diff --git a/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart b/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart
index e4aecb4..5aea704 100644
--- a/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart
+++ b/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart
@@ -949,6 +949,34 @@
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Template<
Message Function(
+ String string,
+ String string2,
+ String
+ string3)> templateConstEvalNegativeShift = const Template<
+ Message Function(String string, String string2, String string3)>(
+ messageTemplate:
+ r"""Binary operator '#string' on '#string2' requires non-negative operand, but was '#string3'.""",
+ withArguments: _withArgumentsConstEvalNegativeShift);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Message Function(String string, String string2, String string3)>
+ codeConstEvalNegativeShift =
+ const Code<Message Function(String string, String string2, String string3)>(
+ "ConstEvalNegativeShift", templateConstEvalNegativeShift,
+ dart2jsCode: "INVALID_CONSTANT_SHIFT");
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+Message _withArgumentsConstEvalNegativeShift(
+ String string, String string2, String string3) {
+ return new Message(codeConstEvalNegativeShift,
+ message:
+ """Binary operator '${string}' on '${string2}' requires non-negative operand, but was '${string3}'.""",
+ arguments: {'string': string, 'string2': string2, 'string3': string3});
+}
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Template<
+ Message Function(
String
string)> templateConstEvalNonConstantLiteral = const Template<
Message Function(String string)>(
@@ -971,6 +999,33 @@
}
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Template<
+ Message Function(
+ String string,
+ String
+ string2)> templateConstEvalZeroDivisor = const Template<
+ Message Function(String string, String string2)>(
+ messageTemplate:
+ r"""Binary operator '#string' on '#string2' requires non-zero divisor, but divisor was '0'.""",
+ withArguments: _withArgumentsConstEvalZeroDivisor);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Message Function(String string, String string2)>
+ codeConstEvalZeroDivisor =
+ const Code<Message Function(String string, String string2)>(
+ "ConstEvalZeroDivisor", templateConstEvalZeroDivisor,
+ analyzerCode: "CONST_EVAL_THROWS_IDBZE",
+ dart2jsCode: "INVALID_CONSTANT_DIV");
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+Message _withArgumentsConstEvalZeroDivisor(String string, String string2) {
+ return new Message(codeConstEvalZeroDivisor,
+ message:
+ """Binary operator '${string}' on '${string2}' requires non-zero divisor, but divisor was '0'.""",
+ arguments: {'string': string, 'string2': string2});
+}
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Code<Null> codeConstFactory = messageConstFactory;
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
diff --git a/pkg/front_end/messages.status b/pkg/front_end/messages.status
index 8249a81..7820263 100644
--- a/pkg/front_end/messages.status
+++ b/pkg/front_end/messages.status
@@ -80,8 +80,11 @@
ConstEvalInvalidStringInterpolationOperand/example: Fail
ConstEvalInvalidType/analyzerCode: Fail # CONST_CONSTRUCTOR_FIELD_TYPE_MISMATCH / CONST_CONSTRUCTOR_PARAM_TYPE_MISMATCH / CONST_CONSTRUCTOR_PARAM_TYPE_MISMATCH / ...
ConstEvalInvalidType/example: Fail
+ConstEvalNegativeShift/analyzerCode: Fail # http://dartbug.com/33481
+ConstEvalNegativeShift/example: Fail
ConstEvalNonConstantLiteral/dart2jsCode: Fail
ConstEvalNonConstantLiteral/example: Fail
+ConstEvalZeroDivisor/example: Fail
ConstFieldWithoutInitializer/example: Fail
ConstructorNotFound/analyzerCode: Fail
ConstructorNotFound/example: Fail
diff --git a/pkg/front_end/messages.yaml b/pkg/front_end/messages.yaml
index 356902d..ebaf317 100644
--- a/pkg/front_end/messages.yaml
+++ b/pkg/front_end/messages.yaml
@@ -102,6 +102,15 @@
ConstEvalInvalidBinaryOperandType:
template: "Binary operator '#string' on '#constant' requires operand of type '#type', but was of type '#type2'."
+ConstEvalZeroDivisor:
+ template: "Binary operator '#string' on '#string2' requires non-zero divisor, but divisor was '0'."
+ dart2jsCode: INVALID_CONSTANT_DIV
+ analyzerCode: CONST_EVAL_THROWS_IDBZE
+
+ConstEvalNegativeShift:
+ template: "Binary operator '#string' on '#string2' requires non-negative operand, but was '#string3'."
+ dart2jsCode: INVALID_CONSTANT_SHIFT
+
ConstEvalInvalidMethodInvocation:
template: "The method '#string' can't be invoked on '#constant' within a const context."
analyzerCode: UNDEFINED_OPERATOR
diff --git a/pkg/kernel/lib/transformations/constants.dart b/pkg/kernel/lib/transformations/constants.dart
index cf18494..4e62d58 100644
--- a/pkg/kernel/lib/transformations/constants.dart
+++ b/pkg/kernel/lib/transformations/constants.dart
@@ -719,8 +719,14 @@
}
} else if (arguments.length == 1) {
final Constant other = arguments[0];
+ final op = node.name.name;
if (other is IntConstant) {
- switch (node.name.name) {
+ if ((op == '<<' || op == '>>') && other.value < 0) {
+ errorReporter.negativeShift(contextChain,
+ node.arguments.positional.first, receiver, op, other);
+ throw const _AbortCurrentEvaluation();
+ }
+ switch (op) {
case '|':
return canonicalize(
new IntConstant(receiver.value | other.value));
@@ -739,12 +745,18 @@
}
}
- if (other is IntConstant || other is DoubleConstant) {
- final num value = (other is IntConstant)
- ? other.value
- : (other as DoubleConstant).value;
+ if (other is IntConstant) {
+ if (other.value == 0 && (op == '%' || op == '~/')) {
+ errorReporter.zeroDivisor(
+ contextChain, node.arguments.positional.first, receiver, op);
+ throw const _AbortCurrentEvaluation();
+ }
+
return evaluateBinaryNumericOperation(
- node.name.name, receiver.value, value, node);
+ node.name.name, receiver.value, other.value, node);
+ } else if (other is DoubleConstant) {
+ return evaluateBinaryNumericOperation(
+ node.name.name, receiver.value, other.value, node);
}
errorReporter.invalidBinaryOperandType(
@@ -1150,9 +1162,6 @@
}
return value;
}
-
- static const kMaxInt64 = (1 << 63) - 1;
- static const kMinInt64 = -(1 << 63);
}
/// Holds the necessary information for a constant object, namely
@@ -1256,6 +1265,10 @@
List<TreeNode> context, TreeNode node, Procedure target);
invalidStringInterpolationOperand(
List<TreeNode> context, TreeNode node, Constant constant);
+ zeroDivisor(
+ List<TreeNode> context, TreeNode node, IntConstant receiver, String op);
+ negativeShift(List<TreeNode> context, TreeNode node, IntConstant receiver,
+ String op, IntConstant argument);
nonConstLiteral(List<TreeNode> context, TreeNode node, String klass);
duplicateKey(List<TreeNode> context, TreeNode node, Constant key);
failedAssertion(List<TreeNode> context, TreeNode node, String message);
@@ -1323,6 +1336,24 @@
node);
}
+ zeroDivisor(
+ List<TreeNode> context, TreeNode node, IntConstant receiver, String op) {
+ report(
+ context,
+ "Binary operator '$op' on '${receiver.value}' requires non-zero "
+ "divisor, but divisor was '0'.",
+ node);
+ }
+
+ negativeShift(List<TreeNode> context, TreeNode node, IntConstant receiver,
+ String op, IntConstant argument) {
+ report(
+ context,
+ "Binary operator '$op' on '${receiver.value}' requires non-negative "
+ "operand, but was '${argument.value}'.",
+ node);
+ }
+
nonConstLiteral(List<TreeNode> context, TreeNode node, String klass) {
report(
context,
diff --git a/pkg/vm/lib/kernel_front_end.dart b/pkg/vm/lib/kernel_front_end.dart
index 928cac8..162890e 100644
--- a/pkg/vm/lib/kernel_front_end.dart
+++ b/pkg/vm/lib/kernel_front_end.dart
@@ -27,6 +27,7 @@
DartType,
Field,
FileUriNode,
+ IntConstant,
Procedure,
StaticGet,
TreeNode;
@@ -283,6 +284,20 @@
reportIt(context, message, node);
}
+ zeroDivisor(
+ List<TreeNode> context, TreeNode node, IntConstant receiver, String op) {
+ final message = codes.templateConstEvalZeroDivisor
+ .withArguments(op, '${receiver.value}');
+ reportIt(context, message, node);
+ }
+
+ negativeShift(List<TreeNode> context, TreeNode node, IntConstant receiver,
+ String op, IntConstant argument) {
+ final message = codes.templateConstEvalNegativeShift
+ .withArguments(op, '${receiver.value}', '${argument.value}');
+ reportIt(context, message, node);
+ }
+
nonConstLiteral(List<TreeNode> context, TreeNode node, String klass) {
final message =
codes.templateConstEvalNonConstantLiteral.withArguments(klass);
diff --git a/tests/language_2/language_2_analyzer.status b/tests/language_2/language_2_analyzer.status
index b22bdfb..671b37d 100644
--- a/tests/language_2/language_2_analyzer.status
+++ b/tests/language_2/language_2_analyzer.status
@@ -142,6 +142,9 @@
vm/lazy_deopt_with_exception_test: Pass
vm/reflect_core_vm_test: CompileTimeError
vm/regress_27201_test: SkipByDesign # Loads bad library, so will always crash.
+vm/regress_33469_test/01: Crash # http://dartbug.com/33481
+vm/regress_33469_test/02: Crash # http://dartbug.com/33481
+vm/regress_33469_test/03: MissingCompileTimeError # http://dartbug.com/33481
void_type_override_test/00: MissingCompileTimeError
void_type_override_test/00b: MissingCompileTimeError
void_type_override_test/01: MissingCompileTimeError
diff --git a/tests/language_2/language_2_kernel.status b/tests/language_2/language_2_kernel.status
index 686ef58..d5c998a 100644
--- a/tests/language_2/language_2_kernel.status
+++ b/tests/language_2/language_2_kernel.status
@@ -212,6 +212,10 @@
implicit_creation/implicit_const_not_default_values_test/e5: MissingCompileTimeError
implicit_creation/implicit_const_not_default_values_test/e7: MissingCompileTimeError
implicit_creation/implicit_const_not_default_values_test/e8: MissingCompileTimeError
+vm/regress_33469_test/01: MissingCompileTimeError
+vm/regress_33469_test/02: MissingCompileTimeError
+vm/regress_33469_test/03: MissingCompileTimeError
+vm/regress_33469_test/04: MissingCompileTimeError
[ $fasta ]
abstract_override_adds_optional_args_concrete_subclass_test: MissingCompileTimeError # Issue 32014.
@@ -805,8 +809,8 @@
named_constructor_test/01: MissingRuntimeError # Fasta bug: Bad compilation of constructor reference.
named_parameters_default_eq_test/none: RuntimeError
nested_generic_closure_test: RuntimeError
-no_main_test/01: Skip
no_main_test/01: DartkCrash
+no_main_test/01: Skip
no_such_method_mock_test: RuntimeError # Issue 31426
null_no_such_method_test: CompileTimeError # Issue 31533
override_inheritance_field_test/04: CompileTimeError # Issue 31616
diff --git a/tests/language_2/vm/regress_33469_test.dart b/tests/language_2/vm/regress_33469_test.dart
new file mode 100644
index 0000000..a18a6ad
--- /dev/null
+++ b/tests/language_2/vm/regress_33469_test.dart
@@ -0,0 +1,15 @@
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class X {
+ final x;
+ const X(this.x);
+}
+
+void main() {
+ print(const X(1 << -1).x); /// 01: compile-time error
+ print(const X(1 >> -1).x); /// 02: compile-time error
+ print(const X(1 % 0).x); /// 03: compile-time error
+ print(const X(1 ~/ 0).x); /// 04: compile-time error
+}