// 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=90 // 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 p = calloc(); Expect.throws(() => p.value = i); calloc.free(p); double d = null; Pointer p2 = calloc(); Expect.throws(() => p2.value = d); calloc.free(p2); Pointer x = null; Pointer> p3 = calloc(); Expect.throws(() => p3.value = x); calloc.free(p3); } void testEquality() { Pointer p = Pointer.fromAddress(12345678); Expect.notEquals(p, null); Expect.notEquals(null, p); } /// With extension methods, the receiver position can be null. testNullReceivers() { Pointer p = calloc(); Pointer p4 = null; Expect.throws(() => Expect.equals(10, p4.value)); Expect.throws(() => p4.value = 10); Pointer> p5 = null; Expect.throws(() => Expect.equals(10, p5.value)); Expect.throws(() => p5.value = p); Pointer p6 = null; Expect.throws(() => Expect.equals(10, p6.ref)); calloc.free(p); } testNullIndices() { Pointer p = calloc(); Expect.throws(() => Expect.equals(10, p[null])); Expect.throws(() => p[null] = 10); Pointer> p5 = p.cast(); Expect.throws(() => Expect.equals(10, p5[null])); Expect.throws(() => p5[null] = p); Pointer p6 = p.cast(); Expect.throws(() => Expect.equals(10, p6[null])); calloc.free(p); } testNullArguments() { Pointer 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("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("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("SumPlus42"); void testNullReturnCallback() { final test = Test("ReturnNull", Pointer.fromFunction(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("Test$name"); final int testCode = tester(callback); if (testCode != 0) { Expect.fail("Test $name failed."); } } } typedef ReturnNullType = Int32 Function(); int returnNull() { return null; }