[vm/ffi] Array dimensions non-positive check in CFE

Bug: https://github.com/dart-lang/sdk/issues/45540
Closes: https://github.com/dart-lang/sdk/pull/45785

TEST=tests/ffi/vmspecific_static_checks_test.dart

GitOrigin-RevId: e4c091a617acf36f60de7ddfc957a58323663813
Change-Id: I393e1dbbf34aa9f72e2e942c3a40c2f37c90e0c4
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/196246
Reviewed-by: Daco Harkes <dacoharkes@google.com>
Commit-Queue: Daco Harkes <dacoharkes@google.com>
diff --git a/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart b/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
index b1cb812..eed68f4 100644
--- a/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
@@ -7277,6 +7277,15 @@
         r"""Try removing the other directives, or moving them to the library for which this is a part.""");
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Null> codeNonPositiveArrayDimensions =
+    messageNonPositiveArrayDimensions;
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const MessageCode messageNonPositiveArrayDimensions = const MessageCode(
+    "NonPositiveArrayDimensions",
+    message: r"""Array dimensions must be positive numbers.""");
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Template<Message Function(String name)>
     templateNonSimpleBoundViaReference =
     const Template<Message Function(String name)>(
diff --git a/pkg/front_end/lib/src/api_unstable/vm.dart b/pkg/front_end/lib/src/api_unstable/vm.dart
index bf01283..b2250cf 100644
--- a/pkg/front_end/lib/src/api_unstable/vm.dart
+++ b/pkg/front_end/lib/src/api_unstable/vm.dart
@@ -53,6 +53,7 @@
         messageFfiExceptionalReturnNull,
         messageFfiExpectedConstant,
         messageFfiPackedAnnotationAlignment,
+        messageNonPositiveArrayDimensions,
         noLength,
         templateFfiDartTypeMismatch,
         templateFfiEmptyStruct,
diff --git a/pkg/front_end/messages.status b/pkg/front_end/messages.status
index 23e753f..9c7263d 100644
--- a/pkg/front_end/messages.status
+++ b/pkg/front_end/messages.status
@@ -606,6 +606,7 @@
 NonNullableOptOutImplicit/example: Fail
 NonPartOfDirectiveInPart/part_wrapped_script1: Fail
 NonPartOfDirectiveInPart/script1: Fail
+NonPositiveArrayDimensions/analyzerCode: Fail
 NotAConstantExpression/example: Fail
 NotAType/example: Fail
 NotAnLvalue/example: Fail
diff --git a/pkg/front_end/messages.yaml b/pkg/front_end/messages.yaml
index e5d851a..82ad1a1 100644
--- a/pkg/front_end/messages.yaml
+++ b/pkg/front_end/messages.yaml
@@ -4646,6 +4646,11 @@
       <int>[...null];
     }
 
+NonPositiveArrayDimensions:
+  # Used by dart:ffi
+  template: "Array dimensions must be positive numbers."
+  external: test/ffi_test.dart
+
 InvalidTypeVariableInSupertype:
   template: "Can't use implicitly 'out' variable '#name' in an '#string2' position in supertype '#name2'."
   script: >
diff --git a/pkg/vm/lib/transformations/ffi_definitions.dart b/pkg/vm/lib/transformations/ffi_definitions.dart
index 6dc8a46..beed450 100644
--- a/pkg/vm/lib/transformations/ffi_definitions.dart
+++ b/pkg/vm/lib/transformations/ffi_definitions.dart
@@ -9,6 +9,7 @@
 import 'package:front_end/src/api_unstable/vm.dart'
     show
         messageFfiPackedAnnotationAlignment,
+        messageNonPositiveArrayDimensions,
         templateFfiEmptyStruct,
         templateFfiFieldAnnotation,
         templateFfiFieldNull,
@@ -323,7 +324,8 @@
               compoundClassDependencies[node].add(clazz);
               _checkPacking(node, packing, clazz, f);
             }
