Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(42)

Side by Side Diff: runtime/vm/precompiler.cc

Issue 3003583002: [VM, Precompiler] PoC Obfuscator (Closed)
Patch Set: address comments and fix stuff Created 3 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #include "vm/precompiler.h" 5 #include "vm/precompiler.h"
6 6
7 #include "vm/aot_optimizer.h" 7 #include "vm/aot_optimizer.h"
8 #include "vm/assembler.h" 8 #include "vm/assembler.h"
9 #include "vm/ast_printer.h" 9 #include "vm/ast_printer.h"
10 #include "vm/branch_optimizer.h" 10 #include "vm/branch_optimizer.h"
(...skipping 27 matching lines...) Expand all
38 #include "vm/redundancy_elimination.h" 38 #include "vm/redundancy_elimination.h"
39 #include "vm/regexp_assembler.h" 39 #include "vm/regexp_assembler.h"
40 #include "vm/regexp_parser.h" 40 #include "vm/regexp_parser.h"
41 #include "vm/resolver.h" 41 #include "vm/resolver.h"
42 #include "vm/runtime_entry.h" 42 #include "vm/runtime_entry.h"
43 #include "vm/symbols.h" 43 #include "vm/symbols.h"
44 #include "vm/tags.h" 44 #include "vm/tags.h"
45 #include "vm/timeline.h" 45 #include "vm/timeline.h"
46 #include "vm/timer.h" 46 #include "vm/timer.h"
47 #include "vm/type_table.h" 47 #include "vm/type_table.h"
48 #include "vm/unicode.h"
48 #include "vm/version.h" 49 #include "vm/version.h"
49 50
50 namespace dart { 51 namespace dart {
51 52
52 #define T (thread()) 53 #define T (thread())
53 #define I (isolate()) 54 #define I (isolate())
54 #define Z (zone()) 55 #define Z (zone())
55 56
56 DEFINE_FLAG(bool, print_unique_targets, false, "Print unique dynamic targets"); 57 DEFINE_FLAG(bool, print_unique_targets, false, "Print unique dynamic targets");
57 DEFINE_FLAG(bool, trace_precompiler, false, "Trace precompiler."); 58 DEFINE_FLAG(bool, trace_precompiler, false, "Trace precompiler.");
(...skipping 424 matching lines...) Expand 10 before | Expand all | Expand 10 after
482 I->object_store()->set_async_star_move_next_helper(null_function); 483 I->object_store()->set_async_star_move_next_helper(null_function);
483 I->object_store()->set_complete_on_async_return(null_function); 484 I->object_store()->set_complete_on_async_return(null_function);
484 I->object_store()->set_async_star_stream_controller(null_class); 485 I->object_store()->set_async_star_stream_controller(null_class);
485 DropLibraryEntries(); 486 DropLibraryEntries();
486 } 487 }
487 DropClasses(); 488 DropClasses();
488 DropLibraries(); 489 DropLibraries();
489 490
490 BindStaticCalls(); 491 BindStaticCalls();
491 SwitchICCalls(); 492 SwitchICCalls();
493 Obfuscate();
492 494
493 ProgramVisitor::Dedup(); 495 ProgramVisitor::Dedup();
494 496
495 zone_ = NULL; 497 zone_ = NULL;
496 } 498 }
497 499
498 intptr_t symbols_before = -1; 500 intptr_t symbols_before = -1;
499 intptr_t symbols_after = -1; 501 intptr_t symbols_after = -1;
500 intptr_t capacity = -1; 502 intptr_t capacity = -1;
501 if (FLAG_trace_precompiler) { 503 if (FLAG_trace_precompiler) {
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after
603 current->field_->set_guarded_cid(cid); 605 current->field_->set_guarded_cid(cid);
604 current->field_->set_is_nullable(cid == kNullCid || cid == kDynamicCid); 606 current->field_->set_is_nullable(cid == kNullCid || cid == kDynamicCid);
605 if (FLAG_trace_precompiler) { 607 if (FLAG_trace_precompiler) {
606 THR_Print( 608 THR_Print(
607 "Field %s <- Type %s\n", current->field_->ToCString(), 609 "Field %s <- Type %s\n", current->field_->ToCString(),
608 Class::Handle(T->isolate()->class_table()->At(cid)).ToCString()); 610 Class::Handle(T->isolate()->class_table()->At(cid)).ToCString());
609 } 611 }
610 } 612 }
611 } 613 }
612 614
613 void Precompiler::AddRoots(Dart_QualifiedFunctionName embedder_entry_points[]) { 615 static Dart_QualifiedFunctionName vm_entry_points[] = {
614 // Note that <rootlibrary>.main is not a root. The appropriate main will be
615 // discovered through _getMainClosure.
616
617 AddSelector(Symbols::NoSuchMethod());
618
619 AddSelector(Symbols::Call()); // For speed, not correctness.
620
621 // Allocated from C++.
622 Class& cls = Class::Handle(Z);
623 for (intptr_t cid = kInstanceCid; cid < kNumPredefinedCids; cid++) {
624 ASSERT(isolate()->class_table()->IsValidIndex(cid));
625 if (!isolate()->class_table()->HasValidClassAt(cid)) {
626 continue;
627 }
628 if ((cid == kDynamicCid) || (cid == kVoidCid) ||
629 (cid == kFreeListElement) || (cid == kForwardingCorpse)) {
630 continue;
631 }
632 cls = isolate()->class_table()->At(cid);
633 AddInstantiatedClass(cls);
634 }
635
636 Dart_QualifiedFunctionName vm_entry_points[] = {
637 // Functions 616 // Functions
638 {"dart:core", "::", "_completeDeferredLoads"}, 617 {"dart:core", "::", "_completeDeferredLoads"},
639 {"dart:core", "::", "identityHashCode"}, 618 {"dart:core", "::", "identityHashCode"},
640 {"dart:core", "AbstractClassInstantiationError", 619 {"dart:core", "AbstractClassInstantiationError",
641 "AbstractClassInstantiationError._create"}, 620 "AbstractClassInstantiationError._create"},
642 {"dart:core", "ArgumentError", "ArgumentError."}, 621 {"dart:core", "ArgumentError", "ArgumentError."},
643 {"dart:core", "ArgumentError", "ArgumentError.value"}, 622 {"dart:core", "ArgumentError", "ArgumentError.value"},
644 {"dart:core", "CyclicInitializationError", "CyclicInitializationError."}, 623 {"dart:core", "CyclicInitializationError", "CyclicInitializationError."},
645 {"dart:core", "FallThroughError", "FallThroughError._create"}, 624 {"dart:core", "FallThroughError", "FallThroughError._create"},
646 {"dart:core", "FormatException", "FormatException."}, 625 {"dart:core", "FormatException", "FormatException."},
(...skipping 19 matching lines...) Expand all
666 {"dart:typed_data", "_ByteBuffer", "_ByteBuffer._New"}, 645 {"dart:typed_data", "_ByteBuffer", "_ByteBuffer._New"},
667 {"dart:_vmservice", "::", "boot"}, 646 {"dart:_vmservice", "::", "boot"},
668 #if !defined(PRODUCT) 647 #if !defined(PRODUCT)
669 {"dart:_vmservice", "::", "_registerIsolate"}, 648 {"dart:_vmservice", "::", "_registerIsolate"},
670 {"dart:developer", "Metrics", "_printMetrics"}, 649 {"dart:developer", "Metrics", "_printMetrics"},
671 {"dart:developer", "::", "_runExtension"}, 650 {"dart:developer", "::", "_runExtension"},
672 {"dart:isolate", "::", "_runPendingImmediateCallback"}, 651 {"dart:isolate", "::", "_runPendingImmediateCallback"},
673 #endif // !PRODUCT 652 #endif // !PRODUCT
674 // Fields 653 // Fields
675 {"dart:core", "Error", "_stackTrace"}, 654 {"dart:core", "Error", "_stackTrace"},
655 {"dart:core", "::", "_uriBaseClosure"},
676 {"dart:math", "_Random", "_state"}, 656 {"dart:math", "_Random", "_state"},
677 {NULL, NULL, NULL} // Must be terminated with NULL entries. 657 {NULL, NULL, NULL} // Must be terminated with NULL entries.
678 }; 658 };
659
660 void Precompiler::AddRoots(Dart_QualifiedFunctionName embedder_entry_points[]) {
661 // Note that <rootlibrary>.main is not a root. The appropriate main will be
662 // discovered through _getMainClosure.
663
664 AddSelector(Symbols::NoSuchMethod());
665
666 AddSelector(Symbols::Call()); // For speed, not correctness.
667
668 // Allocated from C++.
669 Class& cls = Class::Handle(Z);
670 for (intptr_t cid = kInstanceCid; cid < kNumPredefinedCids; cid++) {
671 ASSERT(isolate()->class_table()->IsValidIndex(cid));
672 if (!isolate()->class_table()->HasValidClassAt(cid)) {
673 continue;
674 }
675 if ((cid == kDynamicCid) || (cid == kVoidCid) ||
676 (cid == kFreeListElement) || (cid == kForwardingCorpse)) {
677 continue;
678 }
679 cls = isolate()->class_table()->At(cid);
680 AddInstantiatedClass(cls);
681 }
679 682
680 AddEntryPoints(vm_entry_points); 683 AddEntryPoints(vm_entry_points);
681 AddEntryPoints(embedder_entry_points); 684 AddEntryPoints(embedder_entry_points);
682 const Library& lib = Library::Handle(I->object_store()->root_library()); 685 const Library& lib = Library::Handle(I->object_store()->root_library());
683 const String& name = String::Handle(String::New("main")); 686 const String& name = String::Handle(String::New("main"));
684 const Object& main_closure = Object::Handle(lib.GetFunctionClosure(name)); 687 const Object& main_closure = Object::Handle(lib.GetFunctionClosure(name));
685 if (main_closure.IsClosure()) { 688 if (main_closure.IsClosure()) {
686 if (lib.LookupLocalFunction(name) == Function::null()) { 689 if (lib.LookupLocalFunction(name) == Function::null()) {
687 // Check whether the function is in exported namespace of library, in 690 // Check whether the function is in exported namespace of library, in
688 // this case we have to retain the root library caches. 691 // this case we have to retain the root library caches.
(...skipping 1582 matching lines...) Expand 10 before | Expand all | Expand 10 after
2271 Code& target_code_; 2274 Code& target_code_;
2272 UnlinkedCallSet canonical_unlinked_calls_; 2275 UnlinkedCallSet canonical_unlinked_calls_;
2273 }; 2276 };
2274 2277
2275 ASSERT(!I->compilation_allowed()); 2278 ASSERT(!I->compilation_allowed());
2276 SwitchICCallsVisitor visitor(Z); 2279 SwitchICCallsVisitor visitor(Z);
2277 ProgramVisitor::VisitFunctions(&visitor); 2280 ProgramVisitor::VisitFunctions(&visitor);
2278 #endif 2281 #endif
2279 } 2282 }
2280 2283
2284 void Precompiler::Obfuscate() {
2285 if (!I->obfuscate()) {
2286 return;
2287 }
2288
2289 class ScriptsCollector : public ObjectVisitor {
2290 public:
2291 explicit ScriptsCollector(Zone* zone,
2292 GrowableHandlePtrArray<const Script>* scripts)
2293 : script_(Script::Handle(zone)), scripts_(scripts) {}
2294
2295 void VisitObject(RawObject* obj) {
2296 if (obj->GetClassId() == kScriptCid) {
2297 script_ ^= obj;
2298 scripts_->Add(Script::Cast(script_));
2299 }
2300 }
2301
2302 private:
2303 Script& script_;
2304 GrowableHandlePtrArray<const Script>* scripts_;
2305 };
2306
2307 GrowableHandlePtrArray<const Script> scripts(Z, 100);
2308 Isolate::Current()->heap()->CollectAllGarbage();
2309 {
2310 HeapIterationScope his(T);
2311 ScriptsCollector visitor(Z, &scripts);
2312 I->heap()->VisitObjects(&visitor);
2313 }
2314
2315 {
2316 // Note: when this object is destroyed it will commit obfuscation
2317 // mappings into the ObjectStore. Hence the block around it - to
2318 // ensure that destructor is called before we save obfuscation
2319 // mappings and clear the ObjectStore.
2320 Obfuscator obfuscator(T, /*private_key=*/String::Handle(Z));
2321 String& str = String::Handle(Z);
2322 for (intptr_t i = 0; i < scripts.length(); i++) {
2323 const Script& script = scripts.At(i);
2324
2325 str = script.url();
2326 str = Symbols::New(T, str);
2327 str = obfuscator.Rename(str, /*atomic=*/true);
2328 script.set_url(str);
2329
2330 str = script.resolved_url();
2331 str = Symbols::New(T, str);
2332 str = obfuscator.Rename(str, /*atomic=*/true);
2333 script.set_resolved_url(str);
2334 }
2335
2336 Library& lib = Library::Handle();
2337 for (intptr_t i = 0; i < libraries_.Length(); i++) {
2338 lib ^= libraries_.At(i);
2339 if (!lib.is_dart_scheme()) {
2340 str = lib.name();
2341 str = obfuscator.Rename(str, /*atomic=*/true);
2342 lib.set_name(str);
2343
2344 str = lib.url();
2345 str = Symbols::New(T, str);
2346 str = obfuscator.Rename(str, /*atomic=*/true);
2347 lib.set_url(str);
2348 }
2349 }
2350 Library::RegisterLibraries(T, libraries_);
2351 }
2352
2353 // Obfuscation is done. Move obfuscation map into malloced memory.
2354 I->set_obfuscation_map(Obfuscator::SerializeMap(T));
2355
2356 // Discard obfuscation mappings to avoid including them into snapshot.
2357 I->object_store()->set_obfuscation_map(Array::Handle(Z));
2358 }
2359
2281 void Precompiler::FinalizeAllClasses() { 2360 void Precompiler::FinalizeAllClasses() {
2282 Library& lib = Library::Handle(Z); 2361 Library& lib = Library::Handle(Z);
2283 Class& cls = Class::Handle(Z); 2362 Class& cls = Class::Handle(Z);
2284 2363
2285 for (intptr_t i = 0; i < libraries_.Length(); i++) { 2364 for (intptr_t i = 0; i < libraries_.Length(); i++) {
2286 lib ^= libraries_.At(i); 2365 lib ^= libraries_.At(i);
2287 if (!lib.Loaded()) { 2366 if (!lib.Loaded()) {
2288 String& uri = String::Handle(Z, lib.url()); 2367 String& uri = String::Handle(Z, lib.url());
2289 String& msg = String::Handle( 2368 String& msg = String::Handle(
2290 Z, 2369 Z,
(...skipping 1032 matching lines...) Expand 10 before | Expand all | Expand 10 after
3323 FieldTypeMap* field_type_map) { 3402 FieldTypeMap* field_type_map) {
3324 VMTagScope tagScope(thread, VMTag::kCompileUnoptimizedTagId); 3403 VMTagScope tagScope(thread, VMTag::kCompileUnoptimizedTagId);
3325 TIMELINE_FUNCTION_COMPILATION_DURATION(thread, "CompileFunction", function); 3404 TIMELINE_FUNCTION_COMPILATION_DURATION(thread, "CompileFunction", function);
3326 3405
3327 ASSERT(FLAG_precompiled_mode); 3406 ASSERT(FLAG_precompiled_mode);
3328 const bool optimized = function.IsOptimizable(); // False for natives. 3407 const bool optimized = function.IsOptimizable(); // False for natives.
3329 DartPrecompilationPipeline pipeline(zone, field_type_map); 3408 DartPrecompilationPipeline pipeline(zone, field_type_map);
3330 return PrecompileFunctionHelper(precompiler, &pipeline, function, optimized); 3409 return PrecompileFunctionHelper(precompiler, &pipeline, function, optimized);
3331 } 3410 }
3332 3411
3412 Obfuscator::Obfuscator(Thread* thread, const String& private_key)
3413 : state_(NULL) {
3414 Isolate* isolate = thread->isolate();
3415 Zone* zone = thread->zone();
3416
3417 if (isolate->obfuscate()) {
3418 ObjectStore* store = thread->isolate()->object_store();
3419 Array& obfuscation_state = Array::Handle(zone, store->obfuscation_map());
3420
3421 if (store->obfuscation_map() == Array::null()) {
3422 const int kInitialPrivateCapacity = 256;
3423 obfuscation_state = Array::New(kSavedStateSize);
3424 obfuscation_state.SetAt(
3425 1, Array::Handle(zone, HashTables::New<ObfuscationMap>(
3426 kInitialPrivateCapacity, Heap::kOld)));
3427 }
3428
3429 state_ =
3430 new (zone) ObfuscationState(thread, obfuscation_state, private_key);
3431
3432 if (store->obfuscation_map() == Array::null()) {
3433 InitializeRenamingMap(isolate);
3434 }
3435 }
3436 }
3437
3438 Obfuscator::~Obfuscator() {
3439 if (state_ != NULL) {
3440 state_->SaveState();
3441 }
3442 }
3443
3444 void Obfuscator::InitializeRenamingMap(Isolate* isolate) {
3445 // Prevent renaming of classes and method names mentioned in the
3446 // entry points lists.
3447 PreventRenaming(vm_entry_points);
3448 PreventRenaming(isolate->embedder_entry_points());
3449
3450 // Prevent renaming of all pseudo-keywords and operators.
3451 // Note: not all pseudo-keywords are mentioned in DART_KEYWORD_LIST
3452 // (for example 'hide', 'show' and async related keywords are omitted).
3453 // Those are protected from renaming as part of all symbols.
3454 #define PREVENT_RENAMING(name, value, priority, attr) \
3455 do { \
3456 if (Token::CanBeOverloaded(Token::name) || \
3457 ((Token::attr & Token::kPseudoKeyword) != 0)) { \
3458 PreventRenaming(value); \
3459 } \
3460 } while (0);
3461
3462 DART_TOKEN_LIST(PREVENT_RENAMING)
3463 DART_KEYWORD_LIST(PREVENT_RENAMING)
3464 #undef PREVENT_RENAMING
3465
3466 // this is a keyword token unless it occurs in the string interpolation
3467 // which causes it to be obfuscated.
3468 PreventRenaming("this");
3469
3470 // Protect all symbols from renaming.
3471 #define PREVENT_RENAMING(name, value) PreventRenaming(value);
3472 PREDEFINED_SYMBOLS_LIST(PREVENT_RENAMING)
3473 #undef PREVENT_RENAMING
3474
3475 // Protect NativeFieldWrapperClassX names from being obfuscated. Those
3476 // classes are created manually by the runtime system.
3477 // TODO(dartbug.com/30524) instead call to Obfuscator::Rename from a place
3478 // where these are created.
3479 PreventRenaming("NativeFieldWrapperClass1");
3480 PreventRenaming("NativeFieldWrapperClass2");
3481 PreventRenaming("NativeFieldWrapperClass3");
3482 PreventRenaming("NativeFieldWrapperClass4");
3483
3484 // Prevent renaming of ClassID.cid* fields. These fields are injected by
3485 // runtime.
3486 // TODO(dartbug.com/30524) instead call to Obfuscator::Rename from a place
3487 // where these are created.
3488 #define CLASS_LIST_WITH_NULL(V) \
3489 V(Null) \
3490 CLASS_LIST_NO_OBJECT(V)
3491 #define PREVENT_RENAMING(clazz) PreventRenaming("cid" #clazz);
3492 CLASS_LIST_WITH_NULL(PREVENT_RENAMING)
3493 #undef PREVENT_RENAMING
3494 #undef CLASS_LIST_WITH_NULL
3495
3496 // Prevent renaming of methods that are looked up by method recognizer.
3497 // TODO(dartbug.com/30524) instead call to Obfuscator::Rename from a place
3498 // where these are looked up.
3499 #define PREVENT_RENAMING(class_name, function_name, recognized_enum, \
3500 result_type, fingerprint) \
3501 do { \
3502 PreventRenaming(#class_name); \
3503 PreventRenaming(#function_name); \
3504 } while (0);
3505 RECOGNIZED_LIST(PREVENT_RENAMING)
3506 #undef PREVENT_RENAMING
3507
3508 // Prevent renaming of methods that are looked up by method recognizer.
3509 // TODO(dartbug.com/30524) instead call to Obfuscator::Rename from a place
3510 // where these are looked up.
3511 #define PREVENT_RENAMING(class_name, function_name, recognized_enum, \
3512 fingerprint) \
3513 do { \
3514 PreventRenaming(#class_name); \
3515 PreventRenaming(#function_name); \
3516 } while (0);
3517 INLINE_WHITE_LIST(PREVENT_RENAMING)
3518 INLINE_BLACK_LIST(PREVENT_RENAMING)
3519 POLYMORPHIC_TARGET_LIST(PREVENT_RENAMING)
3520 #undef PREVENT_RENAMING
3521
3522 // These are not mentioned by entry points but are still looked up by name.
3523 // (They are not mentioned in the entry points because we don't need them
3524 // after the compilation)
3525 PreventRenaming("_resolveScriptUri");
3526
3527 // Precompiler is looking up "main".
3528 // TODO(dartbug.com/30524) instead call to Obfuscator::Rename from a place
3529 // where these are created.
3530 PreventRenaming("main");
3531
3532 // Fast path for common conditional import. See Deobfuscate method.
3533 PreventRenaming("dart");
3534 PreventRenaming("library");
3535 PreventRenaming("io");
3536 PreventRenaming("html");
3537 }
3538
3539 RawString* Obfuscator::ObfuscationState::RenameImpl(const String& name,
3540 bool atomic) {
3541 ASSERT(name.IsSymbol());
3542
3543 renamed_ ^= renames_.GetOrNull(name);
3544 if (renamed_.IsNull()) {
3545 renamed_ = BuildRename(name, atomic);
3546 renames_.UpdateOrInsert(name, renamed_);
3547 }
3548 return renamed_.raw();
3549 }
3550
3551 void Obfuscator::PreventRenaming(Dart_QualifiedFunctionName entry_points[]) {
3552 for (intptr_t i = 0; entry_points[i].function_name != NULL; i++) {
3553 const char* class_name = entry_points[i].class_name;
3554 const char* function_name = entry_points[i].function_name;
3555
3556 const size_t class_name_len = strlen(class_name);
3557 if (strncmp(function_name, class_name, class_name_len) == 0 &&
3558 function_name[class_name_len] == '.') {
3559 const char* ctor_name = function_name + class_name_len + 1;
3560 if (ctor_name[0] != '\0') {
3561 PreventRenaming(ctor_name);
3562 }
3563 } else {
3564 PreventRenaming(function_name);
3565 }
3566 PreventRenaming(class_name);
3567 }
3568 }
3569
3570 static const char* const kGetterPrefix = "get:";
3571 static const intptr_t kGetterPrefixLength = strlen(kGetterPrefix);
3572 static const char* const kSetterPrefix = "set:";
3573 static const intptr_t kSetterPrefixLength = strlen(kSetterPrefix);
3574
3575 void Obfuscator::PreventRenaming(const char* name) {
3576 const char* dot = strchr(name, '.');
3577 if (dot != NULL) {
3578 name = dot + 1;
3579 }
3580
3581 if (name[0] == '\0') {
3582 return;
3583 }
3584
3585 if (strncmp(name, kGetterPrefix, kGetterPrefixLength) == 0) {
3586 name = name + kGetterPrefixLength;
3587 } else if (strncmp(name, kSetterPrefix, kSetterPrefixLength) == 0) {
3588 name = name + kSetterPrefixLength;
3589 }
3590
3591 state_->PreventRenaming(name);
3592 }
3593
3594 void Obfuscator::ObfuscationState::SaveState() {
3595 saved_state_.SetAt(kSavedStateNameIndex, String::Handle(String::New(name_)));
3596 saved_state_.SetAt(kSavedStateRenamesIndex, renames_.Release());
3597 thread_->isolate()->object_store()->set_obfuscation_map(saved_state_);
3598 }
3599
3600 void Obfuscator::ObfuscationState::PreventRenaming(const char* name) {
3601 string_ = Symbols::New(thread_, name);
3602 PreventRenaming(string_);
3603 }
3604
3605 void Obfuscator::ObfuscationState::PreventRenaming(const String& name) {
3606 renames_.UpdateOrInsert(name, name);
3607 }
3608
3609 void Obfuscator::ObfuscationState::NextName() {
3610 for (intptr_t i = 0;; i++) {
3611 const char digit = name_[i];
3612 if (digit == '\0') {
3613 name_[i] = 'a';
3614 } else if (digit < 'Z') {
3615 name_[i]++;
3616 } else if (digit == 'Z') {
3617 name_[i] = 'a';
3618 continue;
3619 } else if (digit < 'z') {
3620 name_[i]++;
3621 } else {
3622 name_[i] = 'A';
3623 }
3624 break;
3625 }
3626 }
3627
3628 RawString* Obfuscator::ObfuscationState::NewAtomicRename(
3629 bool should_be_private) {
3630 do {
3631 NextName();
3632 renamed_ = Symbols::NewFormatted(thread_, "%s%s",
3633 should_be_private ? "_" : "", name_);
3634 } while (renames_.ContainsKey(renamed_));
3635 return renamed_.raw();
3636 }
3637
3638 RawString* Obfuscator::ObfuscationState::BuildRename(const String& name,
3639 bool atomic) {
3640 const bool is_private = name.CharAt(0) == '_';
3641 if (!atomic && is_private) {
3642 intptr_t i = 0;
3643 while (i < name.Length() && name.CharAt(i) != '@') {
3644 i++;
3645 }
3646 const intptr_t end = i;
3647
3648 string_ = Symbols::New(thread_, name, 0, end);
3649
3650 string_ = RenameImpl(string_, /*atomic=*/true);
3651 return Symbols::FromConcat(thread_, string_, private_key_);
3652 } else {
3653 return NewAtomicRename(is_private);
3654 }
3655 }
3656
3657 void Obfuscator::ObfuscateSymbolInstance(Thread* thread,
3658 const Instance& symbol) {
3659 const intptr_t kSymbolNameOffset = kWordSize;
3660
3661 Object& name_value = String::Handle();
3662 name_value = symbol.RawGetFieldAtOffset(kSymbolNameOffset);
3663 if (!name_value.IsString()) {
3664 // dart.internal.Symbol constructor does not validate its input.
3665 return;
3666 }
3667
3668 String& name = String::Handle();
3669 name ^= name_value.raw();
3670
3671 // TODO(vegorov) it is quite wasteful to create an obfuscator per-symbol.
3672 Obfuscator obfuscator(thread, /*private_key=*/String::Handle());
3673
3674 String& component = String::Handle();
3675 GrowableHandlePtrArray<const String> renamed(thread->zone(), 2);
3676
3677 const intptr_t length = name.Length();
3678 intptr_t i = 0, start = 0;
3679 while (i < length) {
3680 // First look for a '.' in the symbol.
3681 start = i;
3682 while (i < length && name.CharAt(i) != '.') {
3683 i++;
3684 }
3685 const intptr_t end = i;
3686 if (end == length) {
3687 break;
3688 }
3689
3690 if (start != end) {
3691 component = Symbols::New(thread, name, start, end - start);
3692 component = obfuscator.Rename(component, /*atomic=*/true);
3693 renamed.Add(component);
3694 }
3695
3696 renamed.Add(Symbols::Dot());
3697 i++; // Skip '.'
3698 }
3699
3700 // Handle the last component [start, length).
3701 // If symbol ends up at = and it is not one of '[]=', '==', '<=' or
3702 // '>=' then we treat it as a setter symbol of form 'name=' and
3703 // obfuscate to rename('name') + '='.
3704 const bool is_setter = (length - start) > 1 &&
3705 name.CharAt(length - 1) == '=' &&
3706 !(name.Equals(Symbols::AssignIndexToken()) ||
3707 name.Equals(Symbols::EqualOperator()) ||
3708 name.Equals(Symbols::GreaterEqualOperator()) ||
3709 name.Equals(Symbols::LessEqualOperator()));
3710 const intptr_t end = length - (is_setter ? 1 : 0);
3711
3712 if ((start == 0) && (end == length) && name.IsSymbol()) {
3713 component = name.raw();
3714 } else {
3715 component = Symbols::New(thread, name, start, end - start);
3716 }
3717 component = obfuscator.Rename(component, /*atomic=*/true);
3718 renamed.Add(component);
3719
3720 if (is_setter) {
3721 renamed.Add(Symbols::Equals());
3722 }
3723
3724 name = Symbols::FromConcatAll(thread, renamed);
3725 symbol.RawSetFieldAtOffset(kSymbolNameOffset, name);
3726 }
3727
3728 void Obfuscator::Deobfuscate(Thread* thread,
3729 const GrowableObjectArray& pieces) {
3730 const Array& obfuscation_state = Array::Handle(
3731 thread->zone(), thread->isolate()->object_store()->obfuscation_map());
3732 if (obfuscation_state.IsNull()) {
3733 return;
3734 }
3735
3736 const Array& renames = Array::Handle(
3737 thread->zone(), GetRenamesFromSavedState(obfuscation_state));
3738
3739 ObfuscationMap renames_map(renames.raw());
3740 String& piece = String::Handle();
3741 for (intptr_t i = 0; i < pieces.Length(); i++) {
3742 piece ^= pieces.At(i);
3743 ASSERT(piece.IsSymbol());
3744
3745 // Fast path: skip '.'
3746 if (piece.raw() == Symbols::Dot().raw()) {
3747 continue;
3748 }
3749
3750 // Fast path: check if piece has an identity obfuscation.
3751 if (renames_map.GetOrNull(piece) == piece.raw()) {
3752 continue;
3753 }
3754
3755 ObfuscationMap::Iterator it(&renames_map);
3756 while (it.MoveNext()) {
3757 const intptr_t entry = it.Current();
3758 if (renames_map.GetPayload(entry, 0) == piece.raw()) {
3759 piece ^= renames_map.GetKey(entry);
3760 pieces.SetAt(i, piece);
3761 break;
3762 }
3763 }
3764 }
3765 renames_map.Release();
3766 }
3767
3768 static const char* StringToCString(const String& str) {
3769 const intptr_t len = Utf8::Length(str);
3770 char* result = new char[len + 1];
3771 str.ToUTF8(reinterpret_cast<uint8_t*>(result), len);
3772 result[len] = 0;
3773 return result;
3774 }
3775
3776 const char** Obfuscator::SerializeMap(Thread* thread) {
3777 const Array& obfuscation_state = Array::Handle(
3778 thread->zone(), thread->isolate()->object_store()->obfuscation_map());
3779 if (obfuscation_state.IsNull()) {
3780 return NULL;
3781 }
3782
3783 const Array& renames = Array::Handle(
3784 thread->zone(), GetRenamesFromSavedState(obfuscation_state));
3785 ObfuscationMap renames_map(renames.raw());
3786
3787 const char** result = new const char*[renames_map.NumOccupied() * 2 + 1];
3788 intptr_t idx = 0;
3789 String& str = String::Handle();
3790
3791 ObfuscationMap::Iterator it(&renames_map);
3792 while (it.MoveNext()) {
3793 const intptr_t entry = it.Current();
3794 str ^= renames_map.GetKey(entry);
3795 result[idx++] = StringToCString(str);
3796 str ^= renames_map.GetPayload(entry, 0);
3797 result[idx++] = StringToCString(str);
3798 }
3799 result[idx++] = NULL;
3800 renames_map.Release();
3801
3802 return result;
3803 }
3804
3333 #endif // DART_PRECOMPILER 3805 #endif // DART_PRECOMPILER
3334 3806
3335 } // namespace dart 3807 } // namespace dart
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698