[kernel] Fix vm crash when trying to break on default constructor

Writing "break Foo" in observatory with a file including
```
class Foo { }
```

would crash them VM.

This CL introduces a test that reproduces it and fixes the issue.

Bug:
Change-Id: I24780d9204117ade19a0cb590c45aa31b7c04f7e
Reviewed-on: https://dart-review.googlesource.com/30445
Commit-Queue: Jens Johansen <jensj@google.com>
Reviewed-by: Vyacheslav Egorov <vegorov@google.com>
Reviewed-by: Kevin Millikin <kmillikin@google.com>
This commit is contained in:
Jens Johansen 2017-12-20 13:02:12 +00:00 committed by commit-bot@chromium.org
parent ac068b3cb4
commit 4e162c5318
5 changed files with 124 additions and 0 deletions

View file

@ -0,0 +1,76 @@
// Copyright (c) 2017, 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.
import 'dart:async';
import 'package:observatory/debugger.dart';
import 'package:observatory/service_io.dart';
import 'package:unittest/unittest.dart';
import 'package:observatory/service.dart' as S;
import 'service_test_common.dart';
import 'test_helper.dart';
class Foo {}
code() {
new Foo();
}
class TestDebugger extends Debugger {
TestDebugger(this.isolate, this.stack);
VM get vm => isolate.vm;
Isolate isolate;
ServiceMap stack;
int currentFrame = 0;
}
Future<Debugger> initDebugger(Isolate isolate) {
return isolate.getStack().then((stack) {
return new TestDebugger(isolate, stack);
});
}
List<String> stops = [];
var tests = [
hasPausedAtStart,
// Load the isolate's libraries
(Isolate isolate) async {
for (var lib in isolate.libraries) {
await lib.load();
}
},
(Isolate isolate) async {
var debugger = await initDebugger(isolate);
var loc = await DebuggerLocation.parse(debugger, 'Foo');
if (loc.valid) {
if (loc.function != null) {
try {
await debugger.isolate.addBreakpointAtEntry(loc.function);
} on S.ServerRpcException catch (e) {
if (e.code == S.ServerRpcException.kCannotAddBreakpoint) {
// Expected
} else {
fail("Got unexpected error $e");
}
}
} else {
fail("Expected to find function");
}
} else {
fail("Expected to find function");
}
isolate.resume();
},
];
main(args) {
runIsolateTestsSynchronous(args, tests,
testeeConcurrent: code, pause_on_start: true, pause_on_exit: true);
}

View file

@ -0,0 +1,38 @@
// Copyright (c) 2017, 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.
import 'test_helper.dart';
import 'service_test_common.dart';
const int LINE = 17;
const String file = "step_through_constructor_test.dart";
code() {
new Foo();
}
class Foo {
Foo() {
print("Hello from Foo!");
}
}
List<String> stops = [];
List<String> expected = [
"$file:${LINE+0}:5", // on 'print'
"$file:${LINE+1}:3", // on ending '}'
];
var tests = [
hasPausedAtStart,
setBreakpointAtLine(LINE),
runStepIntoThroughProgramRecordingStops(stops),
checkRecordedStops(stops, expected,
debugPrint: true, debugPrintFile: file, debugPrintLine: LINE)
];
main(args) {
runIsolateTestsSynchronous(args, tests,
testeeConcurrent: code, pause_on_start: true, pause_on_exit: true);
}

View file

@ -322,6 +322,7 @@ class ConstructorHelper {
enum Flag {
kConst = 1 << 0,
kExternal = 1 << 1,
kSyntheticDefault = 1 << 2,
};
explicit ConstructorHelper(StreamingFlowGraphBuilder* builder) {
@ -340,6 +341,7 @@ class ConstructorHelper {
bool IsExternal() { return (flags_ & kExternal) != 0; }
bool IsConst() { return (flags_ & kConst) != 0; }
bool IsSyntheticDefault() { return (flags_ & kSyntheticDefault) != 0; }
NameIndex canonical_name_;
TokenPosition position_;

View file

@ -2827,6 +2827,10 @@ Breakpoint* Debugger::SetBreakpointAtEntry(const Function& target_function,
BreakpointLocation* bpt_location = SetBreakpoint(
script, target_function.token_pos(), target_function.end_token_pos(), -1,
-1 /* no requested line/col */);
if (bpt_location == NULL) {
return NULL;
}
if (single_shot) {
return bpt_location->AddSingleShot(this);
} else {

View file

@ -986,6 +986,10 @@ void KernelLoader::FinishClassLoading(const Class& klass,
true, // is_method
false, // is_closure
&function_node_helper);
if (constructor_helper.IsSyntheticDefault()) {
function.set_is_debuggable(false);
}
function_node_helper.ReadUntilExcluding(FunctionNodeHelper::kEnd);
constructor_helper.SetJustRead(ConstructorHelper::kFunction);
constructor_helper.ReadUntilExcluding(ConstructorHelper::kEnd);