1 // Copyright 2011 the V8 project authors. All rights reserved. 2 // Redistribution and use in source and binary forms, with or without 3 // modification, are permitted provided that the following conditions are 4 // met: 5 // 6 // * Redistributions of source code must retain the above copyright 7 // notice, this list of conditions and the following disclaimer. 8 // * Redistributions in binary form must reproduce the above 9 // copyright notice, this list of conditions and the following 10 // disclaimer in the documentation and/or other materials provided 11 // with the distribution. 12 // * Neither the name of Google Inc. nor the names of its 13 // contributors may be used to endorse or promote products derived 14 // from this software without specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28 // This is clang plugin used by gcmole tool. See README for more details. 29 30 #include "clang/AST/AST.h" 31 #include "clang/AST/ASTConsumer.h" 32 #include "clang/AST/Mangle.h" 33 #include "clang/AST/RecursiveASTVisitor.h" 34 #include "clang/AST/StmtVisitor.h" 35 #include "clang/Frontend/FrontendPluginRegistry.h" 36 #include "clang/Frontend/CompilerInstance.h" 37 #include "llvm/Support/raw_ostream.h" 38 39 #include <bitset> 40 #include <fstream> 41 #include <iostream> 42 #include <map> 43 #include <set> 44 #include <stack> 45 46 namespace { 47 48 typedef std::string MangledName; 49 typedef std::set<MangledName> CalleesSet; 50 51 static bool GetMangledName(clang::MangleContext* ctx, 52 const clang::NamedDecl* decl, 53 MangledName* result) { 54 if (!isa<clang::CXXConstructorDecl>(decl) && 55 !isa<clang::CXXDestructorDecl>(decl)) { 56 llvm::SmallVector<char, 512> output; 57 llvm::raw_svector_ostream out(output); 58 ctx->mangleName(decl, out); 59 *result = out.str().str(); 60 return true; 61 } 62 63 return false; 64 } 65 66 67 static bool InV8Namespace(const clang::NamedDecl* decl) { 68 return decl->getQualifiedNameAsString().compare(0, 4, "v8::") == 0; 69 } 70 71 72 static std::string EXTERNAL("EXTERNAL"); 73 static std::string STATE_TAG("enum v8::internal::StateTag"); 74 75 static bool IsExternalVMState(const clang::ValueDecl* var) { 76 const clang::EnumConstantDecl* enum_constant = 77 dyn_cast<clang::EnumConstantDecl>(var); 78 if (enum_constant != NULL && enum_constant->getNameAsString() == EXTERNAL) { 79 clang::QualType type = enum_constant->getType(); 80 return (type.getAsString() == STATE_TAG); 81 } 82 83 return false; 84 } 85 86 87 struct Resolver { 88 explicit Resolver(clang::ASTContext& ctx) 89 : ctx_(ctx), decl_ctx_(ctx.getTranslationUnitDecl()) { 90 } 91 92 Resolver(clang::ASTContext& ctx, clang::DeclContext* decl_ctx) 93 : ctx_(ctx), decl_ctx_(decl_ctx) { 94 } 95 96 clang::DeclarationName ResolveName(const char* n) { 97 clang::IdentifierInfo* ident = &ctx_.Idents.get(n); 98 return ctx_.DeclarationNames.getIdentifier(ident); 99 } 100 101 Resolver ResolveNamespace(const char* n) { 102 return Resolver(ctx_, Resolve<clang::NamespaceDecl>(n)); 103 } 104 105 template<typename T> 106 T* Resolve(const char* n) { 107 if (decl_ctx_ == NULL) return NULL; 108 109 clang::DeclContext::lookup_result result = 110 decl_ctx_->lookup(ResolveName(n)); 111 112 clang::DeclContext::lookup_iterator end = result.second; 113 for (clang::DeclContext::lookup_iterator i = result.first; 114 i != end; 115 i++) { 116 if (isa<T>(*i)) return cast<T>(*i); 117 } 118 119 return NULL; 120 } 121 122 private: 123 clang::ASTContext& ctx_; 124 clang::DeclContext* decl_ctx_; 125 }; 126 127 128 class CalleesPrinter : public clang::RecursiveASTVisitor<CalleesPrinter> { 129 public: 130 explicit CalleesPrinter(clang::MangleContext* ctx) : ctx_(ctx) { 131 } 132 133 virtual bool VisitCallExpr(clang::CallExpr* expr) { 134 const clang::FunctionDecl* callee = expr->getDirectCallee(); 135 if (callee != NULL) AnalyzeFunction(callee); 136 return true; 137 } 138 139 virtual bool VisitDeclRefExpr(clang::DeclRefExpr* expr) { 140 // If function mentions EXTERNAL VMState add artificial garbage collection 141 // mark. 142 if (IsExternalVMState(expr->getDecl())) AddCallee("CollectGarbage"); 143 return true; 144 } 145 146 void AnalyzeFunction(const clang::FunctionDecl* f) { 147 MangledName name; 148 if (InV8Namespace(f) && GetMangledName(ctx_, f, &name)) { 149 AddCallee(name); 150 151 const clang::FunctionDecl* body = NULL; 152 if (f->hasBody(body) && !Analyzed(name)) { 153 EnterScope(name); 154 TraverseStmt(body->getBody()); 155 LeaveScope(); 156 } 157 } 158 } 159 160 typedef std::map<MangledName, CalleesSet* > Callgraph; 161 162 bool Analyzed(const MangledName& name) { 163 return callgraph_[name] != NULL; 164 } 165 166 void EnterScope(const MangledName& name) { 167 CalleesSet* callees = callgraph_[name]; 168 169 if (callees == NULL) { 170 callgraph_[name] = callees = new CalleesSet(); 171 } 172 173 scopes_.push(callees); 174 } 175 176 void LeaveScope() { 177 scopes_.pop(); 178 } 179 180 void AddCallee(const MangledName& name) { 181 if (!scopes_.empty()) scopes_.top()->insert(name); 182 } 183 184 void PrintCallGraph() { 185 for (Callgraph::const_iterator i = callgraph_.begin(), e = callgraph_.end(); 186 i != e; 187 ++i) { 188 std::cout << i->first << "\n"; 189 190 CalleesSet* callees = i->second; 191 for (CalleesSet::const_iterator j = callees->begin(), e = callees->end(); 192 j != e; 193 ++j) { 194 std::cout << "\t" << *j << "\n"; 195 } 196 } 197 } 198 199 private: 200 clang::MangleContext* ctx_; 201 202 std::stack<CalleesSet* > scopes_; 203 Callgraph callgraph_; 204 }; 205 206 207 class FunctionDeclarationFinder 208 : public clang::ASTConsumer, 209 public clang::RecursiveASTVisitor<FunctionDeclarationFinder> { 210 public: 211 explicit FunctionDeclarationFinder(clang::Diagnostic& d, 212 clang::SourceManager& sm, 213 const std::vector<std::string>& args) 214 : d_(d), sm_(sm) { } 215 216 virtual void HandleTranslationUnit(clang::ASTContext &ctx) { 217 mangle_context_ = clang::createItaniumMangleContext(ctx, d_); 218 callees_printer_ = new CalleesPrinter(mangle_context_); 219 220 TraverseDecl(ctx.getTranslationUnitDecl()); 221 222 callees_printer_->PrintCallGraph(); 223 } 224 225 virtual bool VisitFunctionDecl(clang::FunctionDecl* decl) { 226 callees_printer_->AnalyzeFunction(decl); 227 return true; 228 } 229 230 private: 231 clang::Diagnostic& d_; 232 clang::SourceManager& sm_; 233 clang::MangleContext* mangle_context_; 234 235 CalleesPrinter* callees_printer_; 236 }; 237 238 239 static bool loaded = false; 240 static CalleesSet gc_suspects; 241 242 243 static void LoadGCSuspects() { 244 if (loaded) return; 245 246 std::ifstream fin("gcsuspects"); 247 std::string s; 248 249 while (fin >> s) gc_suspects.insert(s); 250 251 loaded = true; 252 } 253 254 255 static bool KnownToCauseGC(clang::MangleContext* ctx, 256 const clang::FunctionDecl* decl) { 257 LoadGCSuspects(); 258 259 if (!InV8Namespace(decl)) return false; 260 261 MangledName name; 262 if (GetMangledName(ctx, decl, &name)) { 263 return gc_suspects.find(name) != gc_suspects.end(); 264 } 265 266 return false; 267 } 268 269 270 static const int kNoEffect = 0; 271 static const int kCausesGC = 1; 272 static const int kRawDef = 2; 273 static const int kRawUse = 4; 274 static const int kAllEffects = kCausesGC | kRawDef | kRawUse; 275 276 class Environment; 277 278 class ExprEffect { 279 public: 280 bool hasGC() { return (effect_ & kCausesGC) != 0; } 281 void setGC() { effect_ |= kCausesGC; } 282 283 bool hasRawDef() { return (effect_ & kRawDef) != 0; } 284 void setRawDef() { effect_ |= kRawDef; } 285 286 bool hasRawUse() { return (effect_ & kRawUse) != 0; } 287 void setRawUse() { effect_ |= kRawUse; } 288 289 static ExprEffect None() { return ExprEffect(kNoEffect, NULL); } 290 static ExprEffect NoneWithEnv(Environment* env) { 291 return ExprEffect(kNoEffect, env); 292 } 293 static ExprEffect RawUse() { return ExprEffect(kRawUse, NULL); } 294 295 static ExprEffect Merge(ExprEffect a, ExprEffect b); 296 static ExprEffect MergeSeq(ExprEffect a, ExprEffect b); 297 ExprEffect Define(const std::string& name); 298 299 Environment* env() { 300 return reinterpret_cast<Environment*>(effect_ & ~kAllEffects); 301 } 302 303 static ExprEffect GC() { 304 return ExprEffect(kCausesGC, NULL); 305 } 306 307 private: 308 ExprEffect(int effect, Environment* env) 309 : effect_((effect & kAllEffects) | 310 reinterpret_cast<intptr_t>(env)) { } 311 312 intptr_t effect_; 313 }; 314 315 316 const std::string BAD_EXPR_MSG("Possible problem with evaluation order."); 317 const std::string DEAD_VAR_MSG("Possibly dead variable."); 318 319 320 class Environment { 321 public: 322 Environment() { } 323 324 static Environment Unreachable() { 325 Environment env; 326 env.live_.set(); 327 return env; 328 } 329 330 static Environment Merge(const Environment& l, 331 const Environment& r) { 332 return Environment(l, r); 333 } 334 335 Environment ApplyEffect(ExprEffect effect) const { 336 Environment out = effect.hasGC() ? Environment() : Environment(*this); 337 if (effect.env() != NULL) out.live_ |= effect.env()->live_; 338 return out; 339 } 340 341 typedef std::map<std::string, int> SymbolTable; 342 343 bool IsAlive(const std::string& name) const { 344 SymbolTable::iterator code = symbol_table_.find(name); 345 if (code == symbol_table_.end()) return false; 346 return live_[code->second]; 347 } 348 349 bool Equal(const Environment& env) { 350 return live_ == env.live_; 351 } 352 353 Environment Define(const std::string& name) const { 354 return Environment(*this, SymbolToCode(name)); 355 } 356 357 void MDefine(const std::string& name) { 358 live_.set(SymbolToCode(name)); 359 } 360 361 static int SymbolToCode(const std::string& name) { 362 SymbolTable::iterator code = symbol_table_.find(name); 363 364 if (code == symbol_table_.end()) { 365 int new_code = symbol_table_.size(); 366 symbol_table_.insert(std::make_pair(name, new_code)); 367 return new_code; 368 } 369 370 return code->second; 371 } 372 373 static void ClearSymbolTable() { 374 std::vector<Environment*>::iterator end = envs_.end(); 375 for (std::vector<Environment*>::iterator i = envs_.begin(); 376 i != end; 377 ++i) { 378 delete *i; 379 } 380 envs_.clear(); 381 symbol_table_.clear(); 382 } 383 384 void Print() const { 385 bool comma = false; 386 std::cout << "{"; 387 SymbolTable::iterator end = symbol_table_.end(); 388 for (SymbolTable::iterator i = symbol_table_.begin(); 389 i != end; 390 ++i) { 391 if (live_[i->second]) { 392 if (comma) std::cout << ", "; 393 std::cout << i->first; 394 comma = true; 395 } 396 } 397 std::cout << "}"; 398 } 399 400 static Environment* Allocate(const Environment& env) { 401 Environment* allocated_env = new Environment(env); 402 envs_.push_back(allocated_env); 403 return allocated_env; 404 } 405 406 private: 407 Environment(const Environment& l, const Environment& r) 408 : live_(l.live_ & r.live_) { 409 } 410 411 Environment(const Environment& l, int code) 412 : live_(l.live_) { 413 live_.set(code); 414 } 415 416 static SymbolTable symbol_table_; 417 static std::vector<Environment* > envs_; 418 419 static const int kMaxNumberOfLocals = 256; 420 std::bitset<kMaxNumberOfLocals> live_; 421 422 friend class ExprEffect; 423 friend class CallProps; 424 }; 425 426 427 class CallProps { 428 public: 429 CallProps() : env_(NULL) { } 430 431 void SetEffect(int arg, ExprEffect in) { 432 if (in.hasGC()) gc_.set(arg); 433 if (in.hasRawDef()) raw_def_.set(arg); 434 if (in.hasRawUse()) raw_use_.set(arg); 435 if (in.env() != NULL) { 436 if (env_ == NULL) env_ = in.env(); 437 env_->live_ |= in.env()->live_; 438 } 439 } 440 441 ExprEffect ComputeCumulativeEffect(bool result_is_raw) { 442 ExprEffect out = ExprEffect::NoneWithEnv(env_); 443 if (gc_.any()) out.setGC(); 444 if (raw_use_.any()) out.setRawUse(); 445 if (result_is_raw) out.setRawDef(); 446 return out; 447 } 448 449 bool IsSafe() { 450 if (!gc_.any()) return true; 451 std::bitset<kMaxNumberOfArguments> raw = (raw_def_ | raw_use_); 452 if (!raw.any()) return true; 453 return gc_.count() == 1 && !((raw ^ gc_).any()); 454 } 455 456 private: 457 static const int kMaxNumberOfArguments = 64; 458 std::bitset<kMaxNumberOfArguments> raw_def_; 459 std::bitset<kMaxNumberOfArguments> raw_use_; 460 std::bitset<kMaxNumberOfArguments> gc_; 461 Environment* env_; 462 }; 463 464 465 Environment::SymbolTable Environment::symbol_table_; 466 std::vector<Environment* > Environment::envs_; 467 468 469 ExprEffect ExprEffect::Merge(ExprEffect a, ExprEffect b) { 470 Environment* a_env = a.env(); 471 Environment* b_env = b.env(); 472 Environment* out = NULL; 473 if (a_env != NULL && b_env != NULL) { 474 out = Environment::Allocate(*a_env); 475 out->live_ &= b_env->live_; 476 } 477 return ExprEffect(a.effect_ | b.effect_, out); 478 } 479 480 481 ExprEffect ExprEffect::MergeSeq(ExprEffect a, ExprEffect b) { 482 Environment* a_env = b.hasGC() ? NULL : a.env(); 483 Environment* b_env = b.env(); 484 Environment* out = (b_env == NULL) ? a_env : b_env; 485 if (a_env != NULL && b_env != NULL) { 486 out = Environment::Allocate(*b_env); 487 out->live_ |= a_env->live_; 488 } 489 return ExprEffect(a.effect_ | b.effect_, out); 490 } 491 492 493 ExprEffect ExprEffect::Define(const std::string& name) { 494 Environment* e = env(); 495 if (e == NULL) { 496 e = Environment::Allocate(Environment()); 497 } 498 e->MDefine(name); 499 return ExprEffect(effect_, e); 500 } 501 502 503 static std::string THIS ("this"); 504 505 506 class FunctionAnalyzer { 507 public: 508 FunctionAnalyzer(clang::MangleContext* ctx, 509 clang::DeclarationName handle_decl_name, 510 clang::CXXRecordDecl* object_decl, 511 clang::CXXRecordDecl* smi_decl, 512 clang::Diagnostic& d, 513 clang::SourceManager& sm, 514 bool dead_vars_analysis) 515 : ctx_(ctx), 516 handle_decl_name_(handle_decl_name), 517 object_decl_(object_decl), 518 smi_decl_(smi_decl), 519 d_(d), 520 sm_(sm), 521 block_(NULL), 522 dead_vars_analysis_(dead_vars_analysis) { 523 } 524 525 526 // -------------------------------------------------------------------------- 527 // Expressions 528 // -------------------------------------------------------------------------- 529 530 ExprEffect VisitExpr(clang::Expr* expr, const Environment& env) { 531 #define VISIT(type) do { \ 532 clang::type* concrete_expr = dyn_cast_or_null<clang::type>(expr); \ 533 if (concrete_expr != NULL) { \ 534 return Visit##type (concrete_expr, env); \ 535 } \ 536 } while(0); 537 538 VISIT(AbstractConditionalOperator); 539 VISIT(AddrLabelExpr); 540 VISIT(ArraySubscriptExpr); 541 VISIT(BinaryOperator); 542 VISIT(BinaryTypeTraitExpr); 543 VISIT(BlockDeclRefExpr); 544 VISIT(BlockExpr); 545 VISIT(CallExpr); 546 VISIT(CastExpr); 547 VISIT(CharacterLiteral); 548 VISIT(ChooseExpr); 549 VISIT(CompoundLiteralExpr); 550 VISIT(CXXBindTemporaryExpr); 551 VISIT(CXXBoolLiteralExpr); 552 VISIT(CXXConstructExpr); 553 VISIT(CXXDefaultArgExpr); 554 VISIT(CXXDeleteExpr); 555 VISIT(CXXDependentScopeMemberExpr); 556 VISIT(CXXNewExpr); 557 VISIT(CXXNoexceptExpr); 558 VISIT(CXXNullPtrLiteralExpr); 559 VISIT(CXXPseudoDestructorExpr); 560 VISIT(CXXScalarValueInitExpr); 561 VISIT(CXXThisExpr); 562 VISIT(CXXThrowExpr); 563 VISIT(CXXTypeidExpr); 564 VISIT(CXXUnresolvedConstructExpr); 565 VISIT(CXXUuidofExpr); 566 VISIT(DeclRefExpr); 567 VISIT(DependentScopeDeclRefExpr); 568 VISIT(DesignatedInitExpr); 569 VISIT(ExprWithCleanups); 570 VISIT(ExtVectorElementExpr); 571 VISIT(FloatingLiteral); 572 VISIT(GNUNullExpr); 573 VISIT(ImaginaryLiteral); 574 VISIT(ImplicitValueInitExpr); 575 VISIT(InitListExpr); 576 VISIT(IntegerLiteral); 577 VISIT(MemberExpr); 578 VISIT(OffsetOfExpr); 579 VISIT(OpaqueValueExpr); 580 VISIT(OverloadExpr); 581 VISIT(PackExpansionExpr); 582 VISIT(ParenExpr); 583 VISIT(ParenListExpr); 584 VISIT(PredefinedExpr); 585 VISIT(ShuffleVectorExpr); 586 VISIT(SizeOfPackExpr); 587 VISIT(StmtExpr); 588 VISIT(StringLiteral); 589 VISIT(SubstNonTypeTemplateParmPackExpr); 590 VISIT(UnaryOperator); 591 VISIT(UnaryTypeTraitExpr); 592 VISIT(VAArgExpr); 593 #undef VISIT 594 595 return ExprEffect::None(); 596 } 597 598 #define DECL_VISIT_EXPR(type) \ 599 ExprEffect Visit##type (clang::type* expr, const Environment& env) 600 601 #define IGNORE_EXPR(type) \ 602 ExprEffect Visit##type (clang::type* expr, const Environment& env) { \ 603 return ExprEffect::None(); \ 604 } 605 606 IGNORE_EXPR(AddrLabelExpr); 607 IGNORE_EXPR(BinaryTypeTraitExpr); 608 IGNORE_EXPR(BlockExpr); 609 IGNORE_EXPR(CharacterLiteral); 610 IGNORE_EXPR(ChooseExpr); 611 IGNORE_EXPR(CompoundLiteralExpr); 612 IGNORE_EXPR(CXXBoolLiteralExpr); 613 IGNORE_EXPR(CXXDependentScopeMemberExpr); 614 IGNORE_EXPR(CXXNullPtrLiteralExpr); 615 IGNORE_EXPR(CXXPseudoDestructorExpr); 616 IGNORE_EXPR(CXXScalarValueInitExpr); 617 IGNORE_EXPR(CXXNoexceptExpr); 618 IGNORE_EXPR(CXXTypeidExpr); 619 IGNORE_EXPR(CXXUnresolvedConstructExpr); 620 IGNORE_EXPR(CXXUuidofExpr); 621 IGNORE_EXPR(DependentScopeDeclRefExpr); 622 IGNORE_EXPR(DesignatedInitExpr); 623 IGNORE_EXPR(ExtVectorElementExpr); 624 IGNORE_EXPR(FloatingLiteral); 625 IGNORE_EXPR(ImaginaryLiteral); 626 IGNORE_EXPR(IntegerLiteral); 627 IGNORE_EXPR(OffsetOfExpr); 628 IGNORE_EXPR(ImplicitValueInitExpr); 629 IGNORE_EXPR(PackExpansionExpr); 630 IGNORE_EXPR(PredefinedExpr); 631 IGNORE_EXPR(ShuffleVectorExpr); 632 IGNORE_EXPR(SizeOfPackExpr); 633 IGNORE_EXPR(StmtExpr); 634 IGNORE_EXPR(StringLiteral); 635 IGNORE_EXPR(SubstNonTypeTemplateParmPackExpr); 636 IGNORE_EXPR(UnaryTypeTraitExpr); 637 IGNORE_EXPR(VAArgExpr); 638 IGNORE_EXPR(GNUNullExpr); 639 IGNORE_EXPR(OverloadExpr); 640 641 DECL_VISIT_EXPR(CXXThisExpr) { 642 return Use(expr, expr->getType(), THIS, env); 643 } 644 645 DECL_VISIT_EXPR(AbstractConditionalOperator) { 646 Environment after_cond = env.ApplyEffect(VisitExpr(expr->getCond(), env)); 647 return ExprEffect::Merge(VisitExpr(expr->getTrueExpr(), after_cond), 648 VisitExpr(expr->getFalseExpr(), after_cond)); 649 } 650 651 DECL_VISIT_EXPR(ArraySubscriptExpr) { 652 clang::Expr* exprs[2] = {expr->getBase(), expr->getIdx()}; 653 return Par(expr, 2, exprs, env); 654 } 655 656 bool IsRawPointerVar(clang::Expr* expr, std::string* var_name) { 657 if (isa<clang::BlockDeclRefExpr>(expr)) { 658 *var_name = cast<clang::BlockDeclRefExpr>(expr)->getDecl()-> 659 getNameAsString(); 660 return true; 661 } else if (isa<clang::DeclRefExpr>(expr)) { 662 *var_name = cast<clang::DeclRefExpr>(expr)->getDecl()->getNameAsString(); 663 return true; 664 } 665 return false; 666 } 667 668 DECL_VISIT_EXPR(BinaryOperator) { 669 clang::Expr* lhs = expr->getLHS(); 670 clang::Expr* rhs = expr->getRHS(); 671 clang::Expr* exprs[2] = {lhs, rhs}; 672 673 switch (expr->getOpcode()) { 674 case clang::BO_Comma: 675 return Seq(expr, 2, exprs, env); 676 677 case clang::BO_LAnd: 678 case clang::BO_LOr: 679 return ExprEffect::Merge(VisitExpr(lhs, env), VisitExpr(rhs, env)); 680 681 case clang::BO_Assign: { 682 std::string var_name; 683 if (IsRawPointerVar(lhs, &var_name)) { 684 return VisitExpr(rhs, env).Define(var_name); 685 } 686 return Par(expr, 2, exprs, env); 687 } 688 689 default: 690 return Par(expr, 2, exprs, env); 691 } 692 } 693 694 DECL_VISIT_EXPR(CXXBindTemporaryExpr) { 695 return VisitExpr(expr->getSubExpr(), env); 696 } 697 698 DECL_VISIT_EXPR(CXXConstructExpr) { 699 return VisitArguments<>(expr, env); 700 } 701 702 DECL_VISIT_EXPR(CXXDefaultArgExpr) { 703 return VisitExpr(expr->getExpr(), env); 704 } 705 706 DECL_VISIT_EXPR(CXXDeleteExpr) { 707 return VisitExpr(expr->getArgument(), env); 708 } 709 710 DECL_VISIT_EXPR(CXXNewExpr) { 711 return Par(expr, 712 expr->getNumConstructorArgs(), 713 expr->getConstructorArgs(), 714 env); 715 } 716 717 DECL_VISIT_EXPR(ExprWithCleanups) { 718 return VisitExpr(expr->getSubExpr(), env); 719 } 720 721 DECL_VISIT_EXPR(CXXThrowExpr) { 722 return VisitExpr(expr->getSubExpr(), env); 723 } 724 725 DECL_VISIT_EXPR(InitListExpr) { 726 return Seq(expr, expr->getNumInits(), expr->getInits(), env); 727 } 728 729 DECL_VISIT_EXPR(MemberExpr) { 730 return VisitExpr(expr->getBase(), env); 731 } 732 733 DECL_VISIT_EXPR(OpaqueValueExpr) { 734 return VisitExpr(expr->getSourceExpr(), env); 735 } 736 737 DECL_VISIT_EXPR(ParenExpr) { 738 return VisitExpr(expr->getSubExpr(), env); 739 } 740 741 DECL_VISIT_EXPR(ParenListExpr) { 742 return Par(expr, expr->getNumExprs(), expr->getExprs(), env); 743 } 744 745 DECL_VISIT_EXPR(UnaryOperator) { 746 // TODO We are treating all expressions that look like &raw_pointer_var 747 // as definitions of raw_pointer_var. This should be changed to 748 // recognize less generic pattern: 749 // 750 // if (maybe_object->ToObject(&obj)) return maybe_object; 751 // 752 if (expr->getOpcode() == clang::UO_AddrOf) { 753 std::string var_name; 754 if (IsRawPointerVar(expr->getSubExpr(), &var_name)) { 755 return ExprEffect::None().Define(var_name); 756 } 757 } 758 return VisitExpr(expr->getSubExpr(), env); 759 } 760 761 DECL_VISIT_EXPR(CastExpr) { 762 return VisitExpr(expr->getSubExpr(), env); 763 } 764 765 DECL_VISIT_EXPR(DeclRefExpr) { 766 return Use(expr, expr->getDecl(), env); 767 } 768 769 DECL_VISIT_EXPR(BlockDeclRefExpr) { 770 return Use(expr, expr->getDecl(), env); 771 } 772 773 ExprEffect Par(clang::Expr* parent, 774 int n, 775 clang::Expr** exprs, 776 const Environment& env) { 777 CallProps props; 778 779 for (int i = 0; i < n; ++i) { 780 props.SetEffect(i, VisitExpr(exprs[i], env)); 781 } 782 783 if (!props.IsSafe()) ReportUnsafe(parent, BAD_EXPR_MSG); 784 785 return props.ComputeCumulativeEffect(IsRawPointerType(parent->getType())); 786 } 787 788 ExprEffect Seq(clang::Stmt* parent, 789 int n, 790 clang::Expr** exprs, 791 const Environment& env) { 792 ExprEffect out = ExprEffect::None(); 793 Environment out_env = env; 794 for (int i = 0; i < n; ++i) { 795 out = ExprEffect::MergeSeq(out, VisitExpr(exprs[i], out_env)); 796 out_env = out_env.ApplyEffect(out); 797 } 798 return out; 799 } 800 801 ExprEffect Use(const clang::Expr* parent, 802 const clang::QualType& var_type, 803 const std::string& var_name, 804 const Environment& env) { 805 if (IsRawPointerType(var_type)) { 806 if (!env.IsAlive(var_name) && dead_vars_analysis_) { 807 ReportUnsafe(parent, DEAD_VAR_MSG); 808 } 809 return ExprEffect::RawUse(); 810 } 811 return ExprEffect::None(); 812 } 813 814 ExprEffect Use(const clang::Expr* parent, 815 const clang::ValueDecl* var, 816 const Environment& env) { 817 if (IsExternalVMState(var)) { 818 return ExprEffect::GC(); 819 } 820 return Use(parent, var->getType(), var->getNameAsString(), env); 821 } 822 823 824 template<typename ExprType> 825 ExprEffect VisitArguments(ExprType* call, const Environment& env) { 826 CallProps props; 827 VisitArguments<>(call, &props, env); 828 if (!props.IsSafe()) ReportUnsafe(call, BAD_EXPR_MSG); 829 return props.ComputeCumulativeEffect(IsRawPointerType(call->getType())); 830 } 831 832 template<typename ExprType> 833 void VisitArguments(ExprType* call, 834 CallProps* props, 835 const Environment& env) { 836 for (unsigned arg = 0; arg < call->getNumArgs(); arg++) { 837 props->SetEffect(arg + 1, VisitExpr(call->getArg(arg), env)); 838 } 839 } 840 841 842 ExprEffect VisitCallExpr(clang::CallExpr* call, 843 const Environment& env) { 844 CallProps props; 845 846 clang::CXXMemberCallExpr* memcall = 847 dyn_cast_or_null<clang::CXXMemberCallExpr>(call); 848 if (memcall != NULL) { 849 clang::Expr* receiver = memcall->getImplicitObjectArgument(); 850 props.SetEffect(0, VisitExpr(receiver, env)); 851 } 852 853 VisitArguments<>(call, &props, env); 854 855 if (!props.IsSafe()) ReportUnsafe(call, BAD_EXPR_MSG); 856 857 ExprEffect out = 858 props.ComputeCumulativeEffect(IsRawPointerType(call->getType())); 859 860 clang::FunctionDecl* callee = call->getDirectCallee(); 861 if ((callee != NULL) && KnownToCauseGC(ctx_, callee)) { 862 out.setGC(); 863 } 864 865 return out; 866 } 867 868 // -------------------------------------------------------------------------- 869 // Statements 870 // -------------------------------------------------------------------------- 871 872 Environment VisitStmt(clang::Stmt* stmt, const Environment& env) { 873 #define VISIT(type) do { \ 874 clang::type* concrete_stmt = dyn_cast_or_null<clang::type>(stmt); \ 875 if (concrete_stmt != NULL) { \ 876 return Visit##type (concrete_stmt, env); \ 877 } \ 878 } while(0); 879 880 if (clang::Expr* expr = dyn_cast_or_null<clang::Expr>(stmt)) { 881 return env.ApplyEffect(VisitExpr(expr, env)); 882 } 883 884 VISIT(AsmStmt); 885 VISIT(BreakStmt); 886 VISIT(CompoundStmt); 887 VISIT(ContinueStmt); 888 VISIT(CXXCatchStmt); 889 VISIT(CXXTryStmt); 890 VISIT(DeclStmt); 891 VISIT(DoStmt); 892 VISIT(ForStmt); 893 VISIT(GotoStmt); 894 VISIT(IfStmt); 895 VISIT(IndirectGotoStmt); 896 VISIT(LabelStmt); 897 VISIT(NullStmt); 898 VISIT(ReturnStmt); 899 VISIT(CaseStmt); 900 VISIT(DefaultStmt); 901 VISIT(SwitchStmt); 902 VISIT(WhileStmt); 903 #undef VISIT 904 905 return env; 906 } 907 908 #define DECL_VISIT_STMT(type) \ 909 Environment Visit##type (clang::type* stmt, const Environment& env) 910 911 #define IGNORE_STMT(type) \ 912 Environment Visit##type (clang::type* stmt, const Environment& env) { \ 913 return env; \ 914 } 915 916 IGNORE_STMT(IndirectGotoStmt); 917 IGNORE_STMT(NullStmt); 918 IGNORE_STMT(AsmStmt); 919 920 // We are ignoring control flow for simplicity. 921 IGNORE_STMT(GotoStmt); 922 IGNORE_STMT(LabelStmt); 923 924 // We are ignoring try/catch because V8 does not use them. 925 IGNORE_STMT(CXXCatchStmt); 926 IGNORE_STMT(CXXTryStmt); 927 928 class Block { 929 public: 930 Block(const Environment& in, 931 FunctionAnalyzer* owner) 932 : in_(in), 933 out_(Environment::Unreachable()), 934 changed_(false), 935 owner_(owner) { 936 parent_ = owner_->EnterBlock(this); 937 } 938 939 ~Block() { 940 owner_->LeaveBlock(parent_); 941 } 942 943 void MergeIn(const Environment& env) { 944 Environment old_in = in_; 945 in_ = Environment::Merge(in_, env); 946 changed_ = !old_in.Equal(in_); 947 } 948 949 bool changed() { 950 if (changed_) { 951 changed_ = false; 952 return true; 953 } 954 return false; 955 } 956 957 const Environment& in() { 958 return in_; 959 } 960 961 const Environment& out() { 962 return out_; 963 } 964 965 void MergeOut(const Environment& env) { 966 out_ = Environment::Merge(out_, env); 967 } 968 969 void Seq(clang::Stmt* a, clang::Stmt* b, clang::Stmt* c) { 970 Environment a_out = owner_->VisitStmt(a, in()); 971 Environment b_out = owner_->VisitStmt(b, a_out); 972 Environment c_out = owner_->VisitStmt(c, b_out); 973 MergeOut(c_out); 974 } 975 976 void Seq(clang::Stmt* a, clang::Stmt* b) { 977 Environment a_out = owner_->VisitStmt(a, in()); 978 Environment b_out = owner_->VisitStmt(b, a_out); 979 MergeOut(b_out); 980 } 981 982 void Loop(clang::Stmt* a, clang::Stmt* b, clang::Stmt* c) { 983 Seq(a, b, c); 984 MergeIn(out()); 985 } 986 987 void Loop(clang::Stmt* a, clang::Stmt* b) { 988 Seq(a, b); 989 MergeIn(out()); 990 } 991 992 993 private: 994 Environment in_; 995 Environment out_; 996 bool changed_; 997 FunctionAnalyzer* owner_; 998 Block* parent_; 999 }; 1000 1001 1002 DECL_VISIT_STMT(BreakStmt) { 1003 block_->MergeOut(env); 1004 return Environment::Unreachable(); 1005 } 1006 1007 DECL_VISIT_STMT(ContinueStmt) { 1008 block_->MergeIn(env); 1009 return Environment::Unreachable(); 1010 } 1011 1012 DECL_VISIT_STMT(CompoundStmt) { 1013 Environment out = env; 1014 clang::CompoundStmt::body_iterator end = stmt->body_end(); 1015 for (clang::CompoundStmt::body_iterator s = stmt->body_begin(); 1016 s != end; 1017 ++s) { 1018 out = VisitStmt(*s, out); 1019 } 1020 return out; 1021 } 1022 1023 DECL_VISIT_STMT(WhileStmt) { 1024 Block block (env, this); 1025 do { 1026 block.Loop(stmt->getCond(), stmt->getBody()); 1027 } while (block.changed()); 1028 return block.out(); 1029 } 1030 1031 DECL_VISIT_STMT(DoStmt) { 1032 Block block (env, this); 1033 do { 1034 block.Loop(stmt->getBody(), stmt->getCond()); 1035 } while (block.changed()); 1036 return block.out(); 1037 } 1038 1039 DECL_VISIT_STMT(ForStmt) { 1040 Block block (VisitStmt(stmt->getInit(), env), this); 1041 do { 1042 block.Loop(stmt->getCond(), 1043 stmt->getBody(), 1044 stmt->getInc()); 1045 } while (block.changed()); 1046 return block.out(); 1047 } 1048 1049 DECL_VISIT_STMT(IfStmt) { 1050 Environment cond_out = VisitStmt(stmt->getCond(), env); 1051 Environment then_out = VisitStmt(stmt->getThen(), cond_out); 1052 Environment else_out = VisitStmt(stmt->getElse(), cond_out); 1053 return Environment::Merge(then_out, else_out); 1054 } 1055 1056 DECL_VISIT_STMT(SwitchStmt) { 1057 Block block (env, this); 1058 block.Seq(stmt->getCond(), stmt->getBody()); 1059 return block.out(); 1060 } 1061 1062 DECL_VISIT_STMT(CaseStmt) { 1063 Environment in = Environment::Merge(env, block_->in()); 1064 Environment after_lhs = VisitStmt(stmt->getLHS(), in); 1065 return VisitStmt(stmt->getSubStmt(), after_lhs); 1066 } 1067 1068 DECL_VISIT_STMT(DefaultStmt) { 1069 Environment in = Environment::Merge(env, block_->in()); 1070 return VisitStmt(stmt->getSubStmt(), in); 1071 } 1072 1073 DECL_VISIT_STMT(ReturnStmt) { 1074 VisitExpr(stmt->getRetValue(), env); 1075 return Environment::Unreachable(); 1076 } 1077 1078 const clang::TagType* ToTagType(const clang::Type* t) { 1079 if (t == NULL) { 1080 return NULL; 1081 } else if (isa<clang::TagType>(t)) { 1082 return cast<clang::TagType>(t); 1083 } else if (isa<clang::SubstTemplateTypeParmType>(t)) { 1084 return ToTagType(cast<clang::SubstTemplateTypeParmType>(t)-> 1085 getReplacementType().getTypePtr()); 1086 } else { 1087 return NULL; 1088 } 1089 } 1090 1091 bool IsDerivedFrom(clang::CXXRecordDecl* record, 1092 clang::CXXRecordDecl* base) { 1093 return (record == base) || record->isDerivedFrom(base); 1094 } 1095 1096 bool IsRawPointerType(clang::QualType qtype) { 1097 const clang::PointerType* type = 1098 dyn_cast_or_null<clang::PointerType>(qtype.getTypePtrOrNull()); 1099 if (type == NULL) return false; 1100 1101 const clang::TagType* pointee = 1102 ToTagType(type->getPointeeType().getTypePtr()); 1103 if (pointee == NULL) return false; 1104 1105 clang::CXXRecordDecl* record = 1106 dyn_cast_or_null<clang::CXXRecordDecl>(pointee->getDecl()); 1107 if (record == NULL) return false; 1108 1109 if (!InV8Namespace(record)) return false; 1110 1111 if (!record->hasDefinition()) return false; 1112 1113 record = record->getDefinition(); 1114 1115 return IsDerivedFrom(record, object_decl_) && 1116 !IsDerivedFrom(record, smi_decl_); 1117 } 1118 1119 Environment VisitDecl(clang::Decl* decl, const Environment& env) { 1120 if (clang::VarDecl* var = dyn_cast<clang::VarDecl>(decl)) { 1121 Environment out = var->hasInit() ? VisitStmt(var->getInit(), env) : env; 1122 1123 if (IsRawPointerType(var->getType())) { 1124 out = out.Define(var->getNameAsString()); 1125 } 1126 1127 return out; 1128 } 1129 // TODO: handle other declarations? 1130 return env; 1131 } 1132 1133 DECL_VISIT_STMT(DeclStmt) { 1134 Environment out = env; 1135 clang::DeclStmt::decl_iterator end = stmt->decl_end(); 1136 for (clang::DeclStmt::decl_iterator decl = stmt->decl_begin(); 1137 decl != end; 1138 ++decl) { 1139 out = VisitDecl(*decl, out); 1140 } 1141 return out; 1142 } 1143 1144 1145 void DefineParameters(const clang::FunctionDecl* f, 1146 Environment* env) { 1147 env->MDefine(THIS); 1148 clang::FunctionDecl::param_const_iterator end = f->param_end(); 1149 for (clang::FunctionDecl::param_const_iterator p = f->param_begin(); 1150 p != end; 1151 ++p) { 1152 env->MDefine((*p)->getNameAsString()); 1153 } 1154 } 1155 1156 1157 void AnalyzeFunction(const clang::FunctionDecl* f) { 1158 const clang::FunctionDecl* body = NULL; 1159 if (f->hasBody(body)) { 1160 Environment env; 1161 DefineParameters(body, &env); 1162 VisitStmt(body->getBody(), env); 1163 Environment::ClearSymbolTable(); 1164 } 1165 } 1166 1167 Block* EnterBlock(Block* block) { 1168 Block* parent = block_; 1169 block_ = block; 1170 return parent; 1171 } 1172 1173 void LeaveBlock(Block* block) { 1174 block_ = block; 1175 } 1176 1177 private: 1178 void ReportUnsafe(const clang::Expr* expr, const std::string& msg) { 1179 d_.Report(clang::FullSourceLoc(expr->getExprLoc(), sm_), 1180 d_.getCustomDiagID(clang::Diagnostic::Warning, msg)); 1181 } 1182 1183 1184 clang::MangleContext* ctx_; 1185 clang::DeclarationName handle_decl_name_; 1186 clang::CXXRecordDecl* object_decl_; 1187 clang::CXXRecordDecl* smi_decl_; 1188 1189 clang::Diagnostic& d_; 1190 clang::SourceManager& sm_; 1191 1192 Block* block_; 1193 bool dead_vars_analysis_; 1194 }; 1195 1196 1197 class ProblemsFinder : public clang::ASTConsumer, 1198 public clang::RecursiveASTVisitor<ProblemsFinder> { 1199 public: 1200 ProblemsFinder(clang::Diagnostic& d, 1201 clang::SourceManager& sm, 1202 const std::vector<std::string>& args) 1203 : d_(d), sm_(sm), dead_vars_analysis_(false) { 1204 for (unsigned i = 0; i < args.size(); ++i) { 1205 if (args[i] == "--dead-vars") { 1206 dead_vars_analysis_ = true; 1207 } 1208 } 1209 } 1210 1211 virtual void HandleTranslationUnit(clang::ASTContext &ctx) { 1212 Resolver r(ctx); 1213 1214 clang::CXXRecordDecl* object_decl = 1215 r.ResolveNamespace("v8").ResolveNamespace("internal"). 1216 Resolve<clang::CXXRecordDecl>("Object"); 1217 1218 clang::CXXRecordDecl* smi_decl = 1219 r.ResolveNamespace("v8").ResolveNamespace("internal"). 1220 Resolve<clang::CXXRecordDecl>("Smi"); 1221 1222 if (object_decl != NULL) object_decl = object_decl->getDefinition(); 1223 1224 if (smi_decl != NULL) smi_decl = smi_decl->getDefinition(); 1225 1226 if (object_decl != NULL && smi_decl != NULL) { 1227 function_analyzer_ = 1228 new FunctionAnalyzer(clang::createItaniumMangleContext(ctx, d_), 1229 r.ResolveName("Handle"), 1230 object_decl, 1231 smi_decl, 1232 d_, 1233 sm_, 1234 dead_vars_analysis_); 1235 TraverseDecl(ctx.getTranslationUnitDecl()); 1236 } else { 1237 if (object_decl == NULL) { 1238 llvm::errs() << "Failed to resolve v8::internal::Object\n"; 1239 } 1240 if (smi_decl == NULL) { 1241 llvm::errs() << "Failed to resolve v8::internal::Smi\n"; 1242 } 1243 } 1244 } 1245 1246 virtual bool VisitFunctionDecl(clang::FunctionDecl* decl) { 1247 function_analyzer_->AnalyzeFunction(decl); 1248 return true; 1249 } 1250 1251 private: 1252 clang::Diagnostic& d_; 1253 clang::SourceManager& sm_; 1254 bool dead_vars_analysis_; 1255 1256 FunctionAnalyzer* function_analyzer_; 1257 }; 1258 1259 1260 template<typename ConsumerType> 1261 class Action : public clang::PluginASTAction { 1262 protected: 1263 clang::ASTConsumer *CreateASTConsumer(clang::CompilerInstance &CI, 1264 llvm::StringRef InFile) { 1265 return new ConsumerType(CI.getDiagnostics(), CI.getSourceManager(), args_); 1266 } 1267 1268 bool ParseArgs(const clang::CompilerInstance &CI, 1269 const std::vector<std::string>& args) { 1270 args_ = args; 1271 return true; 1272 } 1273 1274 void PrintHelp(llvm::raw_ostream& ros) { 1275 } 1276 private: 1277 std::vector<std::string> args_; 1278 }; 1279 1280 1281 } 1282 1283 static clang::FrontendPluginRegistry::Add<Action<ProblemsFinder> > 1284 FindProblems("find-problems", "Find GC-unsafe places."); 1285 1286 static clang::FrontendPluginRegistry::Add< 1287 Action<FunctionDeclarationFinder> > 1288 DumpCallees("dump-callees", "Dump callees for each function."); 1289