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