[cfe/ffi] Handle invalid types in Array

Closes: https://github.com/dart-lang/sdk/issues/47673

TEST=tests/ffi(_2)/regress_47673(_2)_test.dart

Change-Id: I8fdafc5378797ed071250b0caed1ab944873a218
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/220760
Commit-Queue: Daco Harkes <dacoharkes@google.com>
Reviewed-by: Clement Skau <cskau@google.com>
Reviewed-by: Chloe Stefantsova <cstefantsova@google.com>
This commit is contained in:
Daco Harkes 2021-11-19 13:38:47 +00:00 committed by commit-bot@chromium.org
parent 1ade4ab96f
commit 00ea62f713
6 changed files with 127 additions and 26 deletions

View file

@ -725,10 +725,16 @@ class FfiTransformer extends Transformer {
/// Returns the single element type nested type argument of `Array`.
///
/// `Array<Array<Array<Int8>>>` -> `Int8`.
///
/// `Array<Array<Array<Unknown>>>` -> [InvalidType].
DartType arraySingleElementType(DartType dartType) {
InterfaceType elementType = dartType as InterfaceType;
while (elementType.classNode == arrayClass) {
elementType = elementType.typeArguments[0] as InterfaceType;
final elementTypeAny = elementType.typeArguments[0];
if (elementTypeAny is InvalidType) {
return elementTypeAny;
}
elementType = elementTypeAny as InterfaceType;
}
return elementType;
}
@ -736,11 +742,14 @@ class FfiTransformer extends Transformer {
/// Returns the number of dimensions of `Array`.
///
/// `Array<Array<Array<Int8>>>` -> 3.
///
/// `Array<Array<Array<Unknown>>>` -> 3.
int arrayDimensions(DartType dartType) {
InterfaceType elementType = dartType as InterfaceType;
DartType elementType = dartType;
int dimensions = 0;
while (elementType.classNode == arrayClass) {
elementType = elementType.typeArguments[0] as InterfaceType;
while (
elementType is InterfaceType && elementType.classNode == arrayClass) {
elementType = elementType.typeArguments[0];
dimensions++;
}
return dimensions;

View file

@ -146,8 +146,9 @@ class _FfiDefinitionTransformer extends FfiTransformer {
final sizeAnnotations = _getArraySizeAnnotations(f);
if (sizeAnnotations.length == 1) {
final singleElementType = arraySingleElementType(type);
if (isCompoundSubtype(singleElementType)) {
final clazz = (singleElementType as InterfaceType).classNode;
if (singleElementType is InterfaceType &&
isCompoundSubtype(singleElementType)) {
final clazz = singleElementType.classNode;
dependencies.add(clazz);
}
}
@ -403,24 +404,31 @@ class _FfiDefinitionTransformer extends FfiTransformer {
final sizeAnnotations = _getArraySizeAnnotations(f);
if (sizeAnnotations.length == 1) {
final singleElementType = arraySingleElementType(type);
if (isCompoundSubtype(singleElementType)) {
final clazz = (singleElementType as InterfaceType).classNode;
_checkPacking(node, packing, clazz, f);
}
final dimensions = sizeAnnotations.single;
if (arrayDimensions(type) != dimensions.length) {
diagnosticReporter.report(
templateFfiSizeAnnotationDimensions
.withArguments(f.name.text),
f.fileOffset,
f.name.text.length,
f.fileUri);
}
for (var dimension in dimensions) {
if (dimension < 0) {
diagnosticReporter.report(messageNonPositiveArrayDimensions,
f.fileOffset, f.name.text.length, f.fileUri);
success = false;
if (singleElementType is! InterfaceType) {
assert(singleElementType is InvalidType);
// This class is invalid, but continue reporting other errors on it.
// An error on the type will already have been reported.
success = false;
} else {
if (isCompoundSubtype(singleElementType)) {
final clazz = singleElementType.classNode;
_checkPacking(node, packing, clazz, f);
}
final dimensions = sizeAnnotations.single;
if (arrayDimensions(type) != dimensions.length) {
diagnosticReporter.report(
templateFfiSizeAnnotationDimensions
.withArguments(f.name.text),
f.fileOffset,
f.name.text.length,
f.fileUri);
}
for (var dimension in dimensions) {
if (dimension < 0) {
diagnosticReporter.report(messageNonPositiveArrayDimensions,
f.fileOffset, f.name.text.length, f.fileUri);
success = false;
}
}
}
} else {
@ -568,8 +576,15 @@ class _FfiDefinitionTransformer extends FfiTransformer {
if (sizeAnnotations.length == 1) {
final arrayDimensions = sizeAnnotations.single;
if (this.arrayDimensions(dartType) == arrayDimensions.length) {
type = NativeTypeCfe(this, dartType,
compoundCache: compoundCache, arrayDimensions: arrayDimensions);
final elementType = arraySingleElementType(dartType);
if (elementType is! InterfaceType) {
assert(elementType is InvalidType);
type = InvalidNativeTypeCfe("Invalid element type.");
} else {
type = NativeTypeCfe(this, dartType,
compoundCache: compoundCache,
arrayDimensions: arrayDimensions);
}
} else {
type = InvalidNativeTypeCfe("Invalid array dimensions.");
}

View file

@ -0,0 +1,18 @@
// Copyright (c) 2021, 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.
//
// SharedObjects=ffi_test_functions
import 'dart:ffi';
class A extends Struct {
@Array.multi([16])
external Array<Int8> a;
// This should not crash the FFI transform.
@Array.multi([16]) //# 1: compile-time error
external Array<Unknown> b; //# 1: compile-time error
}
main() {}

View file

@ -0,0 +1,16 @@
// Copyright (c) 2021, 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.
//
// SharedObjects=ffi_test_functions
import 'dart:ffi';
typedef T = Int64;
class A extends Struct {
@Array.multi([16])
external Array<T> b;
}
main() {}

View file

@ -0,0 +1,20 @@
// Copyright (c) 2021, 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.
//
// SharedObjects=ffi_test_functions
// @dart=2.9
import 'dart:ffi';
class A extends Struct {
@Array.multi([16])
Array<Int8> a;
// This should not crash the FFI transform.
@Array.multi([16]) //# 1: compile-time error
Array<Unknown> b; //# 1: compile-time error
}
main() {}

View file

@ -0,0 +1,23 @@
// Copyright (c) 2021, 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.
//
// SharedObjects=ffi_test_functions
// @dart=2.9
import 'dart:ffi';
typedef T = Int64; //# 1: compile-time error
class A extends Struct {
@Array.multi([16])
Array<Int8> a;
// In language version 2.12 we do not support non-function typedefs.
// This should not crash the FFI transform.
@Array.multi([16]) //# 1: compile-time error
Array<T> b; //# 1: compile-time error
}
main() {}