[vm/ffi] Check Array<T extends Struct> bounds on []

TEST=tests/ffi/inline_array_test.dart

Bug: https://github.com/dart-lang/sdk/issues/54379
Change-Id: I2799056ce48fa8cfa590512b241fe72f61a07dbf
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/345060
Reviewed-by: Tess Strickland <sstrickl@google.com>
This commit is contained in:
Daco Harkes
2024-01-05 12:35:49 +00:00
committed by Commit Queue
parent d4f8f24dc8
commit cd9eaef675
2 changed files with 72 additions and 13 deletions
+43 -13
View File
@@ -938,14 +938,43 @@ mixin _FfiUseSiteTransformer on FfiTransformer {
final constructor = clazz.constructors
.firstWhere((c) => c.name == Name("#fromTypedDataBase"));
final typedDataBasePrime = typedDataBaseOffset(
getArrayTypedDataBaseField(NullCheck(node.arguments.positional[0])),
multiply(node.arguments.positional[1], inlineSizeOf(dartType)!),
inlineSizeOf(dartType)!,
dartType,
node.fileOffset);
final arrayVar = VariableDeclaration("#array",
initializer: NullCheck(node.arguments.positional[0]),
type: InterfaceType(arrayClass, Nullability.nonNullable),
isSynthesized: true)
..fileOffset = node.fileOffset;
final indexVar = VariableDeclaration("#index",
initializer: NullCheck(node.arguments.positional[1]),
type: coreTypes.intNonNullableRawType,
isSynthesized: true)
..fileOffset = node.fileOffset;
return ConstructorInvocation(constructor, Arguments([typedDataBasePrime]));
return BlockExpression(
Block([
arrayVar,
indexVar,
ExpressionStatement(InstanceInvocation(
InstanceAccessKind.Instance,
VariableGet(arrayVar),
arrayCheckIndex.name,
Arguments([VariableGet(indexVar)]),
interfaceTarget: arrayCheckIndex,
functionType: arrayCheckIndex.getterType as FunctionType,
)),
]),
ConstructorInvocation(
constructor,
Arguments([
typedDataBaseOffset(
getArrayTypedDataBaseField(VariableGet(arrayVar)),
multiply(VariableGet(indexVar), inlineSizeOf(dartType)!),
inlineSizeOf(dartType)!,
dartType,
node.fileOffset,
)
]),
),
);
}
/// Generates an expression that returns a new `Array<dartType>`.
@@ -1031,12 +1060,13 @@ mixin _FfiUseSiteTransformer on FfiTransformer {
arrayVar,
indexVar,
ExpressionStatement(InstanceInvocation(
InstanceAccessKind.Instance,
VariableGet(arrayVar),
arrayCheckIndex.name,
Arguments([VariableGet(indexVar)]),
interfaceTarget: arrayCheckIndex,
functionType: arrayCheckIndex.getterType as FunctionType)),
InstanceAccessKind.Instance,
VariableGet(arrayVar),
arrayCheckIndex.name,
Arguments([VariableGet(indexVar)]),
interfaceTarget: arrayCheckIndex,
functionType: arrayCheckIndex.getterType as FunctionType,
)),
singleElementSizeVar,
elementSizeVar,
offsetVar
+29
View File
@@ -19,6 +19,8 @@ void main() {
testToString();
testRange();
testRangeArrayOfPointer();
testRangeArrayOfArray();
testRangeArrayOfStruct();
}
void testSizeOf() {
@@ -109,3 +111,30 @@ final class StructWithArrayOfPointer extends Struct {
@Array(8)
external Array<Pointer<Uint8>> a0;
}
void testRangeArrayOfArray() {
final pointer = calloc<StructWithArrayArray>();
final struct = pointer.ref;
final array = struct.a0;
array[0] = array[1];
Expect.throws(() => array[-1]);
Expect.throws(() => array[-1] = array[1]);
Expect.throws(() => array[2]);
Expect.throws(() => array[2] = array[1]);
calloc.free(pointer);
}
final class StructWithArrayArray extends Struct {
@Array(2, 2)
external Array<Array<Uint8>> a0;
}
void testRangeArrayOfStruct() {
final pointer = calloc<Struct4BytesInlineArrayMultiDimensionalInt>();
final struct = pointer.ref;
final array = struct.a0[0];
print(array[0]);
Expect.throws(() => array[-1]);
Expect.throws(() => array[2]);
calloc.free(pointer);
}