[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>
This commit is contained in:
Martin Kustermann 2018-06-19 10:28:05 +00:00
parent f288124d5a
commit b172a42881
8 changed files with 145 additions and 10 deletions

View file

@ -946,6 +946,34 @@ Message _withArgumentsConstEvalInvalidType(
arguments: {'constant': constant, 'type': _type, 'type2': _type2});
}
// 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(
@ -970,6 +998,33 @@ Message _withArgumentsConstEvalNonConstantLiteral(String string) {
arguments: {'string': string});
}
// 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;

View file

@ -80,8 +80,11 @@ ConstEvalInvalidStringInterpolationOperand/dart2jsCode: Fail
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

View file

@ -102,6 +102,15 @@ ConstEvalInvalidType:
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

View file

@ -719,8 +719,14 @@ class ConstantEvaluator extends RecursiveVisitor {
}
} 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 @@ class ConstantEvaluator extends RecursiveVisitor {
}
}
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 @@ class ConstantEvaluator extends RecursiveVisitor {
}
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 @@ abstract class ErrorReporter {
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 @@ abstract class ErrorReporterBase implements ErrorReporter {
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,

View file

@ -27,6 +27,7 @@ import 'package:kernel/ast.dart'
DartType,
Field,
FileUriNode,
IntConstant,
Procedure,
StaticGet,
TreeNode;
@ -283,6 +284,20 @@ class ForwardConstantEvaluationErrors implements constants.ErrorReporter {
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);

View file

@ -142,6 +142,9 @@ vm/debug_break_vm_test/*: Skip
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

View file

@ -212,6 +212,10 @@ implicit_creation/implicit_const_not_default_values_test/e4: MissingCompileTimeE
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 @@ mock_writable_final_private_field_test: RuntimeError # Issue 30849
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

View file

@ -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
}