OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // This clang plugin checks various invariants of the Blink garbage | 5 // This clang plugin checks various invariants of the Blink garbage |
6 // collection infrastructure. | 6 // collection infrastructure. |
7 // | 7 // |
8 // Errors are described at: | 8 // Errors are described at: |
9 // http://www.chromium.org/developers/blink-gc-plugin-errors | 9 // http://www.chromium.org/developers/blink-gc-plugin-errors |
10 | 10 |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
61 | 61 |
62 const char kOwnPtrToGCManagedClassNote[] = | 62 const char kOwnPtrToGCManagedClassNote[] = |
63 "[blink-gc] OwnPtr field %0 to a GC managed class declared here:"; | 63 "[blink-gc] OwnPtr field %0 to a GC managed class declared here:"; |
64 | 64 |
65 const char kStackAllocatedFieldNote[] = | 65 const char kStackAllocatedFieldNote[] = |
66 "[blink-gc] Stack-allocated field %0 declared here:"; | 66 "[blink-gc] Stack-allocated field %0 declared here:"; |
67 | 67 |
68 const char kMemberInUnmanagedClassNote[] = | 68 const char kMemberInUnmanagedClassNote[] = |
69 "[blink-gc] Member field %0 in unmanaged class declared here:"; | 69 "[blink-gc] Member field %0 in unmanaged class declared here:"; |
70 | 70 |
71 const char kPartObjectContainsGCRoot[] = | 71 const char kPartObjectToGCDerivedClassNote[] = |
| 72 "[blink-gc] Part-object field %0 to a GC derived class declared here:"; |
| 73 |
| 74 const char kPartObjectContainsGCRootNote[] = |
72 "[blink-gc] Field %0 with embedded GC root in %1 declared here:"; | 75 "[blink-gc] Field %0 with embedded GC root in %1 declared here:"; |
73 | 76 |
74 const char kFieldContainsGCRoot[] = | 77 const char kFieldContainsGCRootNote[] = |
75 "[blink-gc] Field %0 defining a GC root declared here:"; | 78 "[blink-gc] Field %0 defining a GC root declared here:"; |
76 | 79 |
77 const char kOverriddenNonVirtualTrace[] = | 80 const char kOverriddenNonVirtualTrace[] = |
78 "[blink-gc] Class %0 overrides non-virtual trace of base class %1."; | 81 "[blink-gc] Class %0 overrides non-virtual trace of base class %1."; |
79 | 82 |
80 const char kOverriddenNonVirtualTraceNote[] = | 83 const char kOverriddenNonVirtualTraceNote[] = |
81 "[blink-gc] Non-virtual trace method declared here:"; | 84 "[blink-gc] Non-virtual trace method declared here:"; |
82 | 85 |
83 const char kMissingTraceDispatchMethod[] = | 86 const char kMissingTraceDispatchMethod[] = |
84 "[blink-gc] Class %0 is missing manual trace dispatch."; | 87 "[blink-gc] Class %0 is missing manual trace dispatch."; |
(...skipping 353 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
438 gc_roots_.push_back(current_); | 441 gc_roots_.push_back(current_); |
439 } | 442 } |
440 | 443 |
441 protected: | 444 protected: |
442 RootPath current_; | 445 RootPath current_; |
443 Errors gc_roots_; | 446 Errors gc_roots_; |
444 }; | 447 }; |
445 | 448 |
446 // This visitor checks that the fields of a class are "well formed". | 449 // This visitor checks that the fields of a class are "well formed". |
447 // - OwnPtr, RefPtr and RawPtr must not point to a GC derived types. | 450 // - OwnPtr, RefPtr and RawPtr must not point to a GC derived types. |
| 451 // - Part objects must not be GC derived types. |
448 // - An on-heap class must never contain GC roots. | 452 // - An on-heap class must never contain GC roots. |
449 // - Only stack-allocated types may point to stack-allocated types. | 453 // - Only stack-allocated types may point to stack-allocated types. |
450 class CheckFieldsVisitor : public RecursiveEdgeVisitor { | 454 class CheckFieldsVisitor : public RecursiveEdgeVisitor { |
451 public: | 455 public: |
452 typedef std::vector<std::pair<FieldPoint*, Edge*> > Errors; | 456 |
| 457 enum Error { |
| 458 kRawPtrToGCManaged, |
| 459 kRefPtrToGCManaged, |
| 460 kOwnPtrToGCManaged, |
| 461 kMemberInUnmanaged, |
| 462 kPtrFromHeapToStack, |
| 463 kGCDerivedPartObject |
| 464 }; |
| 465 |
| 466 typedef std::vector<std::pair<FieldPoint*, Error> > Errors; |
453 | 467 |
454 CheckFieldsVisitor(const BlinkGCPluginOptions& options) | 468 CheckFieldsVisitor(const BlinkGCPluginOptions& options) |
455 : options_(options), current_(0), stack_allocated_host_(false) {} | 469 : options_(options), current_(0), stack_allocated_host_(false) {} |
456 | 470 |
457 Errors& invalid_fields() { return invalid_fields_; } | 471 Errors& invalid_fields() { return invalid_fields_; } |
458 | 472 |
459 bool ContainsInvalidFields(RecordInfo* info) { | 473 bool ContainsInvalidFields(RecordInfo* info) { |
460 stack_allocated_host_ = info->IsStackAllocated(); | 474 stack_allocated_host_ = info->IsStackAllocated(); |
461 managed_host_ = stack_allocated_host_ || | 475 managed_host_ = stack_allocated_host_ || |
462 info->IsGCAllocated() || | 476 info->IsGCAllocated() || |
(...skipping 12 matching lines...) Expand all Loading... |
475 void VisitMember(Member* edge) override { | 489 void VisitMember(Member* edge) override { |
476 if (managed_host_) | 490 if (managed_host_) |
477 return; | 491 return; |
478 // A member is allowed to appear in the context of a root. | 492 // A member is allowed to appear in the context of a root. |
479 for (Context::iterator it = context().begin(); | 493 for (Context::iterator it = context().begin(); |
480 it != context().end(); | 494 it != context().end(); |
481 ++it) { | 495 ++it) { |
482 if ((*it)->Kind() == Edge::kRoot) | 496 if ((*it)->Kind() == Edge::kRoot) |
483 return; | 497 return; |
484 } | 498 } |
485 invalid_fields_.push_back(std::make_pair(current_, edge)); | 499 invalid_fields_.push_back(std::make_pair(current_, kMemberInUnmanaged)); |
486 } | 500 } |
487 | 501 |
488 void VisitValue(Value* edge) override { | 502 void VisitValue(Value* edge) override { |
489 // TODO: what should we do to check unions? | 503 // TODO: what should we do to check unions? |
490 if (edge->value()->record()->isUnion()) | 504 if (edge->value()->record()->isUnion()) |
491 return; | 505 return; |
492 | 506 |
493 if (!stack_allocated_host_ && edge->value()->IsStackAllocated()) { | 507 if (!stack_allocated_host_ && edge->value()->IsStackAllocated()) { |
494 invalid_fields_.push_back(std::make_pair(current_, edge)); | 508 invalid_fields_.push_back(std::make_pair(current_, kPtrFromHeapToStack)); |
495 return; | 509 return; |
496 } | 510 } |
497 | 511 |
| 512 if (!Parent() && |
| 513 edge->value()->IsGCDerived() && |
| 514 !edge->value()->IsGCMixin()) { |
| 515 invalid_fields_.push_back(std::make_pair(current_, kGCDerivedPartObject)); |
| 516 return; |
| 517 } |
| 518 |
498 if (!Parent() || !edge->value()->IsGCAllocated()) | 519 if (!Parent() || !edge->value()->IsGCAllocated()) |
499 return; | 520 return; |
500 | 521 |
501 // In transition mode, disallow OwnPtr<T>, RawPtr<T> to GC allocated T's, | 522 // In transition mode, disallow OwnPtr<T>, RawPtr<T> to GC allocated T's, |
502 // also disallow T* in stack-allocated types. | 523 // also disallow T* in stack-allocated types. |
503 if (options_.enable_oilpan) { | 524 if (options_.enable_oilpan) { |
504 if (Parent()->IsOwnPtr() || | 525 if (Parent()->IsOwnPtr() || |
505 Parent()->IsRawPtrClass() || | 526 Parent()->IsRawPtrClass() || |
506 (stack_allocated_host_ && Parent()->IsRawPtr())) { | 527 (stack_allocated_host_ && Parent()->IsRawPtr())) { |
507 invalid_fields_.push_back(std::make_pair(current_, Parent())); | 528 invalid_fields_.push_back(std::make_pair( |
| 529 current_, InvalidSmartPtr(Parent()))); |
508 return; | 530 return; |
509 } | 531 } |
510 | 532 |
511 return; | 533 return; |
512 } | 534 } |
513 | 535 |
514 if (Parent()->IsRawPtr() || Parent()->IsRefPtr() || Parent()->IsOwnPtr()) { | 536 if (Parent()->IsRawPtr() || Parent()->IsRefPtr() || Parent()->IsOwnPtr()) { |
515 invalid_fields_.push_back(std::make_pair(current_, Parent())); | 537 invalid_fields_.push_back(std::make_pair( |
| 538 current_, InvalidSmartPtr(Parent()))); |
516 return; | 539 return; |
517 } | 540 } |
518 } | 541 } |
519 | 542 |
520 private: | 543 private: |
| 544 Error InvalidSmartPtr(Edge* ptr) { |
| 545 if (ptr->IsRawPtr()) |
| 546 return kRawPtrToGCManaged; |
| 547 if (ptr->IsRefPtr()) |
| 548 return kRefPtrToGCManaged; |
| 549 if (ptr->IsOwnPtr()) |
| 550 return kOwnPtrToGCManaged; |
| 551 assert(false && "Unknown smart pointer kind"); |
| 552 } |
| 553 |
521 const BlinkGCPluginOptions& options_; | 554 const BlinkGCPluginOptions& options_; |
522 FieldPoint* current_; | 555 FieldPoint* current_; |
523 bool stack_allocated_host_; | 556 bool stack_allocated_host_; |
524 bool managed_host_; | 557 bool managed_host_; |
525 Errors invalid_fields_; | 558 Errors invalid_fields_; |
526 }; | 559 }; |
527 | 560 |
528 // Main class containing checks for various invariants of the Blink | 561 // Main class containing checks for various invariants of the Blink |
529 // garbage collection infrastructure. | 562 // garbage collection infrastructure. |
530 class BlinkGCPluginConsumer : public ASTConsumer { | 563 class BlinkGCPluginConsumer : public ASTConsumer { |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
588 diag_raw_ptr_to_gc_managed_class_note_ = diagnostic_.getCustomDiagID( | 621 diag_raw_ptr_to_gc_managed_class_note_ = diagnostic_.getCustomDiagID( |
589 DiagnosticsEngine::Note, kRawPtrToGCManagedClassNote); | 622 DiagnosticsEngine::Note, kRawPtrToGCManagedClassNote); |
590 diag_ref_ptr_to_gc_managed_class_note_ = diagnostic_.getCustomDiagID( | 623 diag_ref_ptr_to_gc_managed_class_note_ = diagnostic_.getCustomDiagID( |
591 DiagnosticsEngine::Note, kRefPtrToGCManagedClassNote); | 624 DiagnosticsEngine::Note, kRefPtrToGCManagedClassNote); |
592 diag_own_ptr_to_gc_managed_class_note_ = diagnostic_.getCustomDiagID( | 625 diag_own_ptr_to_gc_managed_class_note_ = diagnostic_.getCustomDiagID( |
593 DiagnosticsEngine::Note, kOwnPtrToGCManagedClassNote); | 626 DiagnosticsEngine::Note, kOwnPtrToGCManagedClassNote); |
594 diag_stack_allocated_field_note_ = diagnostic_.getCustomDiagID( | 627 diag_stack_allocated_field_note_ = diagnostic_.getCustomDiagID( |
595 DiagnosticsEngine::Note, kStackAllocatedFieldNote); | 628 DiagnosticsEngine::Note, kStackAllocatedFieldNote); |
596 diag_member_in_unmanaged_class_note_ = diagnostic_.getCustomDiagID( | 629 diag_member_in_unmanaged_class_note_ = diagnostic_.getCustomDiagID( |
597 DiagnosticsEngine::Note, kMemberInUnmanagedClassNote); | 630 DiagnosticsEngine::Note, kMemberInUnmanagedClassNote); |
| 631 diag_part_object_to_gc_derived_class_note_ = diagnostic_.getCustomDiagID( |
| 632 DiagnosticsEngine::Note, kPartObjectToGCDerivedClassNote); |
598 diag_part_object_contains_gc_root_note_ = diagnostic_.getCustomDiagID( | 633 diag_part_object_contains_gc_root_note_ = diagnostic_.getCustomDiagID( |
599 DiagnosticsEngine::Note, kPartObjectContainsGCRoot); | 634 DiagnosticsEngine::Note, kPartObjectContainsGCRootNote); |
600 diag_field_contains_gc_root_note_ = diagnostic_.getCustomDiagID( | 635 diag_field_contains_gc_root_note_ = diagnostic_.getCustomDiagID( |
601 DiagnosticsEngine::Note, kFieldContainsGCRoot); | 636 DiagnosticsEngine::Note, kFieldContainsGCRootNote); |
602 diag_finalized_field_note_ = diagnostic_.getCustomDiagID( | 637 diag_finalized_field_note_ = diagnostic_.getCustomDiagID( |
603 DiagnosticsEngine::Note, kFinalizedFieldNote); | 638 DiagnosticsEngine::Note, kFinalizedFieldNote); |
604 diag_user_declared_destructor_note_ = diagnostic_.getCustomDiagID( | 639 diag_user_declared_destructor_note_ = diagnostic_.getCustomDiagID( |
605 DiagnosticsEngine::Note, kUserDeclaredDestructorNote); | 640 DiagnosticsEngine::Note, kUserDeclaredDestructorNote); |
606 diag_user_declared_finalizer_note_ = diagnostic_.getCustomDiagID( | 641 diag_user_declared_finalizer_note_ = diagnostic_.getCustomDiagID( |
607 DiagnosticsEngine::Note, kUserDeclaredFinalizerNote); | 642 DiagnosticsEngine::Note, kUserDeclaredFinalizerNote); |
608 diag_base_requires_finalization_note_ = diagnostic_.getCustomDiagID( | 643 diag_base_requires_finalization_note_ = diagnostic_.getCustomDiagID( |
609 DiagnosticsEngine::Note, kBaseRequiresFinalizationNote); | 644 DiagnosticsEngine::Note, kBaseRequiresFinalizationNote); |
610 diag_field_requires_finalization_note_ = diagnostic_.getCustomDiagID( | 645 diag_field_requires_finalization_note_ = diagnostic_.getCustomDiagID( |
611 DiagnosticsEngine::Note, kFieldRequiresFinalizationNote); | 646 DiagnosticsEngine::Note, kFieldRequiresFinalizationNote); |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
710 ReportClassRequiresTraceMethod(info); | 745 ReportClassRequiresTraceMethod(info); |
711 } | 746 } |
712 | 747 |
713 { | 748 { |
714 CheckFieldsVisitor visitor(options_); | 749 CheckFieldsVisitor visitor(options_); |
715 if (visitor.ContainsInvalidFields(info)) | 750 if (visitor.ContainsInvalidFields(info)) |
716 ReportClassContainsInvalidFields(info, &visitor.invalid_fields()); | 751 ReportClassContainsInvalidFields(info, &visitor.invalid_fields()); |
717 } | 752 } |
718 | 753 |
719 if (info->IsGCDerived()) { | 754 if (info->IsGCDerived()) { |
720 CheckLeftMostDerived(info); | |
721 | 755 |
722 CheckDispatch(info); | 756 if (!info->IsGCMixin()) { |
723 | 757 CheckLeftMostDerived(info); |
724 if (CXXMethodDecl* newop = info->DeclaresNewOperator()) | 758 CheckDispatch(info); |
725 ReportClassOverridesNew(info, newop); | 759 if (CXXMethodDecl* newop = info->DeclaresNewOperator()) |
| 760 ReportClassOverridesNew(info, newop); |
| 761 } |
726 | 762 |
727 { | 763 { |
728 CheckGCRootsVisitor visitor; | 764 CheckGCRootsVisitor visitor; |
729 if (visitor.ContainsGCRoots(info)) | 765 if (visitor.ContainsGCRoots(info)) |
730 ReportClassContainsGCRoots(info, &visitor.gc_roots()); | 766 ReportClassContainsGCRoots(info, &visitor.gc_roots()); |
731 } | 767 } |
732 | 768 |
733 if (info->NeedsFinalization()) | 769 if (info->NeedsFinalization()) |
734 CheckFinalization(info); | 770 CheckFinalization(info); |
735 } | 771 } |
(...skipping 406 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1142 void ReportClassContainsInvalidFields(RecordInfo* info, | 1178 void ReportClassContainsInvalidFields(RecordInfo* info, |
1143 CheckFieldsVisitor::Errors* errors) { | 1179 CheckFieldsVisitor::Errors* errors) { |
1144 SourceLocation loc = info->record()->getLocStart(); | 1180 SourceLocation loc = info->record()->getLocStart(); |
1145 SourceManager& manager = instance_.getSourceManager(); | 1181 SourceManager& manager = instance_.getSourceManager(); |
1146 FullSourceLoc full_loc(loc, manager); | 1182 FullSourceLoc full_loc(loc, manager); |
1147 diagnostic_.Report(full_loc, diag_class_contains_invalid_fields_) | 1183 diagnostic_.Report(full_loc, diag_class_contains_invalid_fields_) |
1148 << info->record(); | 1184 << info->record(); |
1149 for (CheckFieldsVisitor::Errors::iterator it = errors->begin(); | 1185 for (CheckFieldsVisitor::Errors::iterator it = errors->begin(); |
1150 it != errors->end(); | 1186 it != errors->end(); |
1151 ++it) { | 1187 ++it) { |
1152 if (it->second->IsRawPtr()) { | 1188 unsigned error; |
1153 NoteField(it->first, diag_raw_ptr_to_gc_managed_class_note_); | 1189 if (it->second == CheckFieldsVisitor::kRawPtrToGCManaged) { |
1154 } else if (it->second->IsRefPtr()) { | 1190 error = diag_raw_ptr_to_gc_managed_class_note_; |
1155 NoteField(it->first, diag_ref_ptr_to_gc_managed_class_note_); | 1191 } else if (it->second == CheckFieldsVisitor::kRefPtrToGCManaged) { |
1156 } else if (it->second->IsOwnPtr()) { | 1192 error = diag_ref_ptr_to_gc_managed_class_note_; |
1157 NoteField(it->first, diag_own_ptr_to_gc_managed_class_note_); | 1193 } else if (it->second == CheckFieldsVisitor::kOwnPtrToGCManaged) { |
1158 } else if (it->second->IsMember()) { | 1194 error = diag_own_ptr_to_gc_managed_class_note_; |
1159 NoteField(it->first, diag_member_in_unmanaged_class_note_); | 1195 } else if (it->second == CheckFieldsVisitor::kMemberInUnmanaged) { |
1160 } else if (it->second->IsValue()) { | 1196 error = diag_member_in_unmanaged_class_note_; |
1161 NoteField(it->first, diag_stack_allocated_field_note_); | 1197 } else if (it->second == CheckFieldsVisitor::kPtrFromHeapToStack) { |
| 1198 error = diag_stack_allocated_field_note_; |
| 1199 } else if (it->second == CheckFieldsVisitor::kGCDerivedPartObject) { |
| 1200 error = diag_part_object_to_gc_derived_class_note_; |
| 1201 } else { |
| 1202 assert(false && "Unknown field error"); |
1162 } | 1203 } |
| 1204 NoteField(it->first, error); |
1163 } | 1205 } |
1164 } | 1206 } |
1165 | 1207 |
1166 void ReportClassContainsGCRoots(RecordInfo* info, | 1208 void ReportClassContainsGCRoots(RecordInfo* info, |
1167 CheckGCRootsVisitor::Errors* errors) { | 1209 CheckGCRootsVisitor::Errors* errors) { |
1168 SourceLocation loc = info->record()->getLocStart(); | 1210 SourceLocation loc = info->record()->getLocStart(); |
1169 SourceManager& manager = instance_.getSourceManager(); | 1211 SourceManager& manager = instance_.getSourceManager(); |
1170 FullSourceLoc full_loc(loc, manager); | 1212 FullSourceLoc full_loc(loc, manager); |
1171 for (CheckGCRootsVisitor::Errors::iterator it = errors->begin(); | 1213 for (CheckGCRootsVisitor::Errors::iterator it = errors->begin(); |
1172 it != errors->end(); | 1214 it != errors->end(); |
(...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1376 unsigned diag_class_overrides_new_; | 1418 unsigned diag_class_overrides_new_; |
1377 unsigned diag_class_declares_pure_virtual_trace_; | 1419 unsigned diag_class_declares_pure_virtual_trace_; |
1378 | 1420 |
1379 unsigned diag_base_requires_tracing_note_; | 1421 unsigned diag_base_requires_tracing_note_; |
1380 unsigned diag_field_requires_tracing_note_; | 1422 unsigned diag_field_requires_tracing_note_; |
1381 unsigned diag_raw_ptr_to_gc_managed_class_note_; | 1423 unsigned diag_raw_ptr_to_gc_managed_class_note_; |
1382 unsigned diag_ref_ptr_to_gc_managed_class_note_; | 1424 unsigned diag_ref_ptr_to_gc_managed_class_note_; |
1383 unsigned diag_own_ptr_to_gc_managed_class_note_; | 1425 unsigned diag_own_ptr_to_gc_managed_class_note_; |
1384 unsigned diag_stack_allocated_field_note_; | 1426 unsigned diag_stack_allocated_field_note_; |
1385 unsigned diag_member_in_unmanaged_class_note_; | 1427 unsigned diag_member_in_unmanaged_class_note_; |
| 1428 unsigned diag_part_object_to_gc_derived_class_note_; |
1386 unsigned diag_part_object_contains_gc_root_note_; | 1429 unsigned diag_part_object_contains_gc_root_note_; |
1387 unsigned diag_field_contains_gc_root_note_; | 1430 unsigned diag_field_contains_gc_root_note_; |
1388 unsigned diag_finalized_field_note_; | 1431 unsigned diag_finalized_field_note_; |
1389 unsigned diag_user_declared_destructor_note_; | 1432 unsigned diag_user_declared_destructor_note_; |
1390 unsigned diag_user_declared_finalizer_note_; | 1433 unsigned diag_user_declared_finalizer_note_; |
1391 unsigned diag_base_requires_finalization_note_; | 1434 unsigned diag_base_requires_finalization_note_; |
1392 unsigned diag_field_requires_finalization_note_; | 1435 unsigned diag_field_requires_finalization_note_; |
1393 unsigned diag_overridden_non_virtual_trace_note_; | 1436 unsigned diag_overridden_non_virtual_trace_note_; |
1394 unsigned diag_manual_dispatch_method_note_; | 1437 unsigned diag_manual_dispatch_method_note_; |
1395 | 1438 |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1431 | 1474 |
1432 private: | 1475 private: |
1433 BlinkGCPluginOptions options_; | 1476 BlinkGCPluginOptions options_; |
1434 }; | 1477 }; |
1435 | 1478 |
1436 } // namespace | 1479 } // namespace |
1437 | 1480 |
1438 static FrontendPluginRegistry::Add<BlinkGCPluginAction> X( | 1481 static FrontendPluginRegistry::Add<BlinkGCPluginAction> X( |
1439 "blink-gc-plugin", | 1482 "blink-gc-plugin", |
1440 "Check Blink GC invariants"); | 1483 "Check Blink GC invariants"); |
OLD | NEW |