0b58c4bd10
Retain the old values. Reapply of https://dart-review.googlesource.com/c/sdk/+/20680 with fixes for VM method fingerprints. Change-Id: Ie14e7ccc3194d5561983348e6b6752728913ff4d Reviewed-on: https://dart-review.googlesource.com/20664 Reviewed-by: Erik Ernst <eernst@google.com> Commit-Queue: Lasse R.H. Nielsen <lrn@google.com>
200 lines
5.4 KiB
Dart
200 lines
5.4 KiB
Dart
// Copyright (c) 2014, 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.
|
|
|
|
// This test reflectively enumerates all the methods in the system and tries to
|
|
// invoke them with various basic values (nulls, ints, etc). This may result in
|
|
// Dart exceptions or hangs, but should never result in crashes or JavaScript
|
|
// exceptions.
|
|
|
|
library test.invoke_natives;
|
|
|
|
import 'dart:mirrors';
|
|
import 'dart:async';
|
|
|
|
// Methods to be skipped, by qualified name.
|
|
var blacklist = [
|
|
// Don't recurse on this test.
|
|
'test.invoke_natives',
|
|
|
|
// Don't exit the test pre-maturely.
|
|
'dart.io.exit',
|
|
|
|
// Don't change the exit code, which may fool the test harness.
|
|
'dart.io.exitCode',
|
|
|
|
// Don't kill random other processes.
|
|
'dart.io.Process.killPid',
|
|
|
|
// Don't break into the debugger.
|
|
'dart.developer.debugger',
|
|
|
|
// Don't run blocking io calls.
|
|
new RegExp(r".*Sync$"),
|
|
|
|
// These prevent the test from exiting.
|
|
'dart.io.sleep',
|
|
'dart._http.HttpServer.HttpServer.listenOn',
|
|
|
|
// These either cause the VM to segfault or throw uncatchable API errors.
|
|
// TODO(15274): Fix them and remove from blacklist.
|
|
'dart.io.SystemEncoding.decode', // Windows only
|
|
'dart.io.SystemEncoding.encode', // Windows only
|
|
|
|
// These construct an object with an uninitialized native field.
|
|
// TODO(23869): We could make this safer, but making the failure non-fatal
|
|
// would we worthless aside from this test.
|
|
'dart.io.X509Certificate.X509Certificate._',
|
|
'dart.io._X509Impl._X509Impl',
|
|
|
|
// Don't call private methods in dart.async as they may circumvent the zoned
|
|
// error handling below.
|
|
new RegExp(r"^dart\.async\._.*$"),
|
|
];
|
|
|
|
bool isBlacklisted(Symbol qualifiedSymbol) {
|
|
var qualifiedString = MirrorSystem.getName(qualifiedSymbol);
|
|
for (var pattern in blacklist) {
|
|
if (qualifiedString.contains(pattern)) {
|
|
print('Skipping $qualifiedString');
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
class Task {
|
|
var name;
|
|
var action;
|
|
}
|
|
|
|
var queue = new List<Task>();
|
|
|
|
checkMethod(MethodMirror m, ObjectMirror target, [origin]) {
|
|
if (isBlacklisted(m.qualifiedName)) return;
|
|
|
|
var task = new Task();
|
|
task.name = '${MirrorSystem.getName(m.qualifiedName)} from $origin';
|
|
|
|
if (m.isRegularMethod) {
|
|
task.action = () => target.invoke(
|
|
m.simpleName, new List.filled(m.parameters.length, fuzzArgument));
|
|
} else if (m.isGetter) {
|
|
task.action = () => target.getField(m.simpleName);
|
|
} else if (m.isSetter) {
|
|
task.action = () => target.setField(m.simpleName, null);
|
|
} else if (m.isConstructor) {
|
|
return;
|
|
} else {
|
|
throw "Unexpected method kind";
|
|
}
|
|
|
|
queue.add(task);
|
|
}
|
|
|
|
checkInstance(instanceMirror, origin) {
|
|
ClassMirror klass = instanceMirror.type;
|
|
while (klass != null) {
|
|
instanceMirror.type.declarations.values
|
|
.where((d) => d is MethodMirror && !d.isStatic)
|
|
.forEach((m) => checkMethod(m, instanceMirror, origin));
|
|
klass = klass.superclass;
|
|
}
|
|
}
|
|
|
|
checkClass(classMirror) {
|
|
classMirror.declarations.values
|
|
.where((d) => d is MethodMirror && d.isStatic)
|
|
.forEach((m) => checkMethod(m, classMirror));
|
|
|
|
classMirror.declarations.values
|
|
.where((d) => d is MethodMirror && d.isConstructor)
|
|
.forEach((m) {
|
|
if (isBlacklisted(m.qualifiedName)) return;
|
|
var task = new Task();
|
|
task.name = MirrorSystem.getName(m.qualifiedName);
|
|
|
|
task.action = () {
|
|
var instance = classMirror.newInstance(m.constructorName,
|
|
new List.filled(m.parameters.length, fuzzArgument));
|
|
checkInstance(instance, task.name);
|
|
};
|
|
queue.add(task);
|
|
});
|
|
}
|
|
|
|
checkLibrary(libraryMirror) {
|
|
print(libraryMirror.simpleName);
|
|
if (isBlacklisted(libraryMirror.qualifiedName)) return;
|
|
|
|
libraryMirror.declarations.values
|
|
.where((d) => d is ClassMirror)
|
|
.forEach(checkClass);
|
|
|
|
libraryMirror.declarations.values
|
|
.where((d) => d is MethodMirror)
|
|
.forEach((m) => checkMethod(m, libraryMirror));
|
|
}
|
|
|
|
var testZone;
|
|
|
|
doOneTask() {
|
|
if (queue.length == 0) {
|
|
print('Done');
|
|
return;
|
|
}
|
|
|
|
var task = queue.removeLast();
|
|
print(task.name);
|
|
try {
|
|
task.action();
|
|
} catch (e) {}
|
|
|
|
// Register the next task in a timer callback so as to yield to async code
|
|
// scheduled in the current task. This isn't necessary for the test itself,
|
|
// but is helpful when trying to figure out which function is responsible for
|
|
// a crash.
|
|
testZone.createTimer(Duration.zero, doOneTask);
|
|
}
|
|
|
|
var fuzzArgument;
|
|
|
|
main() {
|
|
fuzzArgument = null;
|
|
fuzzArgument = 1; // //# smi: ok
|
|
fuzzArgument = false; // //# false: ok
|
|
fuzzArgument = 'string'; // //# string: ok
|
|
fuzzArgument = new List(0); // //# emptyarray: ok
|
|
|
|
print('Fuzzing with $fuzzArgument');
|
|
|
|
currentMirrorSystem().libraries.values.forEach(checkLibrary);
|
|
|
|
var valueObjects = [
|
|
true,
|
|
false,
|
|
null,
|
|
[],
|
|
{},
|
|
dynamic,
|
|
0,
|
|
0xEFFFFFF,
|
|
0xFFFFFFFF,
|
|
0xFFFFFFFFFFFFFFFF,
|
|
3.14159,
|
|
"foo",
|
|
'blåbærgrød',
|
|
'Îñţérñåţîöñåļîžåţîờñ',
|
|
"\u{1D11E}",
|
|
#symbol
|
|
];
|
|
valueObjects.forEach((v) => checkInstance(reflect(v), 'value object'));
|
|
|
|
void uncaughtErrorHandler(self, parent, zone, error, stack) {}
|
|
|
|
var zoneSpec =
|
|
new ZoneSpecification(handleUncaughtError: uncaughtErrorHandler);
|
|
testZone = Zone.current.fork(specification: zoneSpec);
|
|
testZone.createTimer(Duration.zero, doOneTask);
|
|
}
|