[vm] Fix obfuscation of uri

https://github.com/flutter/flutter/issues/99477
https://github.com/dart-lang/sdk/issues/44215

TEST=Test was added.

Change-Id: I585da436f9692d7f2e08db7f74c1a71ad09a1cb1
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/236220
Reviewed-by: Slava Egorov <vegorov@google.com>
Reviewed-by: Alexander Markov <alexmarkov@google.com>
Commit-Queue: Jens Johansen <jensj@google.com>
diff --git a/pkg/vm/lib/transformations/obfuscation_prohibitions_annotator.dart b/pkg/vm/lib/transformations/obfuscation_prohibitions_annotator.dart
index 6b5f9b2..762b17e 100644
--- a/pkg/vm/lib/transformations/obfuscation_prohibitions_annotator.dart
+++ b/pkg/vm/lib/transformations/obfuscation_prohibitions_annotator.dart
@@ -37,9 +37,16 @@
           metadata.protectedNames.add(name + "=");
         }
         final parent = node.parent;
+        final Library library;
         if (parent is Class) {
           metadata.protectedNames.add(parent.name);
+          library = parent.enclosingLibrary;
+        } else if (parent is Library) {
+          library = parent;
+        } else {
+          throw "Unexpected parent";
         }
+        metadata.protectedNames.add(library.importUri.toString());
         break;
       }
     }
