// 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 extra checks // // SharedObjects=ffi_test_dynamic_library ffi_test_functions // @dart = 2.9 import 'dart:ffi'; import "package:ffi/ffi.dart"; import 'dylib_utils.dart'; void main() { testGetGeneric(); testGetGeneric2(); testGetVoid(); testGetNativeFunction(); testGetNativeType(); testGetTypeMismatch(); testSetGeneric(); testSetGeneric2(); testSetVoid(); testSetNativeFunction(); testSetNativeType(); testSetTypeMismatch(); testAsFunctionGeneric(); testAsFunctionGeneric2(); testAsFunctionWrongNativeFunctionSignature(); testAsFunctionTypeMismatch(); testFromFunctionGeneric(); testFromFunctionGeneric2(); testFromFunctionWrongNativeFunctionSignature(); testFromFunctionTypeMismatch(); testFromFunctionClosure(); testFromFunctionTearOff(); testFromFunctionAbstract(); testLookupFunctionGeneric(); testLookupFunctionGeneric2(); testLookupFunctionWrongNativeFunctionSignature(); testLookupFunctionTypeMismatch(); testLookupFunctionPointervoid(); testLookupFunctionPointerNFdyn(); testNativeFunctionSignatureInvalidReturn(); testNativeFunctionSignatureInvalidParam(); testNativeFunctionSignatureInvalidOptionalNamed(); testNativeFunctionSignatureInvalidOptionalPositional(); testHandleVariance(); testEmptyStructLookupFunctionArgument(); testEmptyStructLookupFunctionReturn(); testEmptyStructAsFunctionArgument(); testEmptyStructAsFunctionReturn(); testEmptyStructFromFunctionArgument(); testEmptyStructFromFunctionReturn(); testAllocateGeneric(); testAllocateNativeType(); testRefStruct(); testSizeOfGeneric(); testSizeOfNativeType(); testSizeOfHandle(); testElementAtGeneric(); testElementAtNativeType(); testLookupFunctionIsLeafMustBeConst(); testAsFunctionIsLeafMustBeConst(); testLookupFunctionTakesHandle(); testAsFunctionTakesHandle(); testLookupFunctionReturnsHandle(); testAsFunctionReturnsHandle(); } typedef Int8UnOp = Int8 Function(Int8); typedef IntUnOp = int Function(int); void testGetGeneric() { int generic(Pointer p) { int result; result = p.value; //# 20: compile-time error return result; } Pointer p = calloc(); p.value = 123; Pointer loseType = p; generic(loseType); calloc.free(p); } void testGetGeneric2() { T generic() { Pointer p = calloc(); p.value = 123; T result; result = p.value; //# 21: compile-time error calloc.free(p); return result; } generic(); } void testGetVoid() { Pointer p1 = calloc(); Pointer p2 = p1.cast(); p2.value; //# 22: compile-time error calloc.free(p1); } void testGetNativeFunction() { Pointer> p = Pointer.fromAddress(1337); IntUnOp f = p.value; //# 23: compile-time error } void testGetNativeType() { // Is it possible to obtain a Pointer at all? } void testGetTypeMismatch() { Pointer> p = calloc(); Pointer typedNull = nullptr; p.value = typedNull; // this fails to compile due to type mismatch Pointer p2 = p.value; //# 25: compile-time error calloc.free(p); } void testSetGeneric() { void generic(Pointer p) { p.value = 123; //# 26: compile-time error } Pointer p = calloc(); p.value = 123; Pointer loseType = p; generic(loseType); calloc.free(p); } void testSetGeneric2() { void generic(T arg) { Pointer p = calloc(); p.value = arg; //# 27: compile-time error calloc.free(p); } generic(123); } void testSetVoid() { Pointer p1 = calloc(); Pointer p2 = p1.cast(); p2.value = 1234; //# 28: compile-time error calloc.free(p1); } void testSetNativeFunction() { Pointer> p = Pointer.fromAddress(1337); IntUnOp f = (a) => a + 1; p.value = f; //# 29: compile-time error } void testSetNativeType() { // Is it possible to obtain a Pointer at all? } void testSetTypeMismatch() { // the pointer to pointer types must match up Pointer pHelper = calloc(); pHelper.value = 123; Pointer> p = calloc(); // this fails to compile due to type mismatch p.value = pHelper; //# 40: compile-time error calloc.free(pHelper); calloc.free(p); } void testAsFunctionGeneric() { T generic() { Pointer> p = Pointer.fromAddress(1337); Function f; f = p.asFunction(); //# 11: compile-time error return f; } generic(); } void testAsFunctionGeneric2() { generic(Pointer p) { Function f; f = p.asFunction(); //# 12: compile-time error return f; } Pointer> p = Pointer.fromAddress(1337); generic(p); } void testAsFunctionWrongNativeFunctionSignature() { Pointer> p; Function f = p.asFunction(); //# 13: compile-time error } typedef IntBinOp = int Function(int, int); void testAsFunctionTypeMismatch() { Pointer> p = Pointer.fromAddress(1337); IntBinOp f = p.asFunction(); //# 14: compile-time error } typedef NativeDoubleUnOp = Double Function(Double); typedef DoubleUnOp = double Function(double); double myTimesThree(double d) => d * 3; int myTimesFour(int i) => i * 4; void testFromFunctionGeneric() { Pointer generic(T f) { Pointer> result; result = Pointer.fromFunction(f); //# 70: compile-time error return result; } generic(myTimesThree); } void testFromFunctionGeneric2() { Pointer> generic() { Pointer> result; result = Pointer.fromFunction(myTimesThree); //# 71: compile-time error return result; } generic(); } void testFromFunctionWrongNativeFunctionSignature() { Pointer.fromFunction(myTimesFour); //# 72: compile-time error } void testFromFunctionTypeMismatch() { Pointer> p; p = Pointer.fromFunction(myTimesFour); //# 73: compile-time error } void testFromFunctionClosure() { DoubleUnOp someClosure = (double z) => z / 27.0; Pointer> p; p = Pointer.fromFunction(someClosure); //# 74: compile-time error } class X { double tearoff(double d) => d / 27.0; } void testFromFunctionTearOff() { DoubleUnOp fld = X().tearoff; Pointer> p; p = Pointer.fromFunction(fld); //# 75: compile-time error } void testFromFunctionAbstract() { Pointer.fromFunction(//# 76: compile-time error testFromFunctionAbstract); //# 76: compile-time error } void testLookupFunctionGeneric() { Function generic() { DynamicLibrary l = dlopenPlatformSpecific("ffi_test_dynamic_library"); Function result; result = l.lookupFunction("cos"); //# 15: compile-time error return result; } generic(); } void testLookupFunctionGeneric2() { Function generic() { DynamicLibrary l = dlopenPlatformSpecific("ffi_test_dynamic_library"); Function result; result = //# 16: compile-time error l.lookupFunction("cos"); //# 16: compile-time error return result; } generic(); } void testLookupFunctionWrongNativeFunctionSignature() { DynamicLibrary l = dlopenPlatformSpecific("ffi_test_dynamic_library"); l.lookupFunction("cos"); //# 17: compile-time error } void testLookupFunctionTypeMismatch() { DynamicLibrary l = dlopenPlatformSpecific("ffi_test_dynamic_library"); l.lookupFunction("cos"); //# 18: compile-time error } typedef PointervoidN = Void Function(Pointer); typedef PointervoidD = void Function(Pointer); void testLookupFunctionPointervoid() { DynamicLibrary l = dlopenPlatformSpecific("ffi_test_dynamic_library"); // TODO(https://dartbug.com/44593): This should be a compile-time error in CFE. // l.lookupFunction("cos"); } typedef PointerNFdynN = Void Function(Pointer); typedef PointerNFdynD = void Function(Pointer); void testLookupFunctionPointerNFdyn() { DynamicLibrary l = dlopenPlatformSpecific("ffi_test_dynamic_library"); // TODO(https://dartbug.com/44594): Should this be an error or not? // l.lookupFunction("cos"); } // TODO(dacoharkes): make the next 4 test compile errors typedef Invalid1 = int Function(Int8); typedef Invalid2 = Int8 Function(int); typedef Invalid3 = Int8 Function({Int8 named}); typedef Invalid4 = Int8 Function([Int8 positional]); void testNativeFunctionSignatureInvalidReturn() { // Pointer> p = fromAddress(999); } void testNativeFunctionSignatureInvalidParam() { // Pointer> p = fromAddress(999); } void testNativeFunctionSignatureInvalidOptionalNamed() { // Pointer> p = fromAddress(999); } void testNativeFunctionSignatureInvalidOptionalPositional() { // Pointer> p = fromAddress(999); } // error on missing field annotation class TestStruct extends Struct { @Double() double x; double y; //# 50: compile-time error } // Cannot extend structs. class TestStruct3 extends TestStruct {} //# 52: compile-time error // error on double annotation class TestStruct4 extends Struct { @Double() @Double() //# 53: compile-time error double z; } // error on annotation not matching up class TestStruct5 extends Struct { @Int64() //# 54: compile-time error double z; //# 54: compile-time error Pointer notEmpty; } // error on annotation not matching up class TestStruct6 extends Struct { @Void() //# 55: compile-time error double z; //# 55: compile-time error Pointer notEmpty; } // error on annotation not matching up class TestStruct7 extends Struct { @NativeType() //# 56: compile-time error double z; //# 56: compile-time error Pointer notEmpty; } // error on field initializer on field class TestStruct8 extends Struct { @Double() //# 57: compile-time error double z = 10.0; //# 57: compile-time error Pointer notEmpty; } // error on field initializer in constructor class TestStruct9 extends Struct { @Double() double z; TestStruct9() : z = 0.0 {} //# 58: compile-time error } // Struct classes may not be generic. class TestStruct11 extends //# 60: compile-time error Struct> {} //# 60: compile-time error // Structs may not appear inside structs (currently, there is no suitable // annotation). class TestStruct12 extends Struct { @Pointer //# 61: compile-time error TestStruct9 struct; //# 61: compile-time error Pointer notEmpty; } class DummyAnnotation { const DummyAnnotation(); } // Structs fields may have other annotations. class TestStruct13 extends Struct { @DummyAnnotation() @Double() double z; } // Cannot extend native types. class ENativeType extends NativeType {} //# 90: compile-time error class EInt8 extends Int8 {} //# 91: compile-time error class EInt16 extends Int16 {} //# 92: compile-time error class EInt32 extends Int32 {} //# 93: compile-time error class EInt64 extends Int64 {} //# 94: compile-time error class EUint8 extends Uint8 {} //# 95: compile-time error class EUint16 extends Uint16 {} //# 96: compile-time error class EUint32 extends Uint32 {} //# 97: compile-time error class EUint64 extends Uint64 {} //# 98: compile-time error class EIntPtr extends IntPtr {} //# 99: compile-time error class EFloat extends Float {} //# 910: compile-time error class EDouble extends Double {} //# 911: compile-time error class EVoid extends Void {} //# 912: compile-time error class ENativeFunction extends NativeFunction {} //# 913: compile-time error class EPointer extends Pointer {} //# 914: compile-time error // Cannot implement native natives or Struct. // Cannot extend native types. class INativeType implements NativeType {} //# 80: compile-time error class IInt8 implements Int8 {} //# 81: compile-time error class IInt16 implements Int16 {} //# 82: compile-time error class IInt32 implements Int32 {} //# 83: compile-time error class IInt64 implements Int64 {} //# 84: compile-time error class IUint8 implements Uint8 {} //# 85: compile-time error class IUint16 implements Uint16 {} //# 86: compile-time error class IUint32 implements Uint32 {} //# 87: compile-time error class IUint64 implements Uint64 {} //# 88: compile-time error class IIntPtr implements IntPtr {} //# 88: compile-time error class IFloat implements Float {} //# 810: compile-time error class IDouble implements Double {} //# 811: compile-time error class IVoid implements Void {} //# 812: compile-time error class INativeFunction //# 813: compile-time error implements //# 813: compile-time error NativeFunction {} //# 813: compile-time error class IPointer implements Pointer {} //# 814: compile-time error class IStruct implements Struct {} //# 815: compile-time error class IOpaque implements Opaque {} //# 816: compile-time error class MyClass { int x; MyClass(this.x); } final testLibrary = dlopenPlatformSpecific("ffi_test_functions"); void testHandleVariance() { // Taking a more specific argument is okay. testLibrary.lookupFunction( "PassObjectToC"); // Requiring a more specific return type is not, this requires a cast from // the user. testLibrary.lookupFunction< //# 1000: compile-time error Handle Function(Handle), //# 1000: compile-time error MyClass Function(Object)>("PassObjectToC"); //# 1000: compile-time error } class TestStruct1001 extends Struct { Handle handle; //# 1001: compile-time error Pointer notEmpty; } class TestStruct1002 extends Struct { @Handle() //# 1002: compile-time error Object handle; //# 1002: compile-time error Pointer notEmpty; } class EmptyStruct extends Struct {} //# 1099: compile-time error class EmptyStruct extends Struct {} //# 1100: compile-time error void testEmptyStructLookupFunctionArgument() { testLibrary.lookupFunction< //# 1100: compile-time error Void Function(EmptyStruct), //# 1100: compile-time error void Function(EmptyStruct)>("DoesNotExist"); //# 1100: compile-time error } class EmptyStruct extends Struct {} //# 1101: compile-time error void testEmptyStructLookupFunctionReturn() { testLibrary.lookupFunction< //# 1101: compile-time error EmptyStruct Function(), //# 1101: compile-time error EmptyStruct Function()>("DoesNotExist"); //# 1101: compile-time error } class EmptyStruct extends Struct {} //# 1102: compile-time error void testEmptyStructAsFunctionArgument() { final Pointer< //# 1102: compile-time error NativeFunction< //# 1102: compile-time error Void Function(EmptyStruct)>> //# 1102: compile-time error pointer = Pointer.fromAddress(1234); //# 1102: compile-time error pointer.asFunction(); //# 1102: compile-time error } class EmptyStruct extends Struct {} //# 1103: compile-time error void testEmptyStructAsFunctionReturn() { final Pointer< //# 1103: compile-time error NativeFunction> //# 1103: compile-time error pointer = Pointer.fromAddress(1234); //# 1103: compile-time error pointer.asFunction(); //# 1103: compile-time error } class EmptyStruct extends Struct {} //# 1104: compile-time error void _consumeEmptyStruct(EmptyStruct e) => //# 1104: compile-time error print(e); //# 1104: compile-time error void testEmptyStructFromFunctionArgument() { Pointer.fromFunction(//# 1104: compile-time error _consumeEmptyStruct); //# 1104: compile-time error } class EmptyStruct extends Struct {} //# 1105: compile-time error EmptyStruct _returnEmptyStruct() => EmptyStruct(); //# 1105: compile-time error void testEmptyStructFromFunctionReturn() { Pointer.fromFunction(//# 1105: compile-time error _returnEmptyStruct); //# 1105: compile-time error } class EmptyStruct extends Struct {} //# 1106: compile-time error class HasNestedEmptyStruct extends Struct { EmptyStruct nestedEmptyStruct; //# 1106: compile-time error Pointer notEmpty; } void testAllocateGeneric() { Pointer generic() { Pointer pointer = nullptr; pointer = calloc(); //# 1320: compile-time error return pointer; } Pointer p = generic(); } void testAllocateNativeType() { calloc(); //# 1321: compile-time error } void testRefStruct() { final myStructPointer = calloc(); Pointer structPointer = myStructPointer; structPointer.ref; //# 1330: compile-time error calloc.free(myStructPointer); } T genericRef(Pointer p) => //# 1200: compile-time error p.ref; //# 1200: compile-time error T genericRef2(Pointer p) => //# 1201: compile-time error p.cast().ref; //# 1201: compile-time error T genericRef3(Pointer p) => //# 1202: compile-time error p[0]; //# 1202: compile-time error T genericRef4(Array p) => //# 1210: compile-time error p[0]; //# 1210: compile-time error void testSizeOfGeneric() { int generic() { int size = sizeOf(); size = sizeOf(); //# 1300: compile-time error return size; } int size = generic>(); } void testSizeOfNativeType() { sizeOf(); //# 1301: compile-time error } void testSizeOfHandle() { sizeOf(); //# 1302: compile-time error } void testElementAtGeneric() { Pointer generic(Pointer pointer) { Pointer returnValue = pointer; returnValue = returnValue.elementAt(1); //# 1310: compile-time error return returnValue; } Pointer p = calloc(); p.elementAt(1); generic(p); calloc.free(p); } void testElementAtNativeType() { Pointer p = calloc(); p.elementAt(1); Pointer p2 = p; p2.elementAt(1); //# 1311: compile-time error calloc.free(p); } class TestStruct1400 extends Struct { @Array(8) //# 1400: compile-time error @Array(8) Array a0; } class TestStruct1401 extends Struct { Array a0; //# 1401: compile-time error Pointer notEmpty; } class TestStruct1402 extends Struct { @Array(8, 8, 8) //# 1402: compile-time error Array> a0; //# 1402: compile-time error Pointer notEmpty; } class TestStruct1403 extends Struct { @Array(8, 8) //# 1403: compile-time error Array>> a0; //# 1403: compile-time error Pointer notEmpty; } class TestStruct1404 extends Struct { @Array.multi([8, 8, 8]) //# 1404: compile-time error Array> a0; //# 1404: compile-time error Pointer notEmpty; } class TestStruct1405 extends Struct { @Array.multi([8, 8]) //# 1405: compile-time error Array>> a0; //# 1405: compile-time error Pointer notEmpty; } void testLookupFunctionIsLeafMustBeConst() { bool notAConst = false; DynamicLibrary l = dlopenPlatformSpecific("ffi_test_dynamic_library"); l.lookupFunction("timesFour", isLeaf:notAConst); //# 1500: compile-time error } void testAsFunctionIsLeafMustBeConst() { bool notAConst = false; Pointer> p = Pointer.fromAddress(1337); IntUnOp f = p.asFunction(isLeaf:notAConst); //# 1501: compile-time error } typedef NativeTakesHandle = Void Function(Handle); typedef TakesHandle = void Function(Object); void testLookupFunctionTakesHandle() { DynamicLibrary l = dlopenPlatformSpecific("ffi_test_dynamic_library"); l.lookupFunction("takesHandle", isLeaf:true); //# 1502: compile-time error } void testAsFunctionTakesHandle() { Pointer> p = Pointer.fromAddress(1337); //# 1503: compile-time error TakesHandle f = p.asFunction(isLeaf:true); //# 1503: compile-time error } typedef NativeReturnsHandle = Handle Function(); typedef ReturnsHandle = Object Function(); void testLookupFunctionReturnsHandle() { DynamicLibrary l = dlopenPlatformSpecific("ffi_test_dynamic_library"); l.lookupFunction("returnsHandle", isLeaf:true); //# 1504: compile-time error } void testAsFunctionReturnsHandle() { Pointer> p = Pointer.fromAddress(1337); //# 1505: compile-time error ReturnsHandle f = p.asFunction(isLeaf:true); //# 1505: compile-time error } @Packed(1) class TestStruct1600 extends Struct { Pointer notEmpty; } @Packed(1) @Packed(1) //# 1601: compile-time error class TestStruct1601 extends Struct { Pointer notEmpty; } @Packed(3) //# 1602: compile-time error class TestStruct1602 extends Struct { Pointer notEmpty; } class TestStruct1603 extends Struct { Pointer notEmpty; } @Packed(1) class TestStruct1603Packed extends Struct { Pointer notEmpty; TestStruct1603 nestedNotPacked; //# 1603: compile-time error } @Packed(8) class TestStruct1604 extends Struct { Pointer notEmpty; } @Packed(1) class TestStruct1604Packed extends Struct { Pointer notEmpty; TestStruct1604 nestedLooselyPacked; //# 1604: compile-time error } @Packed(1) class TestStruct1605Packed extends Struct { Pointer notEmpty; @Array(2) //# 1605: compile-time error Array nestedNotPacked; //# 1605: compile-time error } @Packed(1) class TestStruct1606Packed extends Struct { Pointer notEmpty; @Array(2) //# 1606: compile-time error Array nestedLooselyPacked; //# 1606: compile-time error } @Packed(0) //# 1607: compile-time error class TestStruct1607 extends Struct { Pointer notEmpty; } class TestStruct1800 extends Struct { Pointer notEmpty; @Array(-1) //# 1800: compile-time error Array inlineArray; //# 1800: compile-time error } class TestStruct1801 extends Struct { Pointer notEmpty; @Array(1, -1) //# 1801: compile-time error Array inlineArray; //# 1801: compile-time error } class TestStruct1802 extends Struct { Pointer notEmpty; @Array.multi([2, 2, 2, 2, 2, 2, -1]) //# 1802: compile-time error Array inlineArray; //# 1802: compile-time error }