From 7a911ce3f1e945f2cbd1967c6109127e3acbab5a Mon Sep 17 00:00:00 2001 From: Ben Konyi Date: Tue, 3 Dec 2019 23:08:18 +0000 Subject: [PATCH] [ package:vm_service ] Fix issue where an exception could be thrown if remote service protocl version was older than that supported by package:vm_service When connecting to a VM service which supports an older version of the protocol than that supported by package:vm_service, there was the possibility for a crash if the package tried to create a List for a response property which is not supported by the remote VM service. The fix here is to check for null from createServiceObject when building a List from a response and produce an empty list for that property. Issue originally filed here: https://github.com/dart-lang/coverage/issues/278 Change-Id: Ibe8593fa8e4a55d05dd821bbdf363a67c15d5483 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/127065 Reviewed-by: Devon Carew Commit-Queue: Ben Konyi --- pkg/vm_service/CHANGELOG.md | 6 ++ pkg/vm_service/lib/vm_service.dart | 61 +++++++++++---------- pkg/vm_service/pubspec.yaml | 3 +- pkg/vm_service/tool/dart/generate_dart.dart | 2 +- 4 files changed, 41 insertions(+), 31 deletions(-) diff --git a/pkg/vm_service/CHANGELOG.md b/pkg/vm_service/CHANGELOG.md index 6e34daa16b5b..4dcc5946af56 100644 --- a/pkg/vm_service/CHANGELOG.md +++ b/pkg/vm_service/CHANGELOG.md @@ -1,4 +1,10 @@ # Changelog +## 2.1.3 +- Fixed issue where exception would be thrown when attempting to parse a + List entry in a response which is not present. This occurs when connected to + a service which does not yet support the latest service protocol supported by + this package. + ## 2.1.2 - Requests which have not yet completed when `VmService.dispose` is invoked will now complete with an `RPCError` exception rather than a `String` exception. diff --git a/pkg/vm_service/lib/vm_service.dart b/pkg/vm_service/lib/vm_service.dart index 065eb34f6ea5..b35fb4af7a88 100644 --- a/pkg/vm_service/lib/vm_service.dart +++ b/pkg/vm_service/lib/vm_service.dart @@ -2279,7 +2279,7 @@ class AllocationProfile extends Response { AllocationProfile._fromJson(Map json) : super._fromJson(json) { members = List.from( - createServiceObject(json['members'], const ['ClassHeapStats'])); + createServiceObject(json['members'], const ['ClassHeapStats']) ?? []); memoryUsage = createServiceObject(json['memoryUsage'], const ['MemoryUsage']); dateLastAccumulatorReset = json['dateLastAccumulatorReset'] is String @@ -2587,14 +2587,14 @@ class Class extends Obj { superClass = createServiceObject(json['super'], const ['ClassRef']); superType = createServiceObject(json['superType'], const ['InstanceRef']); interfaces = List.from( - createServiceObject(json['interfaces'], const ['InstanceRef'])); + createServiceObject(json['interfaces'], const ['InstanceRef']) ?? []); mixin = createServiceObject(json['mixin'], const ['InstanceRef']); fields = List.from( - createServiceObject(json['fields'], const ['FieldRef'])); + createServiceObject(json['fields'], const ['FieldRef']) ?? []); functions = List.from( - createServiceObject(json['functions'], const ['FuncRef'])); + createServiceObject(json['functions'], const ['FuncRef']) ?? []); subclasses = List.from( - createServiceObject(json['subclasses'], const ['ClassRef'])); + createServiceObject(json['subclasses'], const ['ClassRef']) ?? []); } @override @@ -2692,7 +2692,7 @@ class ClassList extends Response { }); ClassList._fromJson(Map json) : super._fromJson(json) { classes = List.from( - createServiceObject(json['classes'], const ['ClassRef'])); + createServiceObject(json['classes'], const ['ClassRef']) ?? []); } @override @@ -2843,7 +2843,7 @@ class Context extends Obj { length = json['length']; parent = createServiceObject(json['parent'], const ['Context']); variables = List.from( - createServiceObject(json['variables'], const ['ContextElement'])); + createServiceObject(json['variables'], const ['ContextElement']) ?? []); } @override @@ -2948,9 +2948,10 @@ class CpuSamples extends Response { timeExtentMicros = json['timeExtentMicros']; pid = json['pid']; functions = List.from( - createServiceObject(json['functions'], const ['ProfileFunction'])); + createServiceObject(json['functions'], const ['ProfileFunction']) ?? + []); samples = List.from( - createServiceObject(json['samples'], const ['CpuSample'])); + createServiceObject(json['samples'], const ['CpuSample']) ?? []); } @override @@ -3630,7 +3631,8 @@ class FlagList extends Response { @required this.flags, }); FlagList._fromJson(Map json) : super._fromJson(json) { - flags = List.from(createServiceObject(json['flags'], const ['Flag'])); + flags = List.from( + createServiceObject(json['flags'], const ['Flag']) ?? []); } @override @@ -4459,9 +4461,9 @@ class Isolate extends Response { pauseEvent = createServiceObject(json['pauseEvent'], const ['Event']); rootLib = createServiceObject(json['rootLib'], const ['LibraryRef']); libraries = List.from( - createServiceObject(json['libraries'], const ['LibraryRef'])); + createServiceObject(json['libraries'], const ['LibraryRef']) ?? []); breakpoints = List.from( - createServiceObject(json['breakpoints'], const ['Breakpoint'])); + createServiceObject(json['breakpoints'], const ['Breakpoint']) ?? []); error = createServiceObject(json['error'], const ['Error']); exceptionPauseMode = json['exceptionPauseMode']; extensionRPCs = json['extensionRPCs'] == null @@ -4574,7 +4576,7 @@ class IsolateGroup extends Response { number = json['number']; name = json['name']; isolates = List.from( - createServiceObject(json['isolates'], const ['IsolateRef'])); + createServiceObject(json['isolates'], const ['IsolateRef']) ?? []); } @override @@ -4613,7 +4615,8 @@ class InboundReferences extends Response { InboundReferences._fromJson(Map json) : super._fromJson(json) { references = List.from( - createServiceObject(json['references'], const ['InboundReference'])); + createServiceObject(json['references'], const ['InboundReference']) ?? + []); } @override @@ -4795,13 +4798,13 @@ class Library extends Obj { dependencies = List.from( _createSpecificObject(json['dependencies'], LibraryDependency.parse)); scripts = List.from( - createServiceObject(json['scripts'], const ['ScriptRef'])); + createServiceObject(json['scripts'], const ['ScriptRef']) ?? []); variables = List.from( - createServiceObject(json['variables'], const ['FieldRef'])); + createServiceObject(json['variables'], const ['FieldRef']) ?? []); functions = List.from( - createServiceObject(json['functions'], const ['FuncRef'])); + createServiceObject(json['functions'], const ['FuncRef']) ?? []); classes = List.from( - createServiceObject(json['classes'], const ['ClassRef'])); + createServiceObject(json['classes'], const ['ClassRef']) ?? []); } @override @@ -5458,7 +5461,7 @@ class RetainingPath extends Response { length = json['length']; gcRootType = json['gcRootType']; elements = List.from( - createServiceObject(json['elements'], const ['RetainingObject'])); + createServiceObject(json['elements'], const ['RetainingObject']) ?? []); } @override @@ -5719,7 +5722,7 @@ class ScriptList extends Response { }); ScriptList._fromJson(Map json) : super._fromJson(json) { scripts = List.from( - createServiceObject(json['scripts'], const ['ScriptRef'])); + createServiceObject(json['scripts'], const ['ScriptRef']) ?? []); } @override @@ -5805,7 +5808,7 @@ class SourceReport extends Response { ranges = List.from( _createSpecificObject(json['ranges'], SourceReportRange.parse)); scripts = List.from( - createServiceObject(json['scripts'], const ['ScriptRef'])); + createServiceObject(json['scripts'], const ['ScriptRef']) ?? []); } @override @@ -5965,8 +5968,8 @@ class Stack extends Response { this.awaiterFrames, }); Stack._fromJson(Map json) : super._fromJson(json) { - frames = - List.from(createServiceObject(json['frames'], const ['Frame'])); + frames = List.from( + createServiceObject(json['frames'], const ['Frame']) ?? []); asyncCausalFrames = json['asyncCausalFrames'] == null ? null : List.from( @@ -5976,7 +5979,7 @@ class Stack extends Response { : List.from( createServiceObject(json['awaiterFrames'], const ['Frame'])); messages = List.from( - createServiceObject(json['messages'], const ['Message'])); + createServiceObject(json['messages'], const ['Message']) ?? []); } @override @@ -6037,7 +6040,8 @@ class Timeline extends Response { }); Timeline._fromJson(Map json) : super._fromJson(json) { traceEvents = List.from( - createServiceObject(json['traceEvents'], const ['TimelineEvent'])); + createServiceObject(json['traceEvents'], const ['TimelineEvent']) ?? + []); timeOriginMicros = json['timeOriginMicros']; timeExtentMicros = json['timeExtentMicros']; } @@ -6202,7 +6206,7 @@ class TypeArguments extends Obj { TypeArguments._fromJson(Map json) : super._fromJson(json) { name = json['name']; types = List.from( - createServiceObject(json['types'], const ['InstanceRef'])); + createServiceObject(json['types'], const ['InstanceRef']) ?? []); } @override @@ -6416,9 +6420,10 @@ class VM extends Response { pid = json['pid']; startTime = json['startTime']; isolates = List.from( - createServiceObject(json['isolates'], const ['IsolateRef'])); + createServiceObject(json['isolates'], const ['IsolateRef']) ?? []); isolateGroups = List.from( - createServiceObject(json['isolateGroups'], const ['IsolateGroupRef'])); + createServiceObject(json['isolateGroups'], const ['IsolateGroupRef']) ?? + []); } @override diff --git a/pkg/vm_service/pubspec.yaml b/pkg/vm_service/pubspec.yaml index 9c06b397bb5b..bf8c4da65c5a 100644 --- a/pkg/vm_service/pubspec.yaml +++ b/pkg/vm_service/pubspec.yaml @@ -2,9 +2,8 @@ name: vm_service description: >- A library to communicate with a service implementing the Dart VM service protocol. -version: 2.1.2 +version: 2.1.3 -author: Dart Team homepage: https://github.com/dart-lang/sdk/tree/master/pkg/vm_service environment: diff --git a/pkg/vm_service/tool/dart/generate_dart.dart b/pkg/vm_service/tool/dart/generate_dart.dart index c90ea9a09d51..13eb06f37997 100644 --- a/pkg/vm_service/tool/dart/generate_dart.dart +++ b/pkg/vm_service/tool/dart/generate_dart.dart @@ -1465,7 +1465,7 @@ class Type extends Member { "List<${fieldType.listTypeArg}>.from(createServiceObject($ref ?? json['samples'], $typesList));"); } else { gen.writeln("${field.generatableName} = " - "List<${fieldType.listTypeArg}>.from(createServiceObject($ref, $typesList));"); + "List<${fieldType.listTypeArg}>.from(createServiceObject($ref, $typesList) ?? []);"); } } }