blob: d852cd8bedec6f33f12d9649e35c005d841c8e24 [file] [log] [blame]
// Copyright (c) 2019, 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.
//
// Dart test program for testing dart:ffi with null values.
//
// Separated into a separate file to make NNBD testing easier.
//
// VMOptions=
// VMOptions=--deterministic --optimization-counter-threshold=10
// VMOptions=--use-slow-path
// VMOptions=--use-slow-path --stacktrace-every=100
// VMOptions=--write-protect-code --no-dual-map-code
// VMOptions=--write-protect-code --no-dual-map-code --use-slow-path
// VMOptions=--write-protect-code --no-dual-map-code --stacktrace-every=100
// SharedObjects=ffi_test_functions
// @dart = 2.9
import 'dart:ffi';
import "package:expect/expect.dart";
import "package:ffi/ffi.dart";
import 'dylib_utils.dart';
import 'ffi_test_helpers.dart';
void main() {
for (int i = 0; i < 100; i++) {
testPointerStoreNull();
testEquality();
testNullReceivers();
testNullIndices();
testNullArguments();
testNullInt();
testNullDouble();
testNullManyArgs();
testException();
testNullReturnCallback();
}
}
void testPointerStoreNull() {
int i = null;
Pointer<Int8> p = calloc();
Expect.throws(() => p.value = i);
calloc.free(p);
double d = null;
Pointer<Float> p2 = calloc();
Expect.throws(() => p2.value = d);
calloc.free(p2);
Pointer<Void> x = null;
Pointer<Pointer<Void>> p3 = calloc();
Expect.throws(() => p3.value = x);
calloc.free(p3);
}
void testEquality() {
Pointer<Int8> p = Pointer.fromAddress(12345678);
Expect.notEquals(p, null);
Expect.notEquals(null, p);
}
/// With extension methods, the receiver position can be null.
testNullReceivers() {
Pointer<Int8> p = calloc();
Pointer<Int8> p4 = null;
Expect.throws(() => Expect.equals(10, p4.value));
Expect.throws(() => p4.value = 10);
Pointer<Pointer<Int8>> p5 = null;
Expect.throws(() => Expect.equals(10, p5.value));
Expect.throws(() => p5.value = p);
Pointer<Foo> p6 = null;
Expect.throws(() => Expect.equals(10, p6.ref));
calloc.free(p);
}
testNullIndices() {
Pointer<Int8> p = calloc();
Expect.throws(() => Expect.equals(10, p[null]));
Expect.throws(() => p[null] = 10);
Pointer<Pointer<Int8>> p5 = p.cast();
Expect.throws(() => Expect.equals(10, p5[null]));
Expect.throws(() => p5[null] = p);
Pointer<Foo> p6 = p.cast();
Expect.throws(() => Expect.equals(10, p6[null]));
calloc.free(p);
}
testNullArguments() {
Pointer<Int8> p = calloc();
Expect.throws(() => p.value = null);
calloc.free(p);
}
class Foo extends Struct {
@Int8()
int a;
}
void testNullInt() {
Expect.throws(() => sumPlus42(43, null));
}
void testNullDouble() {
Expect.throws(() => times1_337Double(null));
}
void testNullManyArgs() {
Expect.throws(() => sumManyNumbers(1, 2.0, 3, 4.0, 5, 6.0, 7, 8.0, 9, 10.0,
11, 12.0, 13, 14.0, 15, 16.0, 17, 18.0, null, 20.0));
}
typedef NativeBinaryOp = Int32 Function(Int32, Int32);
typedef BinaryOp = int Function(int, int);
typedef NativeDoubleUnaryOp = Double Function(Double);
typedef DoubleUnaryOp = double Function(double);
DoubleUnaryOp times1_337Double = ffiTestFunctions
.lookupFunction<NativeDoubleUnaryOp, DoubleUnaryOp>("Times1_337Double");
typedef NativeVigesimalOp = Double Function(
IntPtr,
Float,
IntPtr,
Double,
IntPtr,
Float,
IntPtr,
Double,
IntPtr,
Float,
IntPtr,
Double,
IntPtr,
Float,
IntPtr,
Double,
IntPtr,
Float,
IntPtr,
Double);
typedef VigesimalOp = double Function(
int,
double,
int,
double,
int,
double,
int,
double,
int,
double,
int,
double,
int,
double,
int,
double,
int,
double,
int,
double);
VigesimalOp sumManyNumbers = ffiTestFunctions
.lookupFunction<NativeVigesimalOp, VigesimalOp>("SumManyNumbers");
// Throw an exception from within the trampoline and collect a stacktrace
// include its frame.
void testException() {
try {
sumPlus42(null, null);
} catch (e, s) {
return;
}
throw "Didn't throw!";
}
BinaryOp sumPlus42 =
ffiTestFunctions.lookupFunction<NativeBinaryOp, BinaryOp>("SumPlus42");
void testNullReturnCallback() {
final test =
Test("ReturnNull", Pointer.fromFunction<ReturnNullType>(returnNull, 42));
test.run();
}
typedef NativeCallbackTest = Int32 Function(Pointer);
typedef NativeCallbackTestFn = int Function(Pointer);
final DynamicLibrary testLibrary = dlopenPlatformSpecific("ffi_test_functions");
class Test {
final String name;
final Pointer callback;
final bool skip;
Test(this.name, this.callback, {bool skipIf: false}) : skip = skipIf {}
void run() {
if (skip) return;
final NativeCallbackTestFn tester = testLibrary
.lookupFunction<NativeCallbackTest, NativeCallbackTestFn>("Test$name");
final int testCode = tester(callback);
if (testCode != 0) {
Expect.fail("Test $name failed.");
}
}
}
typedef ReturnNullType = Int32 Function();
int returnNull() {
return null;
}