[analyzer/ffi] Report non-const fromFunction argument

* Adds missing error to analyzer.
* Adds analyzer test.
* Adds analyzer/cfe negative test.
* Formats the analyzer/cfe negative tests file.

TEST=pkg/analyzer/lib/src/generated/ffi_verifier.dart
TEST=tests/ffi/vmspecific_static_checks_test.dart

Bug: https://github.com/dart-lang/sdk/issues/36780

Change-Id: Ibc2a3d1c3b4b4d8b2285605f084237a55253fb20
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/217007
Commit-Queue: Daco Harkes <dacoharkes@google.com>
Reviewed-by: Clement Skau <cskau@google.com>
This commit is contained in:
Daco Harkes
2021-10-15 11:21:23 +00:00
committed by commit-bot@chromium.org
parent 43d91dd031
commit be195ad329
4 changed files with 95 additions and 23 deletions
@@ -407,6 +407,24 @@ class FfiVerifier extends RecursiveAstVisitor<void> {
return false;
}
bool _isConst(Expression expr) {
if (expr is Literal) {
return true;
}
if (expr is Identifier) {
final staticElm = expr.staticElement;
if (staticElm is ConstVariableElement) {
return true;
}
if (staticElm is PropertyAccessorElementImpl) {
if (staticElm.variable is ConstVariableElement) {
return true;
}
}
}
return false;
}
/// Returns `true` if [nativeType] is a C type that has a size.
bool _isSized(DartType nativeType) {
switch (_primitiveNativeType(nativeType)) {
@@ -510,12 +528,13 @@ class FfiVerifier extends RecursiveAstVisitor<void> {
return false;
}
// Get the const bool value of `expr` if it exists.
// Return null if it isn't a const bool.
/// Get the const bool value of [expr] if it exists.
/// Return null if it isn't a const bool.
bool? _maybeGetBoolConstValue(Expression expr) {
if (expr is BooleanLiteral) {
return expr.value;
} else if (expr is Identifier) {
}
if (expr is Identifier) {
final staticElm = expr.staticElement;
if (staticElm is ConstVariableElement) {
return staticElm.computeConstantValue()?.toBoolValue();
@@ -897,23 +916,26 @@ class FfiVerifier extends RecursiveAstVisitor<void> {
FfiCode.MISSING_EXCEPTION_VALUE, node.methodName);
} else {
Expression e = node.argumentList.arguments[1];
// TODO(brianwilkerson) Validate that `e` is a constant expression.
if (!_validateCompatibleNativeType(e.typeOrThrow, R, true)) {
_errorReporter.reportErrorForNode(
FfiCode.MUST_BE_A_SUBTYPE, e, [e.staticType, R, 'fromFunction']);
}
if (!_isConst(e)) {
_errorReporter.reportErrorForNode(
FfiCode.ARGUMENT_MUST_BE_A_CONSTANT, e, ['exceptionalReturn']);
}
}
}
/// Ensure `isLeaf` is const as we need the value at compile time to know
/// which trampoline to generate.
void _validateIsLeafIsConst(MethodInvocation node) {
// Ensure `isLeaf` is const as we need the value at compile time to know
// which trampoline to generate.
final args = node.argumentList.arguments;
if (args.isNotEmpty) {
for (final arg in args) {
if (arg is NamedExpression) {
if (arg.element?.name == _isLeafParamName) {
if (_maybeGetBoolConstValue(arg.expression) == null) {
if (!_isConst(arg.expression)) {
_errorReporter.reportErrorForNode(
FfiCode.ARGUMENT_MUST_BE_A_CONSTANT,
arg.expression,
@@ -62,6 +62,20 @@ doThings(bool isLeaf) {
]);
}
test_FromFunctionExceptionReturn() async {
await assertErrorsInCode(r'''
import 'dart:ffi';
typedef NativeDoubleUnOp = Double Function(Double);
double myTimesThree(double d) => d * 3;
void testFromFunctionFunctionExceptionValueMustBeConst() {
final notAConst = 1.1;
Pointer.fromFunction<NativeDoubleUnOp>(myTimesThree, notAConst);
}
''', [
error(FfiCode.ARGUMENT_MUST_BE_A_CONSTANT, 250, 9),
]);
}
test_LookupFunctionIsLeaf() async {
await assertErrorsInCode(r'''
import 'dart:ffi';
+26 -8
View File
@@ -36,6 +36,7 @@ void main() {
testFromFunctionClosure();
testFromFunctionTearOff();
testFromFunctionAbstract();
testFromFunctionFunctionExceptionValueMustBeConst();
testLookupFunctionGeneric();
testLookupFunctionGeneric2();
testLookupFunctionWrongNativeFunctionSignature();
@@ -274,6 +275,12 @@ void testFromFunctionAbstract() {
testFromFunctionAbstract); //# 76: compile-time error
}
void testFromFunctionFunctionExceptionValueMustBeConst() {
final notAConst = 1.1;
Pointer<NativeFunction<NativeDoubleUnOp>> p;
p = Pointer.fromFunction(myTimesThree, notAConst); //# 77: compile-time error
}
void testLookupFunctionGeneric() {
Function generic<T extends Function>() {
DynamicLibrary l = dlopenPlatformSpecific("ffi_test_dynamic_library");
@@ -714,13 +721,16 @@ class TestStruct1405 extends Struct {
void testLookupFunctionIsLeafMustBeConst() {
bool notAConst = false;
DynamicLibrary l = dlopenPlatformSpecific("ffi_test_dynamic_library");
l.lookupFunction<NativeDoubleUnOp, DoubleUnOp>("timesFour", isLeaf:notAConst); //# 1500: compile-time error
l.lookupFunction< //# 1500: compile-time error
NativeDoubleUnOp, //# 1500: compile-time error
DoubleUnOp>("timesFour", //# 1500: compile-time error
isLeaf: notAConst); //# 1500: compile-time error
}
void testAsFunctionIsLeafMustBeConst() {
bool notAConst = false;
Pointer<NativeFunction<Int8UnOp>> p = Pointer.fromAddress(1337);
IntUnOp f = p.asFunction(isLeaf:notAConst); //# 1501: compile-time error
IntUnOp f = p.asFunction(isLeaf: notAConst); //# 1501: compile-time error
}
typedef NativeTakesHandle = Void Function(Handle);
@@ -728,12 +738,16 @@ typedef TakesHandle = void Function(Object);
void testLookupFunctionTakesHandle() {
DynamicLibrary l = dlopenPlatformSpecific("ffi_test_dynamic_library");
l.lookupFunction<NativeTakesHandle, TakesHandle>("takesHandle", isLeaf:true); //# 1502: compile-time error
l.lookupFunction< //# 1502: compile-time error
NativeTakesHandle, //# 1502: compile-time error
TakesHandle>("takesHandle", //# 1502: compile-time error
isLeaf: true); //# 1502: compile-time error
}
void testAsFunctionTakesHandle() {
Pointer<NativeFunction<NativeTakesHandle>> p = Pointer.fromAddress(1337); //# 1503: compile-time error
TakesHandle f = p.asFunction(isLeaf:true); //# 1503: compile-time error
Pointer<NativeFunction<NativeTakesHandle>> p = //# 1503: compile-time error
Pointer.fromAddress(1337); //# 1503: compile-time error
TakesHandle f = p.asFunction(isLeaf: true); //# 1503: compile-time error
}
typedef NativeReturnsHandle = Handle Function();
@@ -741,12 +755,16 @@ typedef ReturnsHandle = Object Function();
void testLookupFunctionReturnsHandle() {
DynamicLibrary l = dlopenPlatformSpecific("ffi_test_dynamic_library");
l.lookupFunction<NativeReturnsHandle, ReturnsHandle>("returnsHandle", isLeaf:true); //# 1504: compile-time error
l.lookupFunction< //# 1504: compile-time error
NativeReturnsHandle, //# 1504: compile-time error
ReturnsHandle>("returnsHandle", //# 1504: compile-time error
isLeaf: true); //# 1504: compile-time error
}
void testAsFunctionReturnsHandle() {
Pointer<NativeFunction<NativeReturnsHandle>> p = Pointer.fromAddress(1337); //# 1505: compile-time error
ReturnsHandle f = p.asFunction(isLeaf:true); //# 1505: compile-time error
Pointer<NativeFunction<NativeReturnsHandle>> p = //# 1505: compile-time error
Pointer.fromAddress(1337); //# 1505: compile-time error
ReturnsHandle f = p.asFunction(isLeaf: true); //# 1505: compile-time error
}
@Packed(1)
+26 -8
View File
@@ -38,6 +38,7 @@ void main() {
testFromFunctionClosure();
testFromFunctionTearOff();
testFromFunctionAbstract();
testFromFunctionFunctionExceptionValueMustBeConst();
testLookupFunctionGeneric();
testLookupFunctionGeneric2();
testLookupFunctionWrongNativeFunctionSignature();
@@ -276,6 +277,12 @@ void testFromFunctionAbstract() {
testFromFunctionAbstract); //# 76: compile-time error
}
void testFromFunctionFunctionExceptionValueMustBeConst() {
final notAConst = 1.1;
Pointer<NativeFunction<NativeDoubleUnOp>> p;
p = Pointer.fromFunction(myTimesThree, notAConst); //# 77: compile-time error
}
void testLookupFunctionGeneric() {
Function generic<T extends Function>() {
DynamicLibrary l = dlopenPlatformSpecific("ffi_test_dynamic_library");
@@ -714,13 +721,16 @@ class TestStruct1405 extends Struct {
void testLookupFunctionIsLeafMustBeConst() {
bool notAConst = false;
DynamicLibrary l = dlopenPlatformSpecific("ffi_test_dynamic_library");
l.lookupFunction<NativeDoubleUnOp, DoubleUnOp>("timesFour", isLeaf:notAConst); //# 1500: compile-time error
l.lookupFunction< //# 1500: compile-time error
NativeDoubleUnOp, //# 1500: compile-time error
DoubleUnOp>("timesFour", //# 1500: compile-time error
isLeaf: notAConst); //# 1500: compile-time error
}
void testAsFunctionIsLeafMustBeConst() {
bool notAConst = false;
Pointer<NativeFunction<Int8UnOp>> p = Pointer.fromAddress(1337);
IntUnOp f = p.asFunction(isLeaf:notAConst); //# 1501: compile-time error
IntUnOp f = p.asFunction(isLeaf: notAConst); //# 1501: compile-time error
}
typedef NativeTakesHandle = Void Function(Handle);
@@ -728,12 +738,16 @@ typedef TakesHandle = void Function(Object);
void testLookupFunctionTakesHandle() {
DynamicLibrary l = dlopenPlatformSpecific("ffi_test_dynamic_library");
l.lookupFunction<NativeTakesHandle, TakesHandle>("takesHandle", isLeaf:true); //# 1502: compile-time error
l.lookupFunction< //# 1502: compile-time error
NativeTakesHandle, //# 1502: compile-time error
TakesHandle>("takesHandle", //# 1502: compile-time error
isLeaf: true); //# 1502: compile-time error
}
void testAsFunctionTakesHandle() {
Pointer<NativeFunction<NativeTakesHandle>> p = Pointer.fromAddress(1337); //# 1503: compile-time error
TakesHandle f = p.asFunction(isLeaf:true); //# 1503: compile-time error
Pointer<NativeFunction<NativeTakesHandle>> p = //# 1503: compile-time error
Pointer.fromAddress(1337); //# 1503: compile-time error
TakesHandle f = p.asFunction(isLeaf: true); //# 1503: compile-time error
}
typedef NativeReturnsHandle = Handle Function();
@@ -741,12 +755,16 @@ typedef ReturnsHandle = Object Function();
void testLookupFunctionReturnsHandle() {
DynamicLibrary l = dlopenPlatformSpecific("ffi_test_dynamic_library");
l.lookupFunction<NativeReturnsHandle, ReturnsHandle>("returnsHandle", isLeaf:true); //# 1504: compile-time error
l.lookupFunction< //# 1504: compile-time error
NativeReturnsHandle, //# 1504: compile-time error
ReturnsHandle>("returnsHandle", //# 1504: compile-time error
isLeaf: true); //# 1504: compile-time error
}
void testAsFunctionReturnsHandle() {
Pointer<NativeFunction<NativeReturnsHandle>> p = Pointer.fromAddress(1337); //# 1505: compile-time error
ReturnsHandle f = p.asFunction(isLeaf:true); //# 1505: compile-time error
Pointer<NativeFunction<NativeReturnsHandle>> p = //# 1505: compile-time error
Pointer.fromAddress(1337); //# 1505: compile-time error
ReturnsHandle f = p.asFunction(isLeaf: true); //# 1505: compile-time error
}
@Packed(1)