Fix null-read in RegExpMatch.groupNames.

Fixes VM, DDC and Dart2js.

BUG= http://dartbug.com/39406

Change-Id: If181eaf50905c571614b656a232564e394e1b35d
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/136635
Commit-Queue: Lasse R.H. Nielsen <lrn@google.com>
Reviewed-by: Lasse R.H. Nielsen <lrn@google.com>
Reviewed-by: Teagan Strickland <sstrickl@google.com>
Reviewed-by: Bob Nystrom <rnystrom@google.com>
This commit is contained in:
Lasse Reichstein Holst Nielsen 2020-03-11 14:21:39 +00:00 committed by commit-bot@chromium.org
parent 5ae4448779
commit 9e10ef4458
8 changed files with 65 additions and 17 deletions

View file

@ -203,7 +203,7 @@ class _MatchImplementation implements RegExpMatch {
}
String namedGroup(String name) {
var groups = JS('Object', '#.groups', _match);
var groups = JS('Object|Null', '#.groups', _match);
if (groups != null) {
var result = JS('String|Null', '#[#]', groups, name);
if (result != null || JS<bool>('!', '# in #', name, groups)) {
@ -214,7 +214,7 @@ class _MatchImplementation implements RegExpMatch {
}
Iterable<String> get groupNames {
var groups = JS('Object', '#.groups', _match);
var groups = JS('Object|Null', '#.groups', _match);
if (groups != null) {
var keys = JSArray<String>.of(JS('', 'Object.keys(#)', groups));
return SubListIterable(keys, 0, null);

View file

@ -212,7 +212,7 @@ class _MatchImplementation implements RegExpMatch {
}
String namedGroup(String name) {
var groups = JS('Object', '#.groups', _match);
var groups = JS('Object|Null', '#.groups', _match);
if (groups != null) {
var result = JS('String|Null', '#[#]', groups, name);
if (result != null || JS('bool', '# in #', name, groups)) {
@ -223,7 +223,7 @@ class _MatchImplementation implements RegExpMatch {
}
Iterable<String> get groupNames {
var groups = JS('Object', '#.groups', _match);
var groups = JS('Object|Null', '#.groups', _match);
if (groups != null) {
var keys = new JSArray<String>.markGrowable(
JS('returns:JSExtendableArray;new:true', 'Object.keys(#)', groups));

View file

@ -274,13 +274,18 @@ class _RegExp implements RegExp {
int get _groupCount native "RegExp_getGroupCount";
// Returns a List [String, int, String, int, ...] where each
// String is the name of a capture group and the following
// int is that capture group's index.
/// The names and indices of named capture group.
///
/// Returns a [List] of alternating strings and integers,
/// `[String, int, String, int, ...]` where each
/// [String] is the name of a capture group and the following
/// [int] is that capture group's index.
/// Returns `null` if there are no group names.
List get _groupNameList native "RegExp_getGroupNameMap";
Iterable<String> get _groupNames sync* {
final nameList = _groupNameList;
if (nameList == null) return;
for (var i = 0; i < nameList.length; i += 2) {
yield nameList[i] as String;
}
@ -288,9 +293,10 @@ class _RegExp implements RegExp {
int _groupNameIndex(String name) {
var nameList = _groupNameList;
if (nameList == null) return -1;
for (var i = 0; i < nameList.length; i += 2) {
if (name == nameList[i]) {
return nameList[i + 1];
return nameList[i + 1] as int;
}
}
return -1;

View file

@ -204,7 +204,7 @@ class _MatchImplementation implements RegExpMatch {
}
String? namedGroup(String name) {
var groups = JS<Object?>('', '#.groups', _match);
var groups = JS<Object?>('Object|Null', '#.groups', _match);
if (groups != null) {
var result = JS<String?>('', '#[#]', groups, name);
if (result != null || JS<bool>('!', '# in #', name, groups)) {
@ -215,7 +215,7 @@ class _MatchImplementation implements RegExpMatch {
}
Iterable<String> get groupNames {
var groups = JS<Object?>('', '#.groups', _match);
var groups = JS<Object?>('Object|Null', '#.groups', _match);
if (groups != null) {
var keys = JSArray<String>.of(JS('', 'Object.keys(#)', groups));
return SubListIterable(keys, 0, null);

View file

@ -209,7 +209,7 @@ class _MatchImplementation implements RegExpMatch {
}
String namedGroup(String name) {
var groups = JS('Object', '#.groups', _match);
var groups = JS('Object|Null', '#.groups', _match);
if (groups != null) {
var result = JS('String|Null', '#[#]', groups, name);
if (result != null || JS('bool', '# in #', name, groups)) {
@ -220,7 +220,7 @@ class _MatchImplementation implements RegExpMatch {
}
Iterable<String> get groupNames {
var groups = JS('Object', '#.groups', _match);
var groups = JS('Object|Null', '#.groups', _match);
if (groups != null) {
var keys = new JSArray<String>.markGrowable(
JS('returns:JSExtendableArray;new:true', 'Object.keys(#)', groups));

View file

@ -277,13 +277,18 @@ class _RegExp implements RegExp {
int get _groupCount native "RegExp_getGroupCount";
// Returns a List [String, int, String, int, ...] where each
// String is the name of a capture group and the following
// int is that capture group's index.
List get _groupNameList native "RegExp_getGroupNameMap";
/// The names and indices of named capture group.
///
/// Returns a [List] of alternating strings and integers,
/// `[String, int, String, int, ...]` where each
/// [String] is the name of a capture group and the following
/// [int] is that capture group's index.
/// Returns `null` if there are no group names.
List? get _groupNameList native "RegExp_getGroupNameMap";
Iterable<String> get _groupNames sync* {
final nameList = _groupNameList;
if (nameList == null) return;
for (var i = 0; i < nameList.length; i += 2) {
yield nameList[i] as String;
}
@ -291,9 +296,10 @@ class _RegExp implements RegExp {
int _groupNameIndex(String name) {
var nameList = _groupNameList;
if (nameList == null) return -1;
for (var i = 0; i < nameList.length; i += 2) {
if (name == nameList[i]) {
return nameList[i + 1];
return nameList[i + 1] as int;
}
}
return -1;

View file

@ -0,0 +1,18 @@
// Copyright (c) 2020, 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 "package:expect/expect.dart";
// See http://dartbug.com/39406
//
// The following code must not throw.
void main() {
var regExp = RegExp(r'\w+');
var message = 'Hello world!';
var match = regExp.firstMatch(message);
var groupNames = match!.groupNames.toList();
Expect.listEquals([], groupNames);
Expect.throwsArgumentError(() => match.namedGroup("x"));
}

View file

@ -0,0 +1,18 @@
// Copyright (c) 2020, 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 "package:expect/expect.dart";
// See http://dartbug.com/39406
//
// The following code must not throw.
void main() {
var regExp = RegExp(r'\w+');
var message = 'Hello world!';
var match = regExp.firstMatch(message);
var groupNames = match.groupNames.toList();
Expect.listEquals([], groupNames);
Expect.throwsArgumentError(() => match.namedGroup("x"));
}