1
0
mirror of https://github.com/dart-lang/sdk synced 2024-07-03 00:08:46 +00:00

Reland "[SDK] Adds an SDK hash to kernels and the VM."

Note: This is a reland of https://dart-review.googlesource.com/c/sdk/+/150343

Adds a new SDK hash to kernels and the VM which is optionally checked
to verify kernels are built for the same SDK as the VM.
This helps catch incompatibilities that are currently causing
subtle bugs and (not so subtle) crashes.

The SDK hash is encoded in kernels as a new field in components.
The hash is derived from the 10 byte git short hash.

This new check can be disabled via:
  tools/gn.py ... --no-verify-sdk-hash

This CL bumps the min. (and max.) supported kernel format version,
making the VM backwards incompatible from this point back.

This also bumps the min. and current ABI version.

Bug: https://github.com/dart-lang/sdk/issues/41802
Change-Id: I2f85945045a603eb9dcfd1f2c0d0d024bd84a956
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/152802
Commit-Queue: Clement Skau <cskau@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
This commit is contained in:
Clement Skau 2020-07-07 06:08:20 +00:00 committed by commit-bot@chromium.org
parent 315ecf2606
commit 0ce83987d6
28 changed files with 507 additions and 194 deletions

2
DEPS
View File

@ -512,7 +512,7 @@ deps = {
"packages": [
{
"package": "dart/cfe/dart2js_dills",
"version": "binary_version:42",
"version": "binary_version:43_2",
}
],
"dep_type": "cipd",

View File

@ -473,31 +473,33 @@ class BinaryMdDillReader {
type = type.substring(0, type.indexOf("["));
type = _lookupGenericType(typeNames, type, types);
int intCount = -1;
if (vars[count] != null && vars[count] is int) {
intCount = vars[count];
} else if (count.contains(".")) {
List<String> countData =
count.split(regExpSplit).map((s) => s.trim()).toList();
if (vars[countData[0]] != null) {
dynamic v = vars[countData[0]];
if (v is Map &&
countData[1] == "last" &&
v["items"] is List &&
v["items"].last is int) {
intCount = v["items"].last;
} else if (v is Map && v[countData[1]] != null) {
v = v[countData[1]];
if (v is Map && v[countData[2]] != null) {
v = v[countData[2]];
if (v is int) intCount = v;
} else if (v is int &&
countData.length == 4 &&
countData[2] == "+") {
intCount = v + int.parse(countData[3]);
int intCount = int.tryParse(count) ?? -1;
if (intCount == -1) {
if (vars[count] != null && vars[count] is int) {
intCount = vars[count];
} else if (count.contains(".")) {
List<String> countData =
count.split(regExpSplit).map((s) => s.trim()).toList();
if (vars[countData[0]] != null) {
dynamic v = vars[countData[0]];
if (v is Map &&
countData[1] == "last" &&
v["items"] is List &&
v["items"].last is int) {
intCount = v["items"].last;
} else if (v is Map && v[countData[1]] != null) {
v = v[countData[1]];
if (v is Map && v[countData[2]] != null) {
v = v[countData[2]];
if (v is int) intCount = v;
} else if (v is int &&
countData.length == 4 &&
countData[2] == "+") {
intCount = v + int.parse(countData[3]);
}
} else {
throw "Unknown dot to int ($count)";
}
} else {
throw "Unknown dot to int ($count)";
}
}
}

View File

@ -314,6 +314,7 @@ disallow
disambiguator
disjoint
dispatched
distribute
divided
dmitryas
doc
@ -326,6 +327,7 @@ downloaded
downloading
dq
dquote
dsdk
dst
dummy
dupdate
@ -437,12 +439,14 @@ futured
futureor
g
gardening
gen
generation
gets
getter1a
getter1b
getting
gft
git
github
glb
glob

View File

@ -143,7 +143,8 @@ type CanonicalName {
type ComponentFile {
UInt32 magic = 0x90ABCDEF;
UInt32 formatVersion = 42;
UInt32 formatVersion = 43;
Byte[10] shortSdkHash;
List<String> problemsAsJson; // Described in problems.md.
Library[] libraries;
UriSource sourceMap;

View File

@ -5,6 +5,7 @@ library kernel.ast_from_binary;
import 'dart:core' hide MapEntry;
import 'dart:developer';
import 'dart:convert';
import 'dart:typed_data';
import '../ast.dart';
@ -28,11 +29,22 @@ class InvalidKernelVersionError {
InvalidKernelVersionError(this.version);
String toString() {
return 'Unexpected Kernel version ${version} '
return 'Unexpected Kernel Format Version ${version} '
'(expected ${Tag.BinaryFormatVersion}).';
}
}
class InvalidKernelSdkVersionError {
final String version;
InvalidKernelSdkVersionError(this.version);
String toString() {
return 'Unexpected Kernel SDK Version ${version} '
'(expected ${expectedSdkHash}).';
}
}
class CompilationModeError {
final String message;
@ -484,6 +496,13 @@ class BinaryBuilder {
if (_bytes.length == 0) throw new StateError("Empty input given.");
}
void _readAndVerifySdkHash() {
final sdkHash = ascii.decode(readBytes(sdkHashLength));
if (!isValidSdkHash(sdkHash)) {
throw InvalidKernelSdkVersionError(sdkHash);
}
}
/// Deserializes a kernel component and stores it in [component].
///
/// When linking with a non-empty component, canonical names must have been
@ -511,6 +530,9 @@ class BinaryBuilder {
if (version != Tag.BinaryFormatVersion) {
throw InvalidKernelVersionError(version);
}
_readAndVerifySdkHash();
_byteOffset = offset;
List<int> componentFileSizes = _indexComponents();
if (componentFileSizes.length > 1) {
@ -694,6 +716,8 @@ class BinaryBuilder {
throw InvalidKernelVersionError(formatVersion);
}
_readAndVerifySdkHash();
// Read component index from the end of this ComponentFiles serialized data.
_ComponentIndex index = _readComponentIndex(componentFileSize);
@ -718,6 +742,8 @@ class BinaryBuilder {
throw InvalidKernelVersionError(formatVersion);
}
_readAndVerifySdkHash();
List<String> problemsAsJson = readListOfStrings();
if (problemsAsJson != null) {
component.problemsAsJson ??= <String>[];

View File

@ -4,6 +4,7 @@
library kernel.ast_to_binary;
import 'dart:core' hide MapEntry;
import 'dart:convert';
import 'dart:developer';
import 'dart:io' show BytesBuilder;
import 'dart:typed_data';
@ -537,6 +538,7 @@ class BinaryPrinter implements Visitor<void>, BinarySink {
final componentOffset = getBufferOffset();
writeUInt32(Tag.ComponentFile);
writeUInt32(Tag.BinaryFormatVersion);
writeBytes(ascii.encode(expectedSdkHash));
writeListOfStrings(component.problemsAsJson);
indexLinkTable(component);
_collectMetadata(component);

View File

@ -149,7 +149,7 @@ class Tag {
/// Internal version of kernel binary format.
/// Bump it when making incompatible changes in kernel binaries.
/// Keep in sync with runtime/vm/kernel_binary.h, pkg/kernel/binary.md.
static const int BinaryFormatVersion = 42;
static const int BinaryFormatVersion = 43;
}
abstract class ConstantTag {
@ -169,3 +169,27 @@ abstract class ConstantTag {
static const int UnevaluatedConstant = 12;
// 13 is occupied by [SetConstant]
}
const int sdkHashLength = 10; // Bytes, a Git "short hash".
const String sdkHashNull = '0000000000';
// Will be correct hash for Flutter SDK / Dart SDK we distribute.
// If non-null we will validate when consuming kernel, will use when producing
// kernel.
// If null, local development setting (e.g. run gen_kernel.dart from source),
// we put 0x00..00 into when producing, do not validate when consuming.
String get expectedSdkHash {
final sdkHash =
const String.fromEnvironment('sdk_hash', defaultValue: sdkHashNull);
if (sdkHash.length != sdkHashLength) {
throw '-Dsdk_hash=<hash> must be a ${sdkHashLength} byte string!';
}
return sdkHash;
}
bool isValidSdkHash(String sdkHash) {
return (sdkHash == sdkHashNull ||
expectedSdkHash == sdkHashNull ||
sdkHash == expectedSdkHash);
}

View File

@ -964,9 +964,11 @@ prebuilt_dart_action("gen_kernel_bytecode_dill") {
abs_depfile = rebase_path(depfile)
rebased_output = rebase_path(output, root_build_dir)
vm_args = [
"--depfile=$abs_depfile",
"--depfile_output_filename=$rebased_output",
"-Dsdk_hash=$sdk_hash",
]
args = [

View File

@ -0,0 +1,88 @@
// Copyright (c) 2020, 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.
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';
import 'package:path/path.dart' as path;
import 'package:expect/expect.dart';
import 'snapshot_test_helper.dart';
// Keep in sync with pkg/kernel/lib/binary/tag.dart:
const tagComponentFile = [0x90, 0xAB, 0xCD, 0xEF];
const tagBinaryFormatVersion = [0x00, 0x00, 0x00, 43];
Future<void> main(List<String> args) async {
if (args.length == 1 && args[0] == '--child') {
print('Hello, SDK Hash!');
return;
}
final String sourcePath =
path.join('runtime', 'tests', 'vm', 'dart_2', 'sdk_hash_test.dart');
await withTempDir((String tmp) async {
final String dillPath = path.join(tmp, 'test.dill');
{
final result = await Process.run(dart, [
genKernel,
'--platform',
platformDill,
'-o',
dillPath,
sourcePath,
]);
Expect.equals('', result.stderr);
Expect.equals(0, result.exitCode);
Expect.equals('', result.stdout);
}
{
final result = await Process.run(dart, [dillPath, '--child']);
Expect.equals('', result.stderr);
Expect.equals(0, result.exitCode);
Expect.equals('Hello, SDK Hash!', result.stdout.trim());
}
// Invalidate the SDK hash in the kernel dill:
{
final myFile = File(dillPath);
Uint8List bytes = myFile.readAsBytesSync();
// The SDK Hash is located after the ComponentFile and BinaryFormatVersion
// tags (both UInt32).
Expect.listEquals(tagComponentFile, bytes.sublist(0, 4));
Expect.listEquals(tagBinaryFormatVersion, bytes.sublist(4, 8));
// Flip the first byte in the hash:
bytes[8] ^= bytes[8];
myFile.writeAsBytesSync(bytes);
}
{
final result = await Process.run(dart, [dillPath, '--child']);
Expect.equals(
'Can\'t load Kernel binary: Invalid SDK hash.', result.stderr.trim());
Expect.equals(253, result.exitCode);
Expect.equals('', result.stdout);
}
// Zero out the SDK hash in the kernel dill to disable the check:
{
final myFile = File(dillPath);
Uint8List bytes = myFile.readAsBytesSync();
bytes.setRange(8, 18, ascii.encode('0000000000'));
myFile.writeAsBytesSync(bytes);
}
{
final result = await Process.run(dart, [dillPath, '--child']);
Expect.equals('', result.stderr);
Expect.equals(0, result.exitCode);
Expect.equals('Hello, SDK Hash!', result.stdout.trim());
}
});
}

View File

@ -48,6 +48,7 @@ final String executableSuffix = Platform.isWindows ? ".exe" : "";
final String buildDir = p.dirname(Platform.executable);
final String platformDill = p.join(buildDir, "vm_platform_strong.dill");
final String genSnapshot = p.join(buildDir, "gen_snapshot${executableSuffix}");
final String dart = p.join(buildDir, "dart${executableSuffix}");
final String dartPrecompiledRuntime =
p.join(buildDir, "dart_precompiled_runtime${executableSuffix}");
final String genKernel = p.join("pkg", "vm", "bin", "gen_kernel.dart");

View File

@ -0,0 +1,88 @@
// Copyright (c) 2020, 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.
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';
import 'package:path/path.dart' as path;
import 'package:expect/expect.dart';
import 'snapshot_test_helper.dart';
// Keep in sync with pkg/kernel/lib/binary/tag.dart:
const tagComponentFile = [0x90, 0xAB, 0xCD, 0xEF];
const tagBinaryFormatVersion = [0x00, 0x00, 0x00, 43];
Future<void> main(List<String> args) async {
if (args.length == 1 && args[0] == '--child') {
print('Hello, SDK Hash!');
return;
}
final String sourcePath =
path.join('runtime', 'tests', 'vm', 'dart_2', 'sdk_hash_test.dart');
await withTempDir((String tmp) async {
final String dillPath = path.join(tmp, 'test.dill');
{
final result = await Process.run(dart, [
genKernel,
'--platform',
platformDill,
'-o',
dillPath,
sourcePath,
]);
Expect.equals('', result.stderr);
Expect.equals(0, result.exitCode);
Expect.equals('', result.stdout);
}
{
final result = await Process.run(dart, [dillPath, '--child']);
Expect.equals('', result.stderr);
Expect.equals(0, result.exitCode);
Expect.equals('Hello, SDK Hash!', result.stdout.trim());
}
// Invalidate the SDK hash in the kernel dill:
{
final myFile = File(dillPath);
Uint8List bytes = myFile.readAsBytesSync();
// The SDK Hash is located after the ComponentFile and BinaryFormatVersion
// tags (both UInt32).
Expect.listEquals(tagComponentFile, bytes.sublist(0, 4));
Expect.listEquals(tagBinaryFormatVersion, bytes.sublist(4, 8));
// Flip the first byte in the hash:
bytes[8] ^= bytes[8];
myFile.writeAsBytesSync(bytes);
}
{
final result = await Process.run(dart, [dillPath, '--child']);
Expect.equals(
'Can\'t load Kernel binary: Invalid SDK hash.', result.stderr.trim());
Expect.equals(253, result.exitCode);
Expect.equals('', result.stdout);
}
// Zero out the SDK hash in the kernel dill to disable the check:
{
final myFile = File(dillPath);
Uint8List bytes = myFile.readAsBytesSync();
bytes.setRange(8, 18, ascii.encode('0000000000'));
myFile.writeAsBytesSync(bytes);
}
{
final result = await Process.run(dart, [dillPath, '--child']);
Expect.equals('', result.stderr);
Expect.equals(0, result.exitCode);
Expect.equals('Hello, SDK Hash!', result.stdout.trim());
}
});
}

View File

@ -48,6 +48,7 @@ final String executableSuffix = Platform.isWindows ? ".exe" : "";
final String buildDir = p.dirname(Platform.executable);
final String platformDill = p.join(buildDir, "vm_platform_strong.dill");
final String genSnapshot = p.join(buildDir, "gen_snapshot${executableSuffix}");
final String dart = p.join(buildDir, "dart${executableSuffix}");
final String dartPrecompiledRuntime =
p.join(buildDir, "dart_precompiled_runtime${executableSuffix}");
final String genKernel = p.join("pkg", "vm", "bin", "gen_kernel.dart");

View File

@ -338,11 +338,13 @@ cc/Profiler_TypedArrayAllocation: SkipByDesign
cc/Service_Profile: SkipByDesign
dart/isolates/thread_pool_test: SkipByDesign # Test uses dart:ffi which is not supported on simulators.
dart/regress_41971_test: SkipByDesign # dart:ffi is not supported on simulator
dart/sdk_hash_test: SkipSlow # gen_kernel is slow to run on simarm
dart/unboxed_param_args_descriptor_test: SkipByDesign # FFI helper not supported on simulator
dart/unboxed_param_tear_off_test: SkipByDesign # FFI helper not supported on simulator
dart/unboxed_param_test: SkipByDesign # FFI helper not supported on simulator
dart_2/isolates/thread_pool_test: SkipByDesign # Test uses dart:ffi which is not supported on simulators.
dart_2/regress_41971_test: SkipByDesign # dart:ffi is not supported on simulator
dart_2/sdk_hash_test: SkipSlow # gen_kernel is slow to run on simarm
dart_2/unboxed_param_args_descriptor_test: SkipByDesign # FFI helper not supported on simulator
dart_2/unboxed_param_tear_off_test: SkipByDesign # FFI helper not supported on simulator
dart_2/unboxed_param_test: SkipByDesign # FFI helper not supported on simulator

View File

@ -2654,18 +2654,7 @@ TokenPosition KernelReaderHelper::ReadPosition() {
}
intptr_t KernelReaderHelper::SourceTableFieldCountFromFirstLibraryOffset() {
// translation_helper_.info() might not be initialized at this point so we
// can't use translation_helper_.info().kernel_binary_version().
SetOffset(KernelFormatVersionOffset);
uint32_t formatVersion = reader_.ReadUInt32();
intptr_t count_from_first_library_offset =
SourceTableFieldCountFromFirstLibraryOffsetPre41;
static_assert(kMinSupportedKernelFormatVersion < 41, "cleanup this code");
if (formatVersion >= 41) {
count_from_first_library_offset =
SourceTableFieldCountFromFirstLibraryOffset41Plus;
}
return count_from_first_library_offset;
return SourceTableFieldCountFromFirstLibraryOffset41Plus;
}
intptr_t KernelReaderHelper::SourceTableSize() {

View File

@ -15,6 +15,7 @@
#include "vm/kernel.h"
#include "vm/object.h"
#include "vm/os.h"
#include "vm/version.h"
namespace dart {
@ -84,12 +85,17 @@ const char* kKernelInvalidBinaryFormatVersion =
"Invalid kernel binary format version";
const char* kKernelInvalidSizeIndicated =
"Invalid kernel binary: Indicated size is invalid";
const char* kKernelInvalidSdkHash = "Invalid SDK hash";
const int kSdkHashSizeInBytes = 10;
const char* kSdkHashNull = "0000000000";
std::unique_ptr<Program> Program::ReadFrom(Reader* reader, const char** error) {
if (reader->size() < 60) {
// A kernel file (v41) currently contains at least the following:
if (reader->size() < 70) {
// A kernel file (v43) currently contains at least the following:
// * Magic number (32)
// * Kernel version (32)
// * SDK Hash (10 * 8)
// * List of problems (8)
// * Length of source map (32)
// * Length of canonical name table (8)
@ -98,7 +104,7 @@ std::unique_ptr<Program> Program::ReadFrom(Reader* reader, const char** error) {
// * Length of constant table (8)
// * Component index (11 * 32)
//
// so is at least 64 bytes.
// so is at least 74 bytes.
// (Technically it will also contain an empty entry in both source map and
// string table, taking up another 8 bytes.)
if (error != nullptr) {
@ -124,6 +130,18 @@ std::unique_ptr<Program> Program::ReadFrom(Reader* reader, const char** error) {
return nullptr;
}
uint8_t sdkHash[kSdkHashSizeInBytes + 1];
reader->ReadBytes(sdkHash, kSdkHashSizeInBytes);
sdkHash[kSdkHashSizeInBytes] = 0; // Null terminate.
if (strcmp(Version::SdkHash(), kSdkHashNull) != 0 &&
strcmp((const char*)sdkHash, kSdkHashNull) != 0 &&
strcmp((const char*)sdkHash, Version::SdkHash()) != 0) {
if (error != nullptr) {
*error = kKernelInvalidSdkHash;
}
return nullptr;
}
std::unique_ptr<Program> program(new Program());
program->binary_version_ = formatVersion;
program->typed_data_ = reader->typed_data();
@ -152,13 +170,8 @@ std::unique_ptr<Program> Program::ReadFrom(Reader* reader, const char** error) {
// Read backwards at the end.
program->library_count_ = reader->ReadFromIndexNoReset(
reader->size_, LibraryCountFieldCountFromEnd, 1, 0);
static_assert(kMinSupportedKernelFormatVersion < 41, "cleanup this code");
intptr_t count_from_first_library_offset =
SourceTableFieldCountFromFirstLibraryOffsetPre41;
if (formatVersion >= 41) {
count_from_first_library_offset =
SourceTableFieldCountFromFirstLibraryOffset41Plus;
}
SourceTableFieldCountFromFirstLibraryOffset41Plus;
program->source_table_offset_ = reader->ReadFromIndexNoReset(
reader->size_,
LibraryCountFieldCountFromEnd + 1 + program->library_count_ + 1 +
@ -171,13 +184,9 @@ std::unique_ptr<Program> Program::ReadFrom(Reader* reader, const char** error) {
program->constant_table_offset_ = reader->ReadUInt32();
program->main_method_reference_ = NameIndex(reader->ReadUInt32() - 1);
if (formatVersion >= 41) {
NNBDCompiledMode compilation_mode =
static_cast<NNBDCompiledMode>(reader->ReadUInt32());
program->compilation_mode_ = compilation_mode;
} else {
program->compilation_mode_ = NNBDCompiledMode::kDisabled;
}
NNBDCompiledMode compilation_mode =
static_cast<NNBDCompiledMode>(reader->ReadUInt32());
program->compilation_mode_ = compilation_mode;
return program;
}

View File

@ -20,8 +20,8 @@ namespace kernel {
static const uint32_t kMagicProgramFile = 0x90ABCDEFu;
// Both version numbers are inclusive.
static const uint32_t kMinSupportedKernelFormatVersion = 29;
static const uint32_t kMaxSupportedKernelFormatVersion = 42;
static const uint32_t kMinSupportedKernelFormatVersion = 43;
static const uint32_t kMaxSupportedKernelFormatVersion = 43;
// Keep in sync with package:kernel/lib/binary/tag.dart
#define KERNEL_TAG_LIST(V) \
@ -326,6 +326,12 @@ class Reader : public ValueObject {
uint8_t PeekByte() { return buffer()[offset_]; }
void ReadBytes(uint8_t* buffer, uint8_t size) {
for (int i = 0; i < size; i++) {
buffer[i] = ReadByte();
}
}
bool ReadBool() { return (ReadByte() & 1) == 1; }
uint8_t ReadFlags() { return ReadByte(); }

View File

@ -297,7 +297,11 @@ Object& KernelLoader::LoadEntireProgram(Program* program,
reader.set_raw_buffer(program->kernel_data() + subprogram_start);
reader.set_size(subprogram_end - subprogram_start);
reader.set_offset(0);
std::unique_ptr<Program> subprogram = Program::ReadFrom(&reader);
const char* error = nullptr;
std::unique_ptr<Program> subprogram = Program::ReadFrom(&reader, &error);
if (subprogram == nullptr) {
FATAL1("Failed to load kernel file: %s", error);
}
ASSERT(subprogram->is_single_program());
KernelLoader loader(subprogram.get(), &uri_to_source_table);
Object& load_result = Object::Handle(loader.LoadProgram(false));
@ -894,7 +898,11 @@ void KernelLoader::FindModifiedLibraries(Program* program,
reader.set_raw_buffer(program->kernel_data() + subprogram_start);
reader.set_size(subprogram_end - subprogram_start);
reader.set_offset(0);
std::unique_ptr<Program> subprogram = Program::ReadFrom(&reader);
const char* error = nullptr;
std::unique_ptr<Program> subprogram = Program::ReadFrom(&reader, &error);
if (subprogram == nullptr) {
FATAL1("Failed to load kernel file: %s", error);
}
ASSERT(subprogram->is_single_program());
KernelLoader loader(subprogram.get(), /*uri_to_source_table=*/nullptr);
loader.walk_incremental_kernel(modified_libs, is_empty_program,

View File

@ -16,11 +16,13 @@ class Version : public AllStatic {
static const char* CommitString();
static int CurrentAbiVersion();
static int OldestSupportedAbiVersion();
static const char* SdkHash();
private:
static const char* str_;
static const char* snapshot_hash_;
static const char* commit_;
static const char* git_short_hash_;
};
} // namespace dart

View File

@ -38,8 +38,13 @@ int Version::OldestSupportedAbiVersion() {
return {{OLDEST_SUPPORTED_ABI_VERSION}};
}
const char* Version::SdkHash() {
return git_short_hash_;
}
const char* Version::snapshot_hash_ = "{{SNAPSHOT_HASH}}";
const char* Version::str_ = "{{VERSION_STR}} ({{CHANNEL}}) ({{COMMIT_TIME}})";
const char* Version::commit_ = "{{VERSION_STR}}";
const char* Version::git_short_hash_ = "{{GIT_HASH}}";
} // namespace dart

View File

@ -19,4 +19,22 @@ declare_args() {
# to out/ReleaseX64/args.gn. The path above can be extracted from the `.git`
# file under the git worktree folder.
default_git_folder = "$_dart_root/.git"
# Whether to enable the SDK hash check that will prevent loading a kernel
# into a VM which was built with a different SDK.
verify_sdk_hash = true
}
# The SDK hash to build into VM and kernels.
# The value 0000000000 signifies no hash is set, which will disable the check.
if (verify_sdk_hash) {
sdk_hash = exec_script("$_dart_root/tools/make_version.py",
[ "--format={{GIT_HASH}}" ],
"trim string",
[
"$_dart_root/tools/VERSION",
"$_dart_root/tools/utils.py",
])
} else {
sdk_hash = "0000000000"
}

View File

@ -136,7 +136,7 @@ def UseSysroot(args, gn_args):
return True
def ToGnArgs(args, mode, arch, target_os, sanitizer):
def ToGnArgs(args, mode, arch, target_os, sanitizer, verify_sdk_hash):
gn_args = {}
host_os = HostOsForGn(HOST_OS)
@ -258,6 +258,8 @@ def ToGnArgs(args, mode, arch, target_os, sanitizer):
gn_args['dart_debug_optimization_level'] = args.debug_opt_level
gn_args['debug_optimization_level'] = args.debug_opt_level
gn_args['verify_sdk_hash'] = verify_sdk_hash
return gn_args
@ -466,6 +468,10 @@ def parse_args(args):
default=False,
dest='use_qemu',
action='store_true')
other_group.add_argument('--no-verify-sdk-hash',
help='Disable SDK hash checks.',
default=False,
action='store_true')
options = parser.parse_args(args)
if not ProcessOptions(options):
@ -506,7 +512,8 @@ def Main(argv):
# See dartbug.com/32364
command = [gn, 'gen', out_dir]
gn_args = ToCommandLine(
ToGnArgs(args, mode, arch, target_os, sanitizer))
ToGnArgs(args, mode, arch, target_os, sanitizer,
not args.no_verify_sdk_hash))
gn_args += GetGNArgs(args)
if args.verbose:
print("gn gen --check in %s" % out_dir)

View File

@ -7,19 +7,13 @@
from __future__ import print_function
import argparse
import hashlib
import os
import sys
import time
from optparse import OptionParser
import utils
def debugLog(message):
print(message, file=sys.stderr)
sys.stderr.flush()
# When these files change, snapshots created by the VM are potentially no longer
# backwards-compatible.
VM_SNAPSHOT_FILES = [
@ -45,142 +39,152 @@ VM_SNAPSHOT_FILES = [
]
def MakeVersionString(quiet, no_git_hash, custom_for_pub=None):
channel = utils.GetChannel()
if custom_for_pub and channel == 'be':
latest = utils.GetLatestDevTag()
if not latest:
# If grabbing the dev tag fails, then fall back on the VERSION file.
latest = utils.GetSemanticSDKVersion(no_git_hash=True)
if no_git_hash:
version_string = ("%s.%s" % (latest, custom_for_pub))
else:
git_hash = utils.GetShortGitHash()
version_string = ("%s.%s-%s" % (latest, custom_for_pub, git_hash))
else:
version_string = utils.GetSemanticSDKVersion(no_git_hash=no_git_hash)
if not quiet:
debugLog("Returning version string: %s " % version_string)
return version_string
def MakeSnapshotHashString():
vmhash = hashlib.md5()
for vmfilename in VM_SNAPSHOT_FILES:
vmfilepath = os.path.join(utils.DART_DIR, 'runtime', 'vm', vmfilename)
with open(vmfilepath) as vmfile:
vmhash.update(vmfile.read().encode('utf-8'))
with open(vmfilepath, 'rb') as vmfile:
vmhash.update(vmfile.read())
return vmhash.hexdigest()
def MakeFile(quiet,
output_file,
input_file,
no_git_hash,
custom_for_pub,
version_file=None):
if version_file:
version_string = utils.GetVersion(no_git_hash, version_file)
else:
version_string = MakeVersionString(quiet, no_git_hash, custom_for_pub)
def GetSemanticVersionFormat(no_git_hash, custom_for_pub):
version_format = '{{SEMANTIC_SDK_VERSION}}'
if custom_for_pub and utils.GetChannel() == 'be':
if no_git_hash:
version_format = '{{LATEST}}.{{PUB_CUSTOM}}'
else:
version_format = '{{LATEST}}.{{PUB_CUSTOM}}-{{GIT_HASH}}'
return version_format
def FormatVersionString(version,
no_git_hash,
custom_for_pub,
version_file=None,
git_revision_file=None):
use_git_hash = not no_git_hash
semantic_sdk_version = utils.GetSemanticSDKVersion(no_git_hash,
version_file,
git_revision_file)
semantic_version_format = GetSemanticVersionFormat(no_git_hash,
custom_for_pub)
version_str = (semantic_sdk_version
if version_file else semantic_version_format)
version = version.replace('{{VERSION_STR}}', version_str)
version = version.replace('{{SEMANTIC_SDK_VERSION}}', semantic_sdk_version)
if custom_for_pub:
# LATEST is only used for custom_for_pub.
latest = None
if use_git_hash:
# If grabbing the dev tag fails, then fall back on the default VERSION file.
latest = utils.GetLatestDevTag()
if not latest:
latest = utils.GetSemanticSDKVersion(no_git_hash=True)
version = version.replace('{{LATEST}}', latest)
version = version.replace('{{PUB_CUSTOM}}', custom_for_pub)
git_hash = None
if use_git_hash:
git_hash = utils.GetShortGitHash()
if git_hash is None or len(git_hash) != 10:
git_hash = '0000000000'
version = version.replace('{{GIT_HASH}}', git_hash)
version_cc_text = open(input_file).read()
version_cc_text = version_cc_text.replace("{{VERSION_STR}}", version_string)
channel = utils.GetChannel()
version_cc_text = version_cc_text.replace("{{CHANNEL}}", channel)
version_time = utils.GetGitTimestamp()
if no_git_hash or version_time == None:
version_time = "Unknown timestamp"
version_cc_text = version_cc_text.replace("{{COMMIT_TIME}}",
version_time.decode("utf-8"))
version = version.replace('{{CHANNEL}}', channel)
version_time = None
if use_git_hash:
version_time = utils.GetGitTimestamp()
if version_time == None:
version_time = 'Unknown timestamp'
version = version.replace('{{COMMIT_TIME}}', version_time.decode('utf-8'))
abi_version = utils.GetAbiVersion(version_file)
version_cc_text = version_cc_text.replace("{{ABI_VERSION}}", abi_version)
version = version.replace('{{ABI_VERSION}}', abi_version)
oldest_supported_abi_version = utils.GetOldestSupportedAbiVersion(
version_file)
version_cc_text = version_cc_text.replace(
"{{OLDEST_SUPPORTED_ABI_VERSION}}", oldest_supported_abi_version)
version = version.replace('{{OLDEST_SUPPORTED_ABI_VERSION}}',
oldest_supported_abi_version)
snapshot_hash = MakeSnapshotHashString()
version_cc_text = version_cc_text.replace("{{SNAPSHOT_HASH}}",
snapshot_hash)
open(output_file, 'w').write(version_cc_text)
return True
version = version.replace('{{SNAPSHOT_HASH}}', snapshot_hash)
return version
def main(args):
def main():
try:
# Parse input.
parser = OptionParser()
parser.add_option(
"--custom_for_pub",
action="store",
type="string",
help=("Generates a version string that works with pub that includes"
"the given string. This is silently ignored on channels other"
"than be"))
parser.add_option(
"--input",
action="store",
type="string",
help="input template file.")
parser.add_option(
"--no_git_hash",
action="store_true",
parser = argparse.ArgumentParser()
parser.add_argument(
'--custom_for_pub',
help=('Generates a version string that works with pub that '
'includes the given string. This is silently ignored on '
'channels other than be.'))
parser.add_argument('--input', help='Input template file.')
parser.add_argument(
'--no_git_hash',
action='store_true',
default=False,
help="Don't try to determine svn revision")
parser.add_option(
"--output", action="store", type="string", help="output file name")
parser.add_option(
"-q",
"--quiet",
action="store_true",
default=False,
help="disable console output")
parser.add_option(
"--version-file",
action="store",
type="string",
default=None,
help="Version file")
help=('Don\'t try to call git to derive things like '
'git revision hash.'))
parser.add_argument('--output', help='output file name')
parser.add_argument('-q',
'--quiet',
action='store_true',
default=False,
help='DEPRECATED: Does nothing!')
parser.add_argument('--version-file', help='Path to the VERSION file.')
parser.add_argument('--git-revision-file',
help='Path to the GIT_REVISION file.')
parser.add_argument(
'--format',
default='{{VERSION_STR}}',
help='Version format used if no input template is given.')
(options, args) = parser.parse_args()
args = parser.parse_args()
# If there is no input template, then write the bare version string to
# options.output. If there is no options.output, then write the version
# args.output. If there is no args.output, then write the version
# string to stdout.
if not options.input:
version_string = MakeVersionString(
options.quiet, options.no_git_hash, options.custom_for_pub)
if options.output:
open(options.output, 'w').write(version_string)
else:
print(version_string)
return 0
if not options.output:
sys.stderr.write('--output not specified\n')
return -1
if not options.input:
sys.stderr.write('--input not specified\n')
return -1
version_template = ''
if args.input:
version_template = open(args.input).read()
elif not args.format is None:
version_template = args.format
else:
raise 'No version template given! Set either --input or --format.'
files = []
for arg in args:
files.append(arg)
version = FormatVersionString(version_template, args.no_git_hash,
args.custom_for_pub, args.version_file,
args.git_revision_file)
if not MakeFile(options.quiet, options.output, options.input,
options.no_git_hash, options.custom_for_pub,
options.version_file):
return -1
if args.output:
with open(args.output, 'w') as fh:
fh.write(version)
else:
sys.stdout.write(version)
return 0
except Exception as inst:
sys.stderr.write('make_version.py exception\n')
sys.stderr.write(str(inst))
sys.stderr.write('\n')
return -1
if __name__ == '__main__':
exit_code = main(sys.argv)
sys.exit(exit_code)
sys.exit(main())

View File

@ -349,34 +349,36 @@ def GetBuildSdkBin(host_os, mode=None, arch=None, target_os=None):
return os.path.join(build_root, 'dart-sdk', 'bin')
def GetShortVersion():
version = ReadVersionFile()
def GetShortVersion(version_file=None):
version = ReadVersionFile(version_file)
return ('{}.{}.{}.{}.{}'.format(version.major, version.minor, version.patch,
version.prerelease,
version.prerelease_patch))
def GetSemanticSDKVersion(no_git_hash=False, version_file=None):
def GetSemanticSDKVersion(no_git_hash=False,
version_file=None,
git_revision_file=None):
version = ReadVersionFile(version_file)
if not version:
return None
suffix = ''
if version.channel == 'be':
postfix = '-edge' if no_git_hash else '-edge.{}'.format(
GetGitRevision())
suffix = '-edge' if no_git_hash else '-edge.{}'.format(
GetGitRevision(git_revision_file))
elif version.channel in ('beta', 'dev'):
postfix = '-{}.{}.{}'.format(version.prerelease,
version.prerelease_patch, version.channel)
suffix = '-{}.{}.{}'.format(version.prerelease,
version.prerelease_patch, version.channel)
else:
assert version.channel == 'stable'
postfix = ''
return '{}.{}.{}{}'.format(version.major, version.minor, version.patch,
postfix)
suffix)
def GetVersion(no_git_hash=False, version_file=None):
return GetSemanticSDKVersion(no_git_hash, version_file)
def GetVersion(no_git_hash=False, version_file=None, git_revision_file=None):
return GetSemanticSDKVersion(no_git_hash, version_file, git_revision_file)
# The editor used to produce the VERSION file put on gcs. We now produce this
@ -396,8 +398,8 @@ def GetVersionFileContent():
return json.dumps(result, indent=2)
def GetChannel():
version = ReadVersionFile()
def GetChannel(version_file=None):
version = ReadVersionFile(version_file)
return version.channel
@ -466,8 +468,8 @@ def ReadVersionFile(version_file=None):
# We only use numbers on the master branch (bleeding edge). On branches
# we use the version number instead for archiving purposes.
# The number on master is the count of commits on the master branch.
def GetArchiveVersion():
version = ReadVersionFile()
def GetArchiveVersion(version_file=None):
version = ReadVersionFile(version_file=None)
if not version:
raise 'Could not get the archive version, parsing the version file failed'
if version.channel in ['be', 'integration']:
@ -475,9 +477,10 @@ def GetArchiveVersion():
return GetSemanticSDKVersion()
def GetGitRevision(repo_path=DART_DIR):
def GetGitRevision(git_revision_file=None, repo_path=DART_DIR):
# When building from tarball use tools/GIT_REVISION
git_revision_file = os.path.join(repo_path, 'tools', 'GIT_REVISION')
if git_revision_file is None:
git_revision_file = os.path.join(repo_path, 'tools', 'GIT_REVISION')
try:
with open(git_revision_file) as fd:
return fd.read().decode('utf-8').strip()
@ -493,7 +496,8 @@ def GetGitRevision(repo_path=DART_DIR):
# We expect a full git hash
if len(revision) != 40:
print('Warning: Could not parse git commit, output was {}'.format(
revision))
revision),
file=sys.stderr)
return None
return revision
@ -512,12 +516,14 @@ def GetShortGitHash(repo_path=DART_DIR):
def GetLatestDevTag(repo_path=DART_DIR):
# We used the old, pre-git2.13 refname:strip here since lstrip will fail on
# older git versions. strip is an alias for lstrip in later versions.
cmd = [
'git',
'for-each-ref',
'refs/tags/*dev*',
'--sort=-taggerdate',
"--format=%(refname:lstrip=2)",
"--format=%(refname:strip=2)",
'--count=1',
]
p = subprocess.Popen(cmd,
@ -529,7 +535,8 @@ def GetLatestDevTag(repo_path=DART_DIR):
tag = output.decode('utf-8').strip()
if p.wait() != 0:
print('Warning: Could not get the most recent dev branch tag {}'.format(
tag))
tag),
file=sys.stderr)
return None
return tag
@ -560,7 +567,8 @@ def GetGitNumber(repo_path=DART_DIR):
return number + GIT_NUMBER_BASE
except:
print(
'Warning: Could not parse git count, output was {}'.format(number))
'Warning: Could not parse git count, output was {}'.format(number),
file=sys.stderr)
return None

View File

@ -98,9 +98,11 @@ template("_application_snapshot") {
depfile = "$output.d"
abs_depfile = rebase_path(depfile)
rebased_output = rebase_path(output, root_build_dir)
vm_args = [
"--depfile=$abs_depfile",
"--depfile_output_filename=$rebased_output",
"-Dsdk_hash=$sdk_hash",
]
script = gen_kernel_script

View File

@ -3,6 +3,7 @@
# BSD-style license that can be found in the LICENSE file.
import("../build/dart/dart_action.gni")
import("../sdk_args.gni")
_dart_root = get_path_info("..", "abspath")
@ -46,6 +47,8 @@ template("compile_platform") {
outputs = invoker.outputs
vm_args = [ "-Dsdk_hash=$sdk_hash" ]
inputs = []
deps = []
args = []

View File

@ -44,6 +44,7 @@ prebuilt_dart_action("generate_summary_strong") {
inputs = sdk_lib_files + analyzer_files
output = "$root_gen_dir/strong.sum"
outputs = [ output ]
vm_args = [ "-Dsdk_hash=$sdk_hash" ]
args = [
"build",
rebase_path(output),

View File

@ -82,6 +82,8 @@ template("dart2js_compile") {
packages = "../../.packages"
vm_args = [ "-Dsdk_hash=$sdk_hash" ]
args = [
"$abs_main",
"-m",
@ -118,6 +120,8 @@ prebuilt_dart_action("dartdevc_patch_sdk") {
# TODO(rnystrom): List the outputs more precisely?
outputs = [ "$patched_sdk_dir/version" ]
vm_args = [ "-Dsdk_hash=$sdk_hash" ]
args = [
"--libraries",
rebase_path("$sdk_root/lib/libraries.json"),
@ -230,6 +234,8 @@ template("dartdevc_kernel_compile") {
"$js_gen_dir/$module.js",
]
vm_args = [ "-Dsdk_hash=$sdk_hash" ]
args = [
"-k",
"--dart-sdk-summary=$sdk_path",
@ -384,6 +390,8 @@ template("dartdevc_sdk_js") {
"$js_gen_dir/legacy/dart_sdk.js.map",
]
vm_args = [ "-Dsdk_hash=$sdk_hash" ]
script = "../../pkg/dev_compiler/bin/dartdevc.dart"
args = [

View File

@ -85,9 +85,11 @@ template("kernel_service_dill") {
depfile = "$root_gen_dir/kernel_service" + invoker.target_name + "_dill.d"
abs_depfile = rebase_path(depfile)
rebased_output = rebase_path(output, root_build_dir)
vm_args = [
"--depfile=$abs_depfile",
"--depfile_output_filename=$rebased_output",
"-Dsdk_hash=$sdk_hash",
]
script = gen_kernel_script