Version 2.18.0-125.0.dev

Merge commit '4e520ec7a7ceb903da0c4ec04da7eeb635524748' into 'dev'
diff --git a/pkg/dart2native/lib/dart2native_macho.dart b/pkg/dart2native/lib/dart2native_macho.dart
index eefaf9d..1c45d13 100644
--- a/pkg/dart2native/lib/dart2native_macho.dart
+++ b/pkg/dart2native/lib/dart2native_macho.dart
@@ -265,6 +265,32 @@
   return numWritten;
 }
 
+class _MacOSVersion {
+  final int? _major;
+  final int? _minor;
+
+  static final _regexp = RegExp(r'Version (?<major>\d+).(?<minor>\d+)');
+  static const _parseFailure = 'Could not determine macOS version';
+
+  const _MacOSVersion._internal(this._major, this._minor);
+
+  static const _unknown = _MacOSVersion._internal(null, null);
+
+  factory _MacOSVersion() {
+    if (!Platform.isMacOS) return _unknown;
+    final match =
+        _regexp.matchAsPrefix(Platform.operatingSystemVersion) as RegExpMatch?;
+    if (match == null) return _unknown;
+    final minor = int.tryParse(match.namedGroup('minor')!);
+    final major = int.tryParse(match.namedGroup('major')!);
+    return _MacOSVersion._internal(major, minor);
+  }
+
+  bool get isValid => _major != null;
+  int get major => _major ?? (throw _parseFailure);
+  int get minor => _minor ?? (throw _parseFailure);
+}
+
 // Writes an "appended" dart runtime + script snapshot file in a format
 // compatible with MachO executables.
 Future writeAppendedMachOExecutable(
@@ -312,17 +338,39 @@
   await stream.close();
 
   if (machOFile.hasCodeSignature) {
+    if (!Platform.isMacOS) {
+      throw 'Cannot sign MachO binary on non-macOS platform';
+    }
+
     // After writing the modified file, we perform ad-hoc signing (no identity)
-    // similar to the linker (the linker-signed option flag) to ensure that any
-    // LC_CODE_SIGNATURE block has the correct CD hashes. This is necessary for
-    // platforms where signature verification is always on (e.g., OS X on M1).
+    // to ensure that any LC_CODE_SIGNATURE block has the correct CD hashes.
+    // This is necessary for platforms where signature verification is always on
+    // (e.g., OS X on M1).
     //
     // We use the `-f` flag to force signature overwriting as the official
     // Dart binaries (including dartaotruntime) are fully signed.
-    final signingProcess = await Process.run(
-        'codesign', ['-f', '-o', 'linker-signed', '-s', '-', outputPath]);
+    final args = ['-f', '-s', '-', outputPath];
+
+    // If running on macOS >=11.0, then the linker-signed option flag can be
+    // used to create a signature that does not need to be force overridden.
+    final version = _MacOSVersion();
+    if (version.isValid && version.major >= 11) {
+      final signingProcess =
+          await Process.run('codesign', ['-o', 'linker-signed', ...args]);
+      if (signingProcess.exitCode == 0) {
+        return;
+      }
+      print('Failed to add a linker signed signature, '
+          'adding a regular signature instead.');
+    }
+
+    // If that fails or we're running on an older or undetermined version of
+    // macOS, we fall back to signing without the linker-signed option flag.
+    // Thus, to sign the binary, the developer must force signature overwriting.
+    final signingProcess = await Process.run('codesign', args);
     if (signingProcess.exitCode != 0) {
-      print('Subcommand terminated with exit code ${signingProcess.exitCode}.');
+      print('Failed to replace the dartaotruntime signature, ');
+      print('subcommand terminated with exit code ${signingProcess.exitCode}.');
       if (signingProcess.stdout.isNotEmpty) {
         print('Subcommand stdout:');
         print(signingProcess.stdout);
diff --git a/pkg/dartdev/test/commands/compile_test.dart b/pkg/dartdev/test/commands/compile_test.dart
index e5c15b0..0d497b4 100644
--- a/pkg/dartdev/test/commands/compile_test.dart
+++ b/pkg/dartdev/test/commands/compile_test.dart
@@ -187,7 +187,7 @@
     expect(result.stdout, contains('2: foo'));
   });
 
-  test('Compile and run executable', () async {
+  Future<void> basicCompileTest() async {
     final p = project(mainSrc: 'void main() { print("I love executables"); }');
     final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
     final outFile = path.canonicalize(path.join(p.dirPath, 'lib', 'main.exe'));
@@ -213,7 +213,9 @@
     expect(result.stderr, isEmpty);
     expect(result.exitCode, 0);
     expect(result.stdout, contains('I love executables'));
-  }, skip: isRunningOnIA32);
+  }
+
+  test('Compile and run executable', basicCompileTest, skip: isRunningOnIA32);
 
   test('Compile to executable disabled on IA32', () async {
     final p = project(mainSrc: 'void main() { print("I love executables"); }');
@@ -1112,4 +1114,33 @@
     expect(result.stderr, contains('Warning:'));
     expect(result.exitCode, 0);
   });
+
+  if (Platform.isMacOS) {
+    test('Compile and run executable from signed dartaotruntime', () async {
+      // Either the locally built dartaotruntime is already linker signed
+      // (on M1) or it is unsigned (on X64). For this test, sign the
+      // dartaotruntime executable with a non-linker signed adhoc signature,
+      // which won't cause issues with any other tests that use it. This
+      // ensures the code signing path in dart2native is exercised on X64
+      // (macOS <11.0), and also mimics the case for end users that are using
+      // the published Dart SDK (which is fully signed, not linker signed).
+      final Directory binDir = File(Platform.resolvedExecutable).parent;
+      final String originalRuntimePath =
+          path.join(binDir.path, 'dartaotruntime');
+      final codeSigningProcess = await Process.start('codesign', [
+        '-o',
+        'runtime',
+        '-s',
+        '-',
+        originalRuntimePath,
+      ]);
+
+      final signingResult = await codeSigningProcess.exitCode;
+      expect(signingResult, 0);
+
+      // Now perform the same basic compile and run test with the signed
+      // dartaotruntime.
+      await basicCompileTest();
+    }, skip: isRunningOnIA32);
+  }
 }
diff --git a/tools/VERSION b/tools/VERSION
index c4339e4..0ba49e7 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 18
 PATCH 0
-PRERELEASE 124
+PRERELEASE 125
 PRERELEASE_PATCH 0
\ No newline at end of file