-            if (arrayDimensions(type) != sizeAnnotations.single.length) {
+            final dimensions = sizeAnnotations.single;
+            if (arrayDimensions(type) != dimensions.length) {
               diagnosticReporter.report(
                   templateFfiSizeAnnotationDimensions
                       .withArguments(f.name.text),
@@ -331,6 +333,15 @@
                   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 {
             diagnosticReporter.report(
                 templateFfiSizeAnnotation.withArguments(f.name.text),
@@ -478,8 +489,8 @@
         final sizeAnnotations = _getArraySizeAnnotations(m).toList();
         if (sizeAnnotations.length == 1) {
           final arrayDimensions = sizeAnnotations.single;
-          type = NativeTypeCfe(this, dartType,
-              compoundCache: compoundCache, arrayDimensions: arrayDimensions);
+          type = NativeTypeCfe(this, dartType, compoundCache: compoundCache,
+              arrayDimensions: arrayDimensions);
         }
       } else if (isPointerType(dartType) || isCompoundSubtype(dartType)) {
         type = NativeTypeCfe(this, dartType, compoundCache: compoundCache);
@@ -749,7 +760,7 @@
 abstract class NativeTypeCfe {
   factory NativeTypeCfe(FfiTransformer transformer, DartType dartType,
       {List<int> arrayDimensions,
-      Map<Class, CompoundNativeTypeCfe> compoundCache = const {}}) {
+        Map<Class, CompoundNativeTypeCfe> compoundCache = const {}}) {
     if (transformer.isPrimitiveType(dartType)) {
       final clazz = (dartType as InterfaceType).classNode;
       final nativeType = transformer.getType(clazz);
@@ -772,7 +783,7 @@
       }
       final elementType = transformer.arraySingleElementType(dartType);
       final elementCfeType =
-          NativeTypeCfe(transformer, elementType, compoundCache: compoundCache);
+      NativeTypeCfe(transformer, elementType, compoundCache: compoundCache);
       return ArrayNativeTypeCfe.multi(elementCfeType, arrayDimensions);
     }
     throw "Invalid type $dartType";
@@ -1135,8 +1146,8 @@
 
   ArrayNativeTypeCfe(this.elementType, this.length);
 
-  factory ArrayNativeTypeCfe.multi(
-      NativeTypeCfe elementType, List<int> dimensions) {
+  factory ArrayNativeTypeCfe.multi(NativeTypeCfe elementType,
+      List<int> dimensions) {
     if (dimensions.length == 1) {
       return ArrayNativeTypeCfe(elementType, dimensions.single);
     }
diff --git a/tests/ffi/vmspecific_static_checks_test.dart b/tests/ffi/vmspecific_static_checks_test.dart
index 72636d8..4998b31 100644
--- a/tests/ffi/vmspecific_static_checks_test.dart
+++ b/tests/ffi/vmspecific_static_checks_test.dart
@@ -760,3 +760,24 @@
   external Array<TestStruct1604> //# 1606: compile-time error
       nestedLooselyPacked; //# 1606: compile-time error
 }
+
+class TestStruct1800 extends Struct {
+  external Pointer<Uint8> notEmpty;
+
+  @Array(-1) //# 1800: compile-time error
+  external Array<Uint8> inlineArray; //# 1800: compile-time error
+}
+
+class TestStruct1801 extends Struct {
+  external Pointer<Uint8> notEmpty;
+
+  @Array(1, -1) //# 1801: compile-time error
+  external Array<Uint8> inlineArray; //# 1801: compile-time error
+}
+
+class TestStruct1802 extends Struct {
+  external Pointer<Uint8> notEmpty;
+
+  @Array.multi([2, 2, 2, 2, 2, 2, -1]) //# 1802: compile-time error
+  external Array<Uint8> inlineArray; //# 1802: compile-time error
+}
\ No newline at end of file
diff --git a/tests/ffi_2/vmspecific_static_checks_test.dart b/tests/ffi_2/vmspecific_static_checks_test.dart
index 48e85b8..a81e206 100644
--- a/tests/ffi_2/vmspecific_static_checks_test.dart
+++ b/tests/ffi_2/vmspecific_static_checks_test.dart
@@ -759,3 +759,24 @@
   @Array(2) //# 1606: compile-time error
   Array<TestStruct1604> nestedLooselyPacked; //# 1606: compile-time error
 }
+
+class TestStruct1800 extends Struct {
+  Pointer<Uint8> notEmpty;
+
+  @Array(-1) //# 1800: compile-time error
+  Array<Uint8> inlineArray; //# 1800: compile-time error
+}
+
+class TestStruct1801 extends Struct {
+  Pointer<Uint8> notEmpty;
+
+  @Array(1, -1) //# 1801: compile-time error
+  Array<Uint8> inlineArray; //# 1801: compile-time error
+}
+
+class TestStruct1802 extends Struct {
+  Pointer<Uint8> notEmpty;
+
+  @Array.multi([2, 2, 2, 2, 2, 2, -1]) //# 1802: compile-time error
+  Array<Uint8> inlineArray; //# 1802: compile-time error
+}
\ No newline at end of file