diff --git a/pkg/vm/test/obfuscation_test.dart b/pkg/vm/test/obfuscation_test.dart
new file mode 100644
index 0000000..8ee7401
--- /dev/null
+++ b/pkg/vm/test/obfuscation_test.dart
@@ -0,0 +1,188 @@
+// Copyright (c) 2022, 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:convert';
+import "dart:io";
+
+import 'package:front_end/src/api_unstable/vm.dart'
+    show computePlatformBinariesLocation;
+
+main() {
+  final Directory tmpDir =
+      Directory.systemTemp.createTempSync("obfuscationtest");
+  try {
+    final Uri tmpDirUri = tmpDir.uri;
+    final Uri secretfilename = tmpDirUri.resolve("secretfilename.dart");
+    final File secretfilenameFile = new File.fromUri(secretfilename);
+    secretfilenameFile.writeAsStringSync("""
+import "secretfilename2.dart";
+
+main() {
+  print("Hello, World!");
+  verySecretFoo();
+}
+""");
+    final Uri secretfilename2 = tmpDirUri.resolve("secretfilename2.dart");
+    final File secretfilename2File = new File.fromUri(secretfilename2);
+    secretfilename2File.writeAsStringSync("""
+@pragma('vm:entry-point')
+void verySecretFoo() {
+  print("foo!");
+  alsoVerySecretFoo();
+}
+
+void alsoVerySecretFoo() {
+  print("foo too!");
+}
+""");
+
+    List<MappingPair> mapping = getSnapshotMap(tmpDir, secretfilenameFile);
+    bool good = verify(mapping, {
+      // This contains @pragma('vm:entry-point') and the uri should not change.
+      secretfilename2.toString(),
+      // This contains @pragma('vm:entry-point') and the name should not change.
+      "verySecretFoo",
+    }, {
+      // This is not special and should have been obfuscated.
+      secretfilename.toString(),
+      // This is not special and should have been obfuscated.
+      "alsoVerySecretFoo"
+    });
+    if (!good) throw "Obfuscation didn't work as expected";
+    print("Good");
+  } finally {
+    tmpDir.deleteSync(recursive: true);
+  }
+}
+
+List<MappingPair> getSnapshotMap(Directory tmpDir, File compileDartFile) {
+  final Uri genKernel = Platform.script.resolve('../bin/gen_kernel.dart');
+  final File genKernelFile = new File.fromUri(genKernel);
+  if (!genKernelFile.existsSync()) {
+    throw "Didn't find gen_kernel at $genKernel";
+  }
+
+  File resolvedExecutableFile = new File(Platform.resolvedExecutable);
+  Uri resolvedExecutable = resolvedExecutableFile.uri;
+  String genSnapshotFilename = "gen_snapshot";
+  if (Platform.isWindows) genSnapshotFilename += ".exe";
+
+  Uri genSnapshot = resolvedExecutable.resolve(genSnapshotFilename);
+  File genSnapshotFile = new File.fromUri(genSnapshot);
+  if (!genSnapshotFile.existsSync()) {
+    print(
+        "Didn't find gen_kernel at $genSnapshot... Trying utils/$genSnapshotFilename");
+    genSnapshot = resolvedExecutable.resolve("utils/$genSnapshotFilename");
+    genSnapshotFile = new File.fromUri(genSnapshot);
+    if (!genSnapshotFile.existsSync()) {
+      throw "Didn't find gen_kernel at $genSnapshot";
+    }
+  }
+
+  final Uri platformDill = computePlatformBinariesLocation()
+      .resolve('vm_platform_strong_product.dill');
+  final File platformDillFile = new File.fromUri(platformDill);
+  if (!platformDillFile.existsSync()) {
+    throw "Didn't find vm_platform_strong_product at $platformDill";
+  }
+
+  final Uri tmpDirUri = tmpDir.uri;
+
+  final Uri kernelDill = tmpDirUri.resolve("kernel.dill");
+  final File kernelDillFile = new File.fromUri(kernelDill);
+
+  print("Running gen_kernel");
+  // Extracted from pkg/dart2native/lib/dart2native.dart.
+  final ProcessResult kernelRun = Process.runSync(Platform.resolvedExecutable, [
+    genKernelFile.path,
+    "--platform",
+    platformDillFile.path,
+    "--aot",
+    "-Ddart.vm.product=true",
+    "-o",
+    kernelDillFile.path,
+    "--invocation-modes=compile",
+    "--verbosity=all",
+    compileDartFile.path
+  ]);
+
+  if (kernelRun.exitCode != 0) {
+    throw "Got exit code ${kernelRun.exitCode}\n"
+        "stdout: ${kernelRun.stdout}\n"
+        "stderr: ${kernelRun.stderr}";
+  }
+
+  final Uri aotElf = tmpDirUri.resolve("aot.elf");
+  final File aotElfFile = new File.fromUri(aotElf);
+  final Uri obfuscationMap = tmpDirUri.resolve("obfuscation.map");
+  final File obfuscationMapFile = new File.fromUri(obfuscationMap);
+
+  print("Running $genSnapshot");
+  // Extracted from pkg/dart2native/lib/dart2native.dart.
+  final ProcessResult snapshotRun = Process.runSync(genSnapshotFile.path, [
+    "--snapshot-kind=app-aot-elf",
+    "--elf=${aotElfFile.path}",
+    "--dwarf-stack-traces",
+    "--obfuscate",
+    "--strip",
+    "--save-obfuscation-map=${obfuscationMapFile.path}",
+    kernelDillFile.path,
+  ]);
+
+  if (snapshotRun.exitCode != 0) {
+    throw "Got exit code ${snapshotRun.exitCode}\n"
+        "stdout: ${snapshotRun.stdout}\n"
+        "stderr: ${snapshotRun.stderr}";
+  }
+
+  print("Reading $obfuscationMap");
+
+  return readJsonMapping(obfuscationMapFile);
+}
+
+List<MappingPair> readJsonMapping(File file) {
+  List<MappingPair> result = [];
+  List<dynamic> json = jsonDecode(file.readAsStringSync());
+  for (int i = 0; i < json.length; i += 2) {
+    result.add(new MappingPair(json[i] as String, json[i + 1] as String));
+  }
+  return result;
+}
+
+class MappingPair {
+  final String from;
+  final String to;
+
+  MappingPair(this.from, this.to);
+
+  String toString() => "MappingPair[$from->$to]";
+}
+
+bool verify(List<MappingPair> mapping, Set<String> expectedIdentity,
+    Set<String> expectedDifferent) {
+  bool good = true;
+  Set<String> missingKeys = new Set<String>.of(expectedIdentity)
+    ..addAll(expectedDifferent);
+  for (MappingPair entry in mapping) {
+    missingKeys.remove(entry.from);
+    if (expectedIdentity.contains(entry.from) && entry.from != entry.to) {
+      print("Expected ${entry.from} to map to itself, "
+          "but mapped to ${entry.to}");
+      good = false;
+    }
+    if (expectedDifferent.contains(entry.from) && entry.from == entry.to) {
+      print("Expected ${entry.from} to map to something different, "
+          "but it didn't.");
+      good = false;
+    }
+  }
+  if (missingKeys.isNotEmpty) {
+    print("Expected to have seen the following entries which wasn't found:");
+    for (String missingKey in missingKeys) {
+      print("- $missingKey");
+    }
+    good = false;
+  }
+  return good;
